как открыть конкретный экран при нажатии на push-уведомление для флаттера

Я пытаюсь открыть открытое окно при нажатии push-уведомления, и моя полезная нагрузка выглядит следующим образом:

 var payload = {
        notification: {
            title: notificationTitle,
            body: notificationMessage,
            click_action:"/screena",sound:"default",
        }
    };

Я получаю уведомление, но я не могу отловить событие щелчка уведомления во флаттере, как его поймать. Я использую флаттер

https://github.com/flutter/plugins/tree/master/packages/firebase_messaging

и мой код службы push-сообщений firebase выглядит следующим образом

 pushMessagingService() async{
messagingreference.configure(
onMessage: (Map<String, dynamic> message) {

  print("I am here in on message");
  print(message);
},
onLaunch: (Map<String, dynamic> message) {
  print("I am here onLaunch");
  print(message);
},
onResume: (Map<String, dynamic> message) {
  print("I am hereonResume");
  print(message);
},
);
  messagingreference.requestNotificationPermissions(
  const IosNotificationSettings(sound: true, badge: true, alert: true));
 messagingreference.onIosSettingsRegistered
  .listen((IosNotificationSettings settings) {
print("Settings registered: $settings");
 });
 messagingreference.getToken().then((String token) async {


print(token);
 });
 }

здесь я могу получить сообщение, которое @xqwzts сказал в сообщении, когда мое приложение находится на переднем плане, но мой вопрос заключается в том, как отловить событие клика из push-уведомления, отображаемого в системном трее, и перейти на нужный экран.

Ответ 1

Несколько вещей здесь:

1- click_action должен быть установлен на "FLUTTER_NOTIFICATION_CLICK"

2- click_action должен быть установлен в data секции полезной нагрузки

DATA='{
  "notification": {
    "body": "this is a body",
    "title": "this is a title"
  },
  "data": {
    "click_action": "FLUTTER_NOTIFICATION_CLICK",
    "sound": "default", 
    "status": "done",
    "screen": "screenA",
  },
  "to": "<FCM TOKEN>"
}'

Это должно позволить вам получать сообщение в обработчике onMessage в вашем onMessage приложении.

Оттуда вы можете вызвать Navigator.of(context).pushNamed(message['screen']).

Если в этот момент у вас нет BuildContext, вы можете зарегистрировать GlobalKey как свойство navigatorKey вашего MaterialApp и использовать его для доступа к вашему Navigator глобально через GlobalKey.currentState

Ответ 2

Поскольку метод @xqwzts хорошо работает для получения сообщений в открытом состоянии приложения,

следующий пример переместится на определенную страницу,

[Код взят из примера с пламенным сообщением ТОЛЬКО И НАВИГАЦИЯ НА ИМЯ СТРАНИЦУ, НА КОТОРОЙ ДАННЫЕ, КОТОРЫЕ МЫ ОТПРАВЛИ ПОЖАРНАЯ КОНСОЛЬ]

//eg:if you give /Nexpage3  in status field then it will navigate to Nextpage3 of your App

enter image description here

ПОНИМАНИЕ 2 ВЕЩЕЙ, УВЕДОМЛЕНИЯ FCM ИМЕЕТ 2 РАЗДЕЛА

1-й заголовок сообщения Раздел на странице облачных сообщений Firebase называется Данные уведомления[когда приложение свернуто или закрыто, оно будет отображаться в виде уведомления]

Второй заголовок сообщения, находящийся в нижней части веб-страницы, называется "Данные сообщения", [он будет отображаться внутри приложения в виде уведомления или диалогового окна с предупреждением по вашему желанию]

ЭТАПЫ Создайте фиктивный проект, затем используйте плагин Firebase Message, и в этом поле укажите BMW Cars как тему и нажмите подписаться

Теперь перейдите на консоль, затем отправьте сообщение с СЛЕДУЮЩИМ ФОРМАТОМ, он должен содержать ключи Id и Status, потому что мы разбираем порядок Id и Status Keys, чтобы показать NextPage с Vlaue ключа состояния, но если вы предпочитаете поле, такое как title или body, то вы тоже можете это сделать, но обязательно проанализируйте значение карты в коде вашего флаттера.

//THIS IS A LITTLE BIT MODIFIED VERSION OF Example Code given in Firebase 
//Messagaing Plugin
//WHEN U PASTE THE CODE IN UR VSCODE OR ANDROID STUDIO PLEASE Format the 
//Document because it is aligned in single lines

import 'dart:async';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(
    new MaterialApp(
      home: new PushMessagingExample(),
      routes: <String,WidgetBuilder>{
        "/Nexpage1":(BuildContext context)=> new Nexpage1(),
        "/Nexpage2":(BuildContext context)=> new Nexpage2(),
        "/Nexpage3":(BuildContext context)=> new Nexpage3(),
        } ),);}


//INITIAL PARAMETERS
String _homeScreenText = "Waiting for token...";
bool _topicButtonsDisabled = false;
final FirebaseMessaging _firebaseMessaging = new FirebaseMessaging();
final TextEditingController _topicController = new TextEditingController(text: 'topic');
final Map<String, Item> _items = <String, Item>{};
Item _itemForMessage(Map<String, dynamic> message) {
  final String itemId = message['id'];
  final Item item = _items.putIfAbsent(itemId, () => new Item(itemId: itemId))..status = message['status'];
      return item;
}

