android - flutter -用户打开推送通知消息(FCM)后如何执行任务

标签 android firebase flutter dart google-cloud-functions

我有 firebase 云消息传递 (FCM),可以向我的用户发送消息。

但是,我想做一个场景,如果我的用户在他们的手机上点击通知消息,那么应用程序将打开一个 View 或弹出并执行一些后台任务。

这可能吗?

谢谢

===根据 Shady Boshra 的建议更新问题

1) 我使用 typeScript 创建了谷歌云函数的 firebase:

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();
const fcm = admin.messaging();

export const sendNotif = functions.https.onRequest((request, response) => {

   const tokens = request.query.tokens;
   const payload: admin.messaging.MessagingPayload = {
   notification: {
      title: '[TEST-123] title...',
      body: `[TEST-123]  body of message... `,          
      click_action: 'FLUTTER_NOTIFICATION_CLICK',
      tag: "news",
      data: "{ picture: 'https://i.imgur.com/bY2bBGN.jpg', link: 'https://example.com' }"
    }
  };
  const res = fcm.sendToDevice(tokens, payload);
  response.send(res);
});

2) 我更新了我的移动应用程序代码/Dart :

_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) {
  print("::==>onMessage: $message");

  message.forEach((k,v) => print("${k} - ${v}"));

  String link = "https://example.com";

  FlutterWebBrowser.openWebPage(url: link, androidToolbarColor: Pigment.fromString(UIData.primaryColor));
  return null;
},

然后我尝试在应用程序处于打开模式时发送推送通知。

但是,当我尝试调试它时,我找不到数据的内容。它给出以下响应的返回:

I/flutter (30602): ::==>onMessage: {notification: {body: [TEST-123] body of message... , title: [TEST-123] title...}, data: {}}

I/flutter (30602): ::==>onMessage: {notification: {body: [TEST-123] body of message... , title: [TEST-123] title...}, data: {}}

I/flutter (30602): notification - {body: [TEST-123] body of message... , title: [TEST-123] title...}

I/flutter (30602): data - {}

I/flutter (30602): notification - {body: [TEST-123] body of message... , title: [TEST-123] title...}

I/flutter (30602): data - {}

可以看到,data的内容是空白的。

===更新 2

如果我通过删除双引号来编辑 data,它会在运行 firebase deploy 时返回错误:

> functions@ build /Users/annixercode/myPrj/backend/firebase/functions
> tsc

src/index.ts:10:4 - error TS2322: Type '{ title: string; body: string; click_action: string; tag: string; data: { picture: string; link: string; }; }' is not assignable to type 'NotificationMessagePayload'.
  Property 'data' is incompatible with index signature.
    Type '{ picture: string; link: string; }' is not assignable to type 'string'.

10    notification: {
      ~~~~~~~~~~~~

  node_modules/firebase-admin/lib/index.d.ts:4246:5
    4246     notification?: admin.messaging.NotificationMessagePayload;
             ~~~~~~~~~~~~
    The expected type comes from property 'notification' which is declared here on type 'MessagingPayload'


Found 1 error.

npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! functions@ build: `tsc`
npm ERR! Exit status 2
npm ERR! 
npm ERR! Failed at the functions@ build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/anunixercode/.npm/_logs/2019-08-28T01_02_37_628Z-debug.log

Error: functions predeploy error: Command terminated with non-zero exit code2

==Update 3(回应 Shady Boshra 的回答)

下面是我在 flutter 上的代码:

  _firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) {
  print("::==>onMessage: $message");

  message.forEach((k,v) => print("${k} - ${v}"));

  var data = message['notification']['data']['link'];
  print ("===>data_notif = "+data.toString());

  var data2 = message['data']['link'];
  print ("===>data_notif2 = "+data2.toString());
...

发送推送通知后,我在调试中收到以下消息:

The application is paused.
Reloaded 22 of 1277 libraries.
I/flutter (18608): 0
I/flutter (18608): AsyncSnapshot<String>(ConnectionState.active, Tuesday, September 3, 2019, null)
I/flutter (18608): ::==>onMessage: {notification: {body: [TEST-123]  body of message... , title: [TEST-123] title...}, data: {}}
I/flutter (18608): notification - {body: [TEST-123]  body of message... , title: [TEST-123] title...}
I/flutter (18608): data - {}
Application finished.

如您所见,我无法在 data 中获取 link 的值

最佳答案

当然,您也可以在 Flutter 上完成。

首先,我希望您在 list 中设置这些代码

<intent-filter> <action android:name="FLUTTER_NOTIFICATION_CLICK" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter>

在后端 (node.js) 的 JSON 通知正文中添加标签元素。

const payload: admin.messaging.MessagingPayload = {
  notification: {
    title: 'New Puppy!',
    body: `${puppy.name} is ready for adoption`,
    icon: 'your-icon-url',
    tag: 'puppy', 
    data: {"click_action": "FLUTTER_NOTIFICATION_CLICK", "id": "1", "status": "done"}, 
    click_action: 'FLUTTER_NOTIFICATION_CLICK' // required only for onResume or onLaunch callbacks
  }
};

并且在 Dart 代码中,确保在第一个 initState() 页面中设置此代码。

_fcm.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
        var tag = message['notification']['title']);

        if (tag == 'puppy') 
        {
         // go to puppy page
        } else if (tag == 'catty') 
        {
         // go to catty page
        } 
    },
    onLaunch: (Map<String, dynamic> message) async {
        print("onLaunch: $message");
        // TODO optional
    },
    onResume: (Map<String, dynamic> message) async {
        print("onResume: $message");
        // TODO optional
    },
  );

