【问题标题】:how to open particular screen on clicking on push notification for flutter如何在单击推送通知时打开特定屏幕以进行颤动
【发布时间】:2018-07-02 09:28:36
【问题描述】:

我正在尝试在单击推送通知时打开特定屏幕,我的有效负载如下所示:

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

我收到通知,但我无法捕捉通知点击事件,如何捕捉它。我正在使用颤振消息传递

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 在消息中所说的消息,但我的问题是如何从系统托盘中提出的推送通知中捕获点击事件并导航到所需的屏幕。

【问题讨论】:

  • 解决了,我也有同样的问题

标签: android ios flutter dart firebase-cloud-messaging


【解决方案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>"
}'

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

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

如果您此时没有BuildContext,您可以将GlobalKey 注册为MaterialAppnavigatorKey 属性,并使用它通过@987654333 全局访问您的Navigator @

【讨论】:

  • 在这里,当我的应用程序处于前台时,我可以收到您在消息中所说的消息,但我的问题是如何从系统托盘中提出的推送通知中捕获点击事件并导航到所需的屏幕
  • 我能够捕捉到消息['screen'] 并且调用 Navigator 不会打开路线
  • 不适合我。这是我在 onMessage {notification: {title: First Notification, body: hELLO hELLO Test}, data: {click_action: FLUTTER_NOTIFICATION_CLICK}} 中收到的消息,但重定向不起作用。我已经使用Navigator.of(navigatorKey.currentContext).pushNamed('test'); 配置了 onMessage 和 onResume。 navigatorKey 是 GlobalKey 设置 MaterialApp 及其 navigatorKey。
  • 我对 Dart 很陌生,我对最后一段很迷茫——你能解释一下吗@xqwzts?
  • 最好包括一个你评论过的例子:)
【解决方案2】:

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

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

[代码取自 Firebase 消息传递插件示例代码 仅导航到指定页面,我们通过该页面发送数据 FIREBASE 控制台]

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

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

第一个消息标题 Firebase 云消息页面中的部分称为通知数据[当应用最小化或关闭时,它将显示为通知]

网页底部的第二个消息标题部分称为消息数据,[它将在应用内显示为通知或警报对话框,这取决于您的意愿]

步骤 创建一个虚拟项目,然后使用 firebase 消息插件,并在该框中将 BMW Cars 作为 atopic 并点击订阅

现在转到您的控制台,然后使用以下格式发送一条消息,它必须包含 IdStatus 键,因为我们正在解析 Id 和状态键以便显示带有状态键值的 NextPage,但如果您更喜欢像标题或正文这样的字段,那么您也可以这样做,但请确保在您的颤动代码中解析地图值。

