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

122

我正在尝试在点击推送通知时打开特定的屏幕,我的有效载荷看起来像这样:

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

我收到了通知,但是在Flutter中无法捕获通知点击事件,该如何捕获呢?我正在使用下面链接的Firebase Messaging包:

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


已经修好了,我有同样的问题。 - Mikel Tawfik
17个回答

132

有几点需要注意:

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属性,并使用GlobalKey.currentState全局访问您的Navigator


11
在我的应用程序处于前台时,我可以像您说的那样在一条消息中获取消息,但我的问题是如何捕获从系统托盘中引发的推送通知的点击事件并导航到所需屏幕。 - siva kumar
3
我能捕获到 message['screen'],但调用导航器时无法打开路由。 - temirbek
7
对我无效。这是我在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。 - Ashish
3
我可以翻译您的内容。请问是否需要将原文附上?需要的话请提供。 - kris
2
如果您不清楚如何实现navigatorKey,请参考此答案:https://dev59.com/H1QJ5IYBdhLWcg3w2ZtT#53397266 - sarah
显示剩余8条评论

37

如果有任何人想在Null Safety之前迁移到最新版本的Firebase Messaging(适用于iOS和Android),以下是步骤:

pubspec.yaml

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

主要.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: ...

   );
  }

}

主屏幕.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_support来在onMessage(应用在前台)期间显示通知。

对于iOS,在单击通知时(当应用程序在后台、终止或前台时),将触发方法onMessageOpenedApp。对于Android,这种情况只适用于应用程序在后台或终止时(如果启用了浮动显示/横幅通知,则需要为Android创建channel_id)。

您不再需要在数据有效负载中发送click_action: FLUTTER_CLICK_ACTION以便在通知上具有可点击的事件。FirebaseMessaging会为您处理。


3
如果通知类型是数据,则不会调用onMessageOpenedApp方法,有任何想法吗? - Fatima ayaa
请您更新答案并提供有效载荷,或者查看此链接 https://stackoverflow.com/questions/68798736/fcm-push-notification-payload。 - Gbenga B Ayannuga
我尝试过这个,如果应用程序处于打开状态,当我点击通知时,会打开特定的页面。但是,如果应用程序终止,我点击通知后,它会打开应用程序的主页面。 - jancooth
在我的情况下,onMessageOpenedApp没有被触发。 - Muhammad Umair Saqib
使用了你的代码,在 navigatorKey.currentState!.context 上它说 null check operator used on null value。这发生在通知被点击且应用程序在后台(未终止)时。 - Faizan Ahmad
当应用程序被终止时,onMessageOpenedApp 没有被调用。 - vishalknishad

20

提供有效载荷的方法:

1- 将click_action设置为“FLUTTER_NOTIFICATION_CLICK” - 在Android清单文件中,我们已经定义了它的意图。

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。您可以按以下方式导航到所需页面。

当您按下应用程序栏中的通知时,它会调用 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"],
                      )));
        });
      },
    );
  }

1
这是最简单的解决方案,而且它有效。谢谢。 - Paolo
我们如何提出这个解决方案呢?这是正确的方法,无需使用其他答复中所看到的任何本地代码。 - Uriel Arvizu
你为什么使用addPostFrameCallback - SametSahin

19

由于@xqwzts的方法在App处于开放状态时能够成功接收消息,下面的示例将导航到特定页面。

[该代码是从Firebase Messaging插件示例代码中提取出来的,它会导航到一个已命名的页面,在该页面上我们通过Firebase控制台发送了数据。]

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

这里输入图像描述

了解两点,FCM通知包含两个部分

第一个信息标题 在您的Firebase Cloud Messaging页面中称为通知数据[当应用程序最小化或关闭时,它将显示为通知]

第二个信息标题在网页底部的部分称为消息数据,[它将作为通知或警报对话框显示在应用程序内部,由您决定]

步骤 创建一个虚拟项目,然后使用Firebase消息插件,在该框中提供“BMW汽车”作为主题并单击“订阅”。

现在转到您的控制台,然后发送具有以下格式的消息,它必须包含IdStatus键,因为我们正在解析Id和Status键以显示带有状态键值的NextPage,但如果您更喜欢像标题或正文之类的字段,则也可以这样做,但请确保在您的Flutter代码中解析映射值。

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

14

步骤1: 在Firebase通知中传递一个键值对,click_action:FLUTTER_CLICK_ACTION

步骤2: 使用步骤1,在onResumeonLaunch方法内获取通知的onTap回调。

步骤3: 执行以下场景,以便在单击通知时导航到特定屏幕。

  • 当构建MaterialApp时,请传递一个navigatorKey参数,该参数指定用于导航器的键,然后将该键分配给您的material app,如下所示:
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
@humblePilgrim,你也可以在全局级别声明它。 - Dhaval Kansara

5
如果您的应用程序被终止,您需要使用 getInitialMessage 函数。
 RemoteMessage terminatedMessage =
        await FirebaseMessaging.instance.getInitialMessage();

 if (terminatedMessage != null) {
     // this is a function I created to route to a page
    _processPushNotification(message: terminatedMessage);
 }