//MAIN CLASS WHICH IS THE HOMEPAGE
class PushMessagingExample extends StatefulWidget {
  @override
  _PushMessagingExampleState createState() => new _PushMessagingExampleState();
}


class _PushMessagingExampleState extends State<PushMessagingExample> {
void _navigateToItemDetail(Map<String, dynamic> message) {
final String pagechooser= message['status'];
Navigator.pushNamed(context, pagechooser);
}

//CLEAR TOPIC
void _clearTopicText() {setState(() {_topicController.text = "";_topicButtonsDisabled = true;});}

//DIALOGUE
void _showItemDialog(Map<String, dynamic> message) {showDialog<bool>(context: context,builder: (_) => _buildDialog(context, _itemForMessage(message)),).then((bool shouldNavigate) {if (shouldNavigate == true) {_navigateToItemDetail(message);}});}

//WIDGET WHICH IS GOING TO BE CALLED IN THE ABOVE DIALOGUE
Widget _buildDialog(BuildContext context, Item item) {return new AlertDialog(content: new Text("Item ${item.itemId} has been updated"),actions: <Widget>[new FlatButton(child: const Text('CLOSE'),onPressed: () {Navigator.pop(context, false);},),new FlatButton(child: const Text('SHOW'),onPressed: () {Navigator.pop(context, true);},),]);}


@override
void initState() {
super.initState();
_firebaseMessaging.configure(
onLaunch: (Map<String, dynamic> message) async { _navigateToItemDetail(message);},
onResume: (Map<String, dynamic> message) async { _navigateToItemDetail(message);},
onMessage: (Map<String, dynamic> message) async {_showItemDialog(message);},);

//GETTING TOKEN FOR TESTING MANUALY
_firebaseMessaging.getToken().then((String token) {assert(token != null);setState(() {_homeScreenText = "Push Messaging token: $token";});print(_homeScreenText);});}



  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(  title: const Text('Push Messaging Demo'),),
        body: new Material(
          child: new Column(
            children: <Widget>[
              new Center(
                child: new Text(_homeScreenText),
              ),
              new Row(children: <Widget>[
                new Expanded(
                  child: new TextField(
                      controller: _topicController,
                      onChanged: (String v) {
                        setState(() {
                          _topicButtonsDisabled = v.isEmpty;
                        });
                      }),
                ),
                new FlatButton(
                  child: const Text("subscribe"),
                  onPressed: _topicButtonsDisabled
                      ? null
                      : () {
                          _firebaseMessaging
                              .subscribeToTopic(_topicController.text);
                          _clearTopicText();
                        },
                ),
new FlatButton(child: const Text("unsubscribe"),
onPressed: _topicButtonsDisabled? null: () { _firebaseMessaging.unsubscribeFromTopic(_topicController.text);
 _clearTopicText();},),

])],),));}}




//THREE DUMMY CLASSES FOR TESTING PURPOSE 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//PAGE1
class Nexpage1 extends StatefulWidget {  @override  _Nexpage1State createState() => _Nexpage1State();}
class _Nexpage1State extends State<Nexpage1> { @override Widget build(BuildContext context) { return Scaffold(body: new Center(child: new Text(" Page1"),));}}

//PAGE2
class Nexpage2 extends StatefulWidget {  @override  _Nexpage2State createState() => _Nexpage2State();}
class _Nexpage2State extends State<Nexpage2> {  @override  Widget build(BuildContext context) {    return Scaffold(      body: Center(child: new Text("2pending"),)      );  }}

//PAGE3
class Nexpage3 extends StatefulWidget {  @override  _Nexpage3State createState() => _Nexpage3State();}
class _Nexpage3State extends State<Nexpage3> {  @override  Widget build(BuildContext context) {    return Scaffold(      body: Center(child: new Text("3connected"),)      );  }}


//THIS IS THE CLASS WHICH IS USED TO PARSE THE INFORMATION
class Item {
  Item({this.itemId});
  final String itemId;
  StreamController<Item> _controller = new StreamController<Item>.broadcast();
  Stream<Item> get onChanged => _controller.stream;
  String _status;
  String get status => _status;
  set status(String value) {
    _status = value;
    _controller.add(this);
}

  static final Map<String, Route<Null>> routes = <String, Route<Null>>{};
  Route<Null> get route {
    final String routeName = '/detail/$itemId';
    return routes.putIfAbsent(
      routeName,
      () => new MaterialPageRoute<Null>(
            settings: new RouteSettings(name: routeName),
            builder: (BuildContext context) => new Nexpage3(),
          ),
    );
  }
}

Ответ 3

Я перехожу к определенному экрану onResume и onLaunch при нажатии на уведомление. Но у меня все еще есть проблема, когда мое приложение закрывается, и я нажимаю на уведомление, мой экран открыт и через несколько секунд Мой экран приложения по умолчанию - open.pleasue guid.

Ответ 4

    onLaunch: (Map<String, dynamic> message) {
      print("I am here onLaunch");
      print(message);
      Navigator.push(
       context,
       MaterialPageRoute(
        builder: (context) => ScreenA()
       )
      );
    },
    onResume: (Map<String, dynamic> message) {
      print("I am here onResume");
      print(message);
      Navigator.push(
       context,
       MaterialPageRoute(
        builder: (context) => ScreenA()
       )
      );
    },

попробуй это