我的大部分回答来自这个 blog .

它在博客中提到了回调触发的时间,因此请仔细决定在哪个回调中设置您的代码。

onMessage fires when the app is open and running in the foreground.

onResume fires if the app is closed, but still running in the background.

onLaunch fires if the app is fully terminated.

更新

由于您的问题已更新,请考虑此 article 中的以下内容

• Notification Messages - Consist of a title and a message body and trigger the notification system on arrival at the device. In other words, an icon will appear in the status bar and an entry will appear in the notification shade. Such notifications should be used when sending an informational message that you want the user to see.

ex:

var payload = {
  notification: {
    title: "Account Deposit",
    body: "A deposit to your savings account has just cleared."
  }
};

• Data Messages - Contain data in the form of key/value pairs and are delivered directly to the app without triggering the notification system. Data messages are used when sending data silently to the app.

ex:

var payload = {
  data: {
    account: "Savings",
    balance: "$3020.25"
  }
};

• Combined Messages – Contain a payload comprising both notification and data. The notification is shown to the user and the data is delivered to the app.

ex:

var payload = {
  notification: {
    title: "Account Deposit",
    body: "A deposit to your savings account has just cleared."
  },
  data: {
    account: "Savings",
    balance: "$3020.25"
  }
};

所以,我想你会使用第三个,它同时发送通知和数据。

您可以使用 dart 访问数据,如下所示。

message['data']['account']

更新2

当您更新您的问题时,我的解决方案并没有很好地为您服务。我决定自己测试一下,你猜怎么着!它适用于您和相同的代码。

我的 node.js 后端代码

'use strict';

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

const db = admin.firestore();
const fcm = admin.messaging();

exports.sendNotification = functions.firestore
    .document('orders/{orderId}')
    .onCreate(async snapshot => {

        const order = snapshot.data();

        // Token of my device only
        const tokens = ["f5zebdRcsgg:APA91bGolg9-FiLlCd7I0LntNo1_7b3CS5EAJBINZqIpaz0LVZtLeGCvoYvfjQDhW0Qdt99jHHS5r5mXL5Up0kBt2M7rDmXQEqVl_gIpSQphbaL2NhULVv3ZkPXAY-oxX5ooJZ40TQ2-"];

        const payload = {
            notification: {
                title: "Account Deposit",
                body: "A deposit to your savings account has just cleared."
            },
            data: {
                account: "Savings",
                balance: "$3020.25",
                link: "https://somelink.com"
            }
        };

        return fcm.sendToDevice(tokens, payload);
    });

和 Dart 代码

final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();

  @override
  void initState() {
    super.initState();

    _firebaseMessaging.requestNotificationPermissions();

    _firebaseMessaging.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");

        var data2 = message['data']['link'];
        print ("===>data_notif2 = "+data2.toString());

        showDialog(
          context: context,
          builder: (context) => AlertDialog(
            content: ListTile(
              title: Text(message['notification']['title']),
              subtitle: Text(message['notification']['body']),
            ),
            actions: <Widget>[
              FlatButton(
                child: Text('Ok'),
                onPressed: () => Navigator.of(context).pop(),
              ),
            ],
          ),
        );
      },
      onLaunch: (Map<String, dynamic> message) async {
        print("onLaunch: $message");
        // TODO optional
      },
      onResume: (Map<String, dynamic> message) async {
        print("onResume: $message");
        // TODO optional
      },
    );

    _saveDeviceToken();
  }

  /// Get the token, save it to the database for current user
  _saveDeviceToken() async {
    // Get the current user
    String uid = 'jeffd23';
    // FirebaseUser user = await _auth.currentUser();

    // Get the token for this device
    String fcmToken = await _firebaseMessaging.getToken();

    // Save it to Firestore
    if (fcmToken != null) {
      print(fcmToken);
    }
  }

和控制台输出

I/flutter (20959): onMessage: {notification: {title: Account Deposit, body: A deposit to your savings account has just cleared.}, data: {account: Savings, balance: $3020.25, link: https://somelink.com}}
I/flutter (20959): ===>data_notif2 = https://somelink.com

所以我认为问题出在您的代码中,而不是我给您的解决方案中。请清楚地查找您可能遇到的问题。希望你能找到它并为你工作。

关于android - flutter -用户打开推送通知消息(FCM)后如何执行任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57650892/

相关文章:

ios - 使用 Firebase 字典在 Swift 中填充数组

regex - 用于验证邮政编码格式的 dart 正则表达式

android - 地理编码器 getFromLocation 失败

Android Java : Fatal exception main nullpointer. 我没有明确定义的线程。它说它无法实例化 Activity

android - 如何修复 Kotlin Android Studio 3.3 中的 "Unresolved reference "错误

javascript - Firebase 保存数据

dart - flutter :如何在应用开始前显示对话框?

Android:隐藏配对对话框

java - 在 fragment 之间传递对象作为参数

swift - Firebase:如何从子节点swift中提取子键值