processPushNotification函数

void _processPushNotification({@required RemoteMessage message}) async {
    print("message data ${message.data}");

    print("Processing Future after 46 seconds data ${message.data}");
    Future.delayed(Duration(
      seconds: 4,
    )).then((value) async { }); 
}

你能分享一下_processPushNotification函数的代码吗? - L.Goyal
你可以在上面看到代码。 - Rashid Iqbal
2
不,我想知道你是如何路由到一个新页面的。你从哪里获取上下文?或者你在哪里调用这个函数? - L.Goyal
当我点击通知时,它不会进入OnMessageOpenedApp或初始消息的检查中,有人知道为什么吗?这是我的问题。https://dev59.com/68Tra4cB1Zd3GeqP_pKJ - Ahmed Elsayed

4

我回答这个问题已经太晚了,但是最终,我使用了一些Android本地代码和当然还有Flutter代码来实现。那么,让我们从头开始一步步来。

1.) 打开你的build.gradle文件 (路径:android>app>build.gradle),添加Firebase消息依赖,之后通过Android Studio同步该文件。

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

2.) 在 MainActivity 的文件路径下创建一个名为 MyApplication.java 的新文件 (路径 android>app>src>main>kotlin>com>yourpackage>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应用清单文件 (路径为 android>app>src>main>AndroidManifest.xml),将<application android:name标签替换为".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.) 将Firebase代码添加到您的main.dart文件中

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.) 再次进入你的AndroidManifest文件,在activity标签和metadata标签代码闭合标签之后添加intent filter代码

    <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.) 现在前往安卓value文件夹路径(android>app>src>main>res>values>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);
});

3
 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

你在哪里添加这个函数?在MyApp Init中还是其他地方? - L.Goyal
在 @override 内 void initState() { super.initState(); //代码在这里} - Unais IB
你知道为什么消息返回 null,但我收到通知并且当我点击它时,getInitialState 被触发吗? - Ahmed Elsayed

2

AndroidManifest.xml

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


1

在处理推送通知重定向代码之前,有几件事情需要注意。

第一,在推送通知有效负载的数据块中添加 "click_action": "FLUTTER_NOTIFICATION_CLICK"。

第二,在 firebasehelper 类中定义以下回调函数。

//This method will call when the app is in kill state
    FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) {
      if (message != null) {
        //Handle push notification redirection here
      }
    });

    //This method will call when the app is in foreground state
    FirebaseMessaging.onMessage.listen((RemoteMessage? message) async {
      if (message != null && message.data.isNotEmpty) {
        //Handle push notification redirection here
      }
    });

    //This method will call when the app is in background state
    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage? message) {
      if (message != null) {
        //Handle push notification redirection here
      }
    });

Firebase助手类代码

class FirebaseHelper {
  static late FirebaseApp _firebaseApp;
  static late FirebaseMessaging _firebaseMessaging;

  static final FirebaseHelper _singleton = FirebaseHelper._internal();
  static late Timer _timer;

  factory FirebaseHelper() {
    return _singleton;
  }

  FirebaseHelper._internal();

  // To Initialize Firebase
  static Future<void> init() async {
    _firebaseApp = await Firebase.initializeApp();
    await _initCloudMessaging();
  }

  static FirebaseApp getFireBaseApp() {
    return _firebaseApp;
  }

  // To Initialize Firebase FCM
  static Future<void> _initCloudMessaging() async {
    _firebaseMessaging = FirebaseMessaging.instance;
    _firebaseMessaging.setForegroundNotificationPresentationOptions(sound: true, badge: true);
    await requestNotificationPermissions();
    _setUpNotificationListener();
  }

  static Future<NotificationSettings> getNotificationSettings() async {
    return await FirebaseMessaging.instance.getNotificationSettings();
  }

  // To Request Notification Permissions (For IOS)
  static Future<NotificationSettings> requestNotificationPermissions() async {
// for permission
    return await FirebaseMessaging.instance.requestPermission(
      alert: true,
      badge: true,
      provisional: false,
      sound: true,
    );
  }

  // To Set On Notification Listener
  static void _setUpNotificationListener() {
    //This method will call when the app is in kill state
    FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage? message) {
      if (message != null) {
        //Handle push notification redirection here
      }
    });

    //This method will call when the app is in foreground state
    FirebaseMessaging.onMessage.listen((RemoteMessage? message) async {
      if (message != null && message.data.isNotEmpty) {
        //Handle push notification redirection here
      }
    });

    //This method will call when the app is in background state
    FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage? message) {
      if (message != null) {
        //Handle push notification redirection here
      }
    });
  }

  // To Get Device Token
  static Future<String?> getDeviceToken() async {
    return await _firebaseMessaging.getToken();
  }
  
}

在main.dart文件中的runApp函数之前,您需要初始化此类,如下所示。

 WidgetsFlutterBinding.ensureInitialized();
  FirebaseHelper.init();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接