//THIS IS A LITTLE BIT MODIFIED VERSION OF Example Code given in Firebase 
//Messaging Plugin
//WHEN U PASTE THE CODE IN UR VS CODE 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】:
        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()
           )
          );
        },
    

    试试这个

    【讨论】:

      【解决方案4】:

      最初,@xqwzts 的回答对我不起作用。经过大量研究,我发现我们需要初始化配置方法,延迟很小。我附上了下面的代码。这对其他人会有所帮助。

      void initState() {
              // TODO: implement initState
              super.initState();
              _firebaseMsgListener();
            }
      
            void _firebaseMsgListener() {
              // if (Platform.isIOS) iOS_Permission();
      
              _firebaseMessaging.getToken().then((token) {
                Fimber.d("=====> token : $token");
                UpdateTokenRequest request = UpdateTokenRequest();
                request.token = token;
                homeBloc.updateFCMToken(request);
              });
      
              Future.delayed(Duration(seconds: 1), () {
                _firebaseMessaging.configure(
                  onBackgroundMessage: myBackgroundMessageHandler,
                  onMessage: (Map<String, dynamic> message) async {
                    Fimber.d("=====>on message $message");
                    Fluttertoast.showToast(msg: "onMessage $message");
                  },
                  onResume: (Map<String, dynamic> message) async {
                    Fimber.d("=====>onResume $message");
                    Fluttertoast.showToast(msg: "onResume $message");
                  },
                  onLaunch: (Map<String, dynamic> message) async {
                    Fimber.d("=====>onLaunch $message");
                    Fluttertoast.showToast(msg: "onLaunch $message");
                  },
                );
              });
            }
      
            Future<dynamic> myBackgroundMessageHandler(
                Map<String, dynamic> message) async {
              print("_backgroundMessageHandler");
              if (message.containsKey('data')) {
                // Handle data message
                final dynamic data = message['data'];
                print("_backgroundMessageHandler data: ${data}");
              }
      
              if (message.containsKey('notification')) {
                // Handle notification message
                final dynamic notification = message['notification'];
                print("_backgroundMessageHandler notification: ${notification}");
                Fimber.d("=====>myBackgroundMessageHandler $message");
              }
              return Future<void>.value();
            }
      

      【讨论】:

        【解决方案5】:
              onBackgroundMessage: myBackgroundMessageHandler,
          onLaunch: (Map<String, dynamic> message) async {
            await print("onLaunch: $message");
            ///_navigateToItemDetail(message);
            await _showItemDialog(message); // Diyalog Kutusu Oluştur
          },
          onResume: (Map<String, dynamic> message) async {
            await print("onResume: $message");
            ///_navigateToItemDetail(message);      
            await _showItemDialog(message); // Diyalog Kutusu Oluştur
          },
        

        添加等待正在工作

        【讨论】:

        • await print("onLaunch: $message"); 是什么,
        【解决方案6】:

        第 1 步: 在 Firebase 通知中传递一个键值对作为 click_action: FLUTTER_CLICK_ACTION

        第 2 步:使用第 1 步,您将在 onResumeonLaunch 方法中收到通知的 onTap 回调。

        第 3 步:执行以下方案,在点击通知时导航到特定屏幕。

        • 在构建 MaterialApp 时,传递一个 navigatorKey 参数,该参数指定用于导航器的键,然后将该键分配给您的材质应用程序,如下所示:
        class _MyHomePageState extends State<MyHomePage> {
          final GlobalKey<NavigatorState> navigatorKey = GlobalKey(debugLabel: "Main Navigator");
        
          @override
          Widget build(BuildContext context) {
            return new MaterialApp(
              navigatorKey: navigatorKey,
              home: new Scaffold(
                appBar: AppBar(),
                body: new Container(),
              ),
            );
          }
        }
        
        • 现在,从 onResumeonLaunch 方法使用以下代码行导航到您的屏幕:
         navigatorKey.currentState.push(
            MaterialPageRoute(builder: (_) => Dashboard())
         );
        

        【讨论】:

        • 我们如何从内部方法访问全局键?
        • @humblePilgrim 你也可以在全球范围内声明它。
        【解决方案7】:

        使用 firebase_messaging:“^8.0.0-dev.10” FlutterFire FCM FlutterFire FCM notifications

        遵循此代码。这要容易得多。

        class Application extends StatefulWidget {
          @override
          State<StatefulWidget> createState() => _Application();
        }
        
        class _Application extends State<Application> {
          @override
          void initState() async {
            super.initState();
        
            // Get any messages which caused the application to open from
            // a terminated state.
            RemoteMessage initialMessage =
                await FirebaseMessaging.instance.getInitialMessage();
        
            // If the message also contains a data property with a "type" of "chat",
            // navigate to a chat screen
            if (initialMessage?.data['type'] == 'chat') {
              Navigator.pushNamed(context, '/chat',
                  arguments: ChatArguments(initialMessage));
            }
        
            // Also handle any interaction when the app is in the background via a
            // Stream listener
            FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
              if (message.data['type'] == 'chat') {
                Navigator.pushNamed(context, '/chat',
                  arguments: ChatArguments(message));
              }
            });
          }
        
          @override
          Widget build(BuildContext context) {
            return Text("...");
          }
        }
        

        【讨论】:

          【解决方案8】:

          这对我有用。 您需要在 AndroidManifest.xml 文件中添加此代码。您可以将任何内容作为“click_action”,但它必须与清单文件中的相同。不确定 iOS。

          【讨论】:

            【解决方案9】:

            从包的文档 (https://pub.dev/packages/firebase_messaging) 中,它明确指出您需要在 android/app/src/main/java/app/{{appName}} 位置创建一个 Application.java。

            在该文件 (Application.java) 中,它指定了您需要包含的确切代码。

            完成后,对于颤振代码,请确保在 main.dart 文件中设置 backgroundMessageHandler 函数,因为它需要是顶级函数。

            还有一点需要注意,如果您的 PluginRegistry 出现错误,请使用以下代码:

            import io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin;
            FirebaseMessagingPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
            

            当您确实发送了一个通知并且您希望您的 backgroundMessage 捕获它以及 onResume 在您单击通知时捕获它,确保您的通知具有标题、正文、click_action,那么您的数据也应该有一个标题,正文,然后是您想要的任何数据。

            我在自己的例子中使用了这个:

            $notification = [
                    'title' => 'New notification',
                    'body' => "{$group->group_name} needs it's members to be updated. It starts on {$startDate->toFormattedDateString()}, however...",
                    'icon' => '',
                    'click_action'=> 'FLUTTER_NOTIFICATION_CLICK',
                    'Test' => 'Some testing data',
                ];
                $data = [
                    'title' => 'This title is in the data',
                    'body' => "this body is in the data",
                    'Test' => 'Some testing data',
                    'click_action'=> 'FLUTTER_NOTIFICATION_CLICK'
                ];
            

            【讨论】:

              【解决方案10】:

              提供有效载荷使用:

              1- click_action 必须设置为“FLUTTER_NOTIFICATION_CLICK” - 在 android manifest 文件中,我们已经定义了它的意图。

              2- click_action 必须在有效载荷的数据部分中设置

              为 NavigatorState 定义一个全局变量:

              import 'package:flutter/cupertino.dart';
              
              /// Global variables
              /// * [GlobalKey<NavigatorState>]
              class GlobalVariable {
                
                /// This global key is used in material app for navigation through firebase notifications.
                /// [navState] usage can be found in [notification_notifier.dart] file.
                static final GlobalKey<NavigatorState> navState = GlobalKey<NavigatorState>();
              }
              
              

              转到您的 MaterialApp 并添加

              class MyApp extends StatelessWidget {
              
                @override
                Widget build(BuildContext context) {
                  return ScrollConfiguration(
                    behavior: BounceScrollBehavior(),
                    child: MaterialApp(
                      navigatorKey: GlobalVariable.navState,
                      debugShowCheckedModeBanner: false,
                      theme: themeData,
                      home: App(),
                    ),
                  );
                }
              }
              

              当您在应用栏中按下通知时,它会调用 onResume。您可以按如下方式导航到所需的页面。

              void listenToNotification() {
                  fcm.configure(
                    onMessage: (Map<String, dynamic> message) async {
                      print("onMessage: $message");
                      getPreviousNotifications();
                    },
                    onLaunch: (Map<String, dynamic> message) async {
                      print("onLaunch: $message");
                    },
                    onResume: (Map<String, dynamic> message) async {
                      print("onResume: ${message["data"]}");
                      SchedulerBinding.instance.addPostFrameCallback((_) {
                        Navigator.of(GlobalVariable.navState.currentContext)
                            .push(MaterialPageRoute(
                                builder: (context) => TimelineView(
                                      campaignId: message["data"]["campaign"],
                                    )));
                      });
                    },
                  );
                }
              

              【讨论】:

              • 这是最简单的解决方案,而且有效。谢谢
              • 我们如何为解决方案提出这个建议?这是要走的路,不需要使用我在其他回复中看到的任何本机代码
              • 你为什么用addPostFrameCallback
              【解决方案11】:

              我来不及回答这个问题,但最后,我已经用一些 android 原生代码和 Flutter 代码实现了这一点。所以,让我们一步一步从头开始

              1.) 转到您的 build.gradle 文件 (PATH android&gt;app&gt;buid.gradle)。添加firebase消息依赖,然后从android studio同步文件

              implementation 'com.google.firebase:firebase-messaging'
              

              2.) 在MainActivity文件路径(PATH android&gt;app&gt;src&gt;main&gt;kotlin&gt;com&gt;yourpackage&gt;MyApplication.java)中新建一个文件名MyApplication.java

              import android.app.NotificationChannel;
              import android.app.NotificationManager;
              import android.content.Context;
              import android.os.Build;
              
              import io.flutter.app.FlutterApplication;
              import io.flutter.plugin.common.PluginRegistry;
              import io.flutter.plugins.firebasemessaging.FlutterFirebaseMessagingService;
              import io.flutter.plugins.pathprovider.PathProviderPlugin;
              
              public class MyApplication extends FlutterApplication implements PluginRegistry.PluginRegistrantCallback {
              
                  @Override
                  public void onCreate() {
                      super.onCreate();
                      this.createChannel();
                      FlutterFirebaseMessagingService.setPluginRegistrant(this);
                  }
              
                  @Override
                  public void registerWith(PluginRegistry registry) {
                      io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin.registerWith(registry.registrarFor("io.flutter.plugins.firebasemessaging.FirebaseMessagingPlugin"));
                      PathProviderPlugin.registerWith(registry.registrarFor("io.flutter.plugins.pathprovider.PathProviderPlugin"));
                  }
              
                  private void createChannel(){
                      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                          String name = getString(R.string.default_notification_channel_id);
                          NotificationChannel channel = new NotificationChannel(name, "default", NotificationManager.IMPORTANCE_HIGH);
                          NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                          notificationManager.createNotificationChannel(channel);
                      }
                  }
              }
              

              3.) 转到您的 android 应用清单文件 (PATH android&gt;app&gt;src&gt;main&gt;AndroidManifest.xml) 并添加替换 &lt;application android:name with ".MyApplication" 标记

              <application
                      android:name=".MyApplication" //replace your name with .MyApplication
                      android:label="helpwise"
                      android:icon="@mipmap/ic_launcher">
              

              4.) 现在您需要在 Flutter 项目中添加 firebase 消息传递依赖项。所以在 pubspec.yaml 中添加

              firebase_messaging: ^6.0.9
              

              5.) 在 main.dart 文件中添加 firebase 代码

              Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) {
                if (message.containsKey('data')) {
                  final dynamic data = message['data'];
                  print('Notification data is ');
                  print(message['data']);
                }
              
                if (message.containsKey('notification')) {
                  // Handle notification message
                  final dynamic notification = message['notification'];
                }
              }
              
              class SelectMailbox extends StatefulWidget {
                static const routeName = '/mailbox-screen';
              
                @override
                _SelectMailboxState createState() => _SelectMailboxState();
              }
              
              class _SelectMailboxState extends State<SelectMailbox> {
                final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
              
                @override
                void initState() {
                  
                  _firebaseMessaging.getToken().then((token) async{
                    SharedPreferences preferences = await SharedPreferences.getInstance();
                    final String userData = preferences.get('userData');
                    final String authToken=jsonDecode(userData)['token'];
                    print("Device token is $token"); //I will use this token to send notif.
                    await http.post("https://your_domain/mobile/save-token",
                        headers: {"Content-Type": "application/json"},
                        body: jsonEncode({"device_token": token,"type":"android","token":authToken}));
                  });
              
                  _firebaseMessaging.configure(
                      onMessage: (Map<String, dynamic> message) async {
                       // 
                      }, onBackgroundMessage: Platform.isAndroid?myBackgroundMessageHandler:null,
                      onResume: (Map<String, dynamic> message) async {
                         print("onBackground Message $message"); 
                        _selectIdsNotification(message['data']['thread_id'],message['data']['mailbox_id'],14,message['data']['mailboxType'],"All",context);
                      }, onLaunch: (Map<String, dynamic> message) async {
                    print("onLaunch Message $message");
                    _selectIdsNotification(message['data']['thread_id'],message['data']['mailbox_id'],14,message['data']['mailboxType'],"All",context);
                  });
              
                  super.initState();
                }
              
                _selectIdsNotification(threadID,mailboxId,subBox,mailboxType,mailboxTab,myContext) async {
                  // YOU CAN ADD THE LOGIC OF DIFFERENT PAGE ROUTE ACCORDING TO DATA PASS FROM NOTIFICATION in my case i could use the mailboxType
                  Navigator.push(
                    myContext,
                    MaterialPageRoute(
                      builder: (context) => ThreadDetail(threadID, mailboxType,notificationMailboxId: mailboxId),
                    ),
                  );
                }
              

              6.) 再次转到您的 AndoridManifest.file 并在活动标签内添加意图过滤器代码和活动关闭标签后的元数据标签代码

                  <application
                          android:name=".MyApplication"
                          android:label="helpwise"
                          android:icon="@mipmap/ic_launcher">
                          <activity
                              android:name=".MainActivity"
                              android:launchMode="singleTop"
                              android:theme="@style/LaunchTheme"
                              android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
                              android:hardwareAccelerated="true"
                              android:windowSoftInputMode="adjustResize">
                             
                              <meta-data
                                android:name="io.flutter.embedding.android.NormalTheme"
                                android:resource="@style/NormalTheme"
                                />
                              <meta-data
                                android:name="io.flutter.embedding.android.SplashScreenDrawable"
                                android:resource="@drawable/launch_background"
                                />
                              <intent-filter>
                                  <action android:name="android.intent.action.MAIN"/>
                                  <category android:name="android.intent.category.LAUNCHER"/>
                              </intent-filter>
                  <-- ADD THIS INTENT FILTER IN YOUR CODE -->
                              <intent-filter>
                                  <action android:name="FLUTTER_NOTIFICATION_CLICK" />
                                  <category android:name="android.intent.category.DEFAULT" />
                              </intent-filter>
                  
                          </activity>
                          <meta-data
                              android:name="flutterEmbedding"
                              android:value="2" />
               <-- ADD THIS META DATA TAG IN YOUR CODE -->
                          <meta-data android:name="com.google.firebase.messaging.default_notification_channel_id"
                                     android:value="@string/default_notification_channel_id" />
                      </application> 
              

              7.) 现在转到 android 值文件夹 PATH(android&gt;app&gt;src&gt;main&gt;res&gt;values&gt;strings.xml)。如果您没有看到 strings.xml 文件,则在与 strings.xml 文件相同的路径上创建一个文件并添加以下代码

              <?xml version="1.0" encoding="utf-8"?>
              <resources>
                  <string name="default_notification_channel_id">default_notification_channel_id</string>
              </resources>
              

              10.) 这就是它的家伙。现在,您需要重新启动应用并将 firebase 消息通知 API 调用到设备令牌。

                  ar axios = require('axios');
              var data = JSON.stringify(
              {
                "to": "your_mobile_device_token",
                "data": {
                  "mailbox_id": "11111",
                  "thread_id": "1111",
                  "mailboxType": "email",
                  "click_action": "FLUTTER_NOTIFICATION_CLICK"
                },
                "priority": "high",
                "notification": {
                  "body": "Hi, You have received new Message",
                  "title": "Flutter",
                  "image": "your_image_cdn_path"
                },
                "click_action": "FLUTTER_NOTIFICATION_CLICK"
              });
              
              var config = {
                method: 'post',
                url: 'https://fcm.googleapis.com/fcm/send',
                headers: { 
                  'Authorization': 'key=your_firebase_server_key', 
                  'Content-Type': 'application/json'
                },
                data : data
              };
              
              axios(config)
              .then(function (response) {
                console.log(JSON.stringify(response.data));
              })
              .catch(function (error) {
                console.log(error);
              });
              

              【讨论】:

                【解决方案12】:

                对于任何想要在 Null Safety 之前迁移到最新版本的 Firebase 消息传递(适用于 iOS 和 Android)的人,以下是步骤

                pubspec.yaml

                firebase_core: ^0.7.0
                firebase_messaging: ^8.0.0-dev.15
                

                main.dart

                GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
                
                Future<void> main() async {
                      
                        WidgetsFlutterBinding.ensureInitialized();
                        await Firebase.initializeApp();
                        await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
                          alert: true,
                          badge: true,
                          sound: true,
                        );
                        runApp(new MyApp());
                }
                
                
                class MyApp extends StatefulWidget {
                
                  @override
                  _MyAppState createState() => _MyAppState();
                }
                
                class _MyAppState extends State<MyApp> {
                
                @override
                  Widget build(BuildContext context) {
                  return MaterialApp(
                              navigatorKey: navigatorKey,
                              title: ...
                
                   );
                  }
                
                }
                

                homeScreen.dart

                    Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
                      print("onBackgroundMessage: $message");
                    }
                    
                    class HomeScreen extends StatefulWidget {
                      @override
                      _HomeScreenState createState() => _HomeScreenState();
                    }
                    
                    class _HomeScreenState extends State<HomeScreen>{
                    
                      @override
                      void initState() {
                        super.initState();
                    
                    FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
                    FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
                        print("onMessage: $message");
                    });
                    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) async {
                        print("onMessageOpenedApp: $message");
                            
                                 
                          if (message.data["navigation"] == "/your_route") {
                            int _yourId = int.tryParse(message.data["id"]) ?? 0;
                            Navigator.push(
                                    navigatorKey.currentState.context,
                                    MaterialPageRoute(
                                        builder: (context) => YourScreen(
                                              yourId:_yourId,
                                            )));
                        });
                      }
                    }
                

                注意iOS通知会出现在顶部(抬头显示)和onMessage(应用在前台时)和onBackgroundMessage(当应用程序在后台或终止)。

                Android 通知将出现在顶部的托盘和 onBackgroundMessage 的触发方法(当应用程序在后台或终止时)。您必须使用第三方解决方案,如flutter_local_notificationsoverlay_supportonMessage(前台应用)期间显示通知。

                对于 iOS,当点击通知时(当应用程序在后台、终止或前台时),方法 onMessageOpenedApp 将被触发。对于 Android,此方案仅在应用程序在后台运行或终止时有效(如果启用了抬头通知显示/横幅 - 您需要为 android 创建 channel_id)

                您不再需要在数据负载上发送click_action: FLUTTER_CLICK_ACTION 以在通知中获得可点击事件。 FirebaseMessaging 将为您处理

                【讨论】:

                【解决方案13】:

                如果您的应用被终止,您需要使用 getInitialMessage 函数

                 RemoteMessage terminatedMessage =
                        await FirebaseMessaging.instance.getInitialMessage();
                
                 if (terminatedMessage != null) {
                     // this is a function I created to route to a page
                    _processPushNotification(message: terminatedMessage);
                 }
                

                【讨论】:

                  【解决方案14】:
                   FirebaseMessaging.instance.getInitialMessage().then((message) {
                    RemoteNotification notification = message.notification;
                    AndroidNotification android = message.notification?.android;
                    if (notification != null && android != null) {
                      Navigator.push(
                        context,
                        MaterialPageRoute(
                          builder: (context) => NotificationScreen(
                            name: message.data['name'],
                            place: message.data['place'],
                            address: message.data['address'],
                          ),
                        ),
                      );
                    }
                  });// handles notification clicks while the app is in the terminated state
                  

                  【讨论】:

                    猜你喜欢
                    • 2020-07-27
                    • 1970-01-01
                    • 2017-09-15
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多