Home Articles

如何在点击推送通知时打开特定屏幕

Asked
Viewed 1975 times
4

我试图在点击推送通知时实现打开特定屏幕,我的有效负载如下所示:

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

我收到通知但我无法捕捉到flutter中的通知点击事件如何捕获它 . 我正在使用扑动消息

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

和我的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在我的应用程序处于前台时在消息中说,但我的问题是如何从系统托盘中引发的推送通知中捕获点击事件并导航到所需的屏幕 .

2 Answers

  • 7

    这里有几件事:

    1- click_action 必须设置为 "FLUTTER_NOTIFICATION_CLICK"

    必须在有效负载的 data 部分中设置2- click_action

    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>"
    }'
    

    这应该允许您在flutter应用程序的 onMessage 处理程序中接收消息 .

    从那里你可以拨打 Navigator.of(context).pushNamed(message['screen']) .

    如果此时没有 BuildContext ,则可以将 GlobalKey 注册为 MaterialAppnavigatorKey 属性,并使用它来全局访问 Navigator ,通过 GlobalKey.currentState

  • 2

    由于@xqwzts方法适用于在App上接收消息是开放状态,

    下面的示例将导航到特定页面,

    [该守则仅来自消防局信息插件示例代码,并导航到一个名为页面,我们通过火灾控制台发送的数据]

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

    enter image description here

    了解2件事,FCM通知有2个部分

    1st Message Title firebase Cloud 消息传递页面中的部分名为 Notification Data [当应用程序被缩减或关闭时,它将显示为通知]

    2nd Message Title seciton which is in the Bottom of th webpage is called Message Data ,[它将显示在内部应用程序中作为通知或警报对话符合您的愿望]

    STEPS 创建一个虚拟项目然后使用firebase消息插件,并在该框中将BMW Cars作为主题并单击订阅

    现在转到你的控制台,然后发送一条消息,其中包含以下格式,它必须包含 IdStatus 键,因为我们正在解析Id和状态键,以便显示带有状态键的Vlaue的NextPage,但如果你更喜欢像 Headers 或正文这样的字段,那么你可以这样做但确保在你的flutter代码中解析 Map 值 .

    //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(),
              ),
        );
      }
    }
    

Related