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

Posted

技术标签:

【中文标题】颤振 - 用户打开推送通知消息(FCM)后如何执行任务【英文标题】:flutter - How to do a task after user open push notif message (FCM) 【发布时间】:2019-12-30 05:32:37 【问题描述】:

我有firebase cloud messaging (FCM),可以向我的用户发送消息。

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

这可能吗?

谢谢

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

1) 我使用typeScript 创建谷歌云函数的火力基地:

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): 通知 - body: [TEST-123] body of message... , title: [TEST-123] title...

I/flutter (30602):数据 -

I/flutter (30602): 通知 - body: [TEST-123] body of message... , title: [TEST-123] title...

I/flutter (30602):数据 -

如您所见,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

==更新 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 的值

【问题讨论】:

尝试删除双引号,看看是否可行,data: picture: 'https://i.imgur.com/bY2bBGN.jpg', link: 'https://example.com' @ShadyBoshra 如果我这样做,它会返回错误,请查看更新的问题(更新 2)... 试试这个data: 'picture' : 'https://i.imgur.com/bY2bBGN.jpg', 'link' : 'https://example.com' ,我在键前后添加了单个qoute 仍然错误:Type ' 'picture': string; 'link': string; ' is not assignable to type 'string'. @ShadyBoshra 对不起,还没有。我明天会看到。谢谢…… 【参考方案1】:

当然,你也可以在 Flutter 上做到这一点。

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

<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 在应用打开并在前台运行时触发。

onResume 如果应用已关闭但仍在后台运行,则会触发。

onLaunch 在应用完全终止时触发。

更新

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

• 通知消息 - 由标题和消息正文和 到达设备时触发通知系统。其他 的话,状态栏中会出现一个图标,并会出现一个条目 在通知栏。此类通知应在以下情况下使用 发送您希望用户看到的信息性消息。

例如:

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

• 数据消息 - 包含键/值对形式的数据,并且是 直接发送到应用程序而不触发通知 系统。以静默方式向应用发送数据时使用数据消息。

例如:

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

• 组合消息 – 包含包含两个通知的有效负载 和数据。通知显示给用户,数据是 传送到应用程序。

例如:

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);
    );

和飞镖代码

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

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

【讨论】:

我已经尝试了您的解决方案,但仍然没有使用 nodejs 而是使用 firebase 控制台。我收到有关onMessage 状态的消息,但是对于onLaunchonResume,我无法在调试控制台上得到它。有什么想法吗? 我更新了我的答案,请再次阅读,但是您将无法继续仅使用 Firebase 控制台,您应该继续使用后端 node.js 作为示例。 我在我的 Android 清单上有现有的 FLUTTER_NOTIFICATION_CLICK 意图。但它不起作用...... 现在可以解决了,因为我之前的代码(firebase)使用的是typeScript而不是javascript 哦,我明白了。祝你编码完美。【参考方案2】:

是的,在本机中是可能的,但我不确定是否会颤抖。 您可以使用返回堆栈构建 PendingIntent。

Intent notifIntent = new Intent(this, notifActivity.class);
TaskStackBuilder stkBuilder = TaskStackBuilder.create(this);
stkBuilder.addNextIntentWithParentStack(notifIntent);
PendingIntent resultPendingIntent =
        stkBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

那么你应该将 PendingIntent 传递给通知。

检查此链接: https://developer.android.com/training/notify-user/navigation

【讨论】:

【参考方案3】:

最简单的方法是使用OneSignal,如果你没有足够的时间来构建后端使用firebase发送推送通知,但是,OneSignal对他的订阅者有限制(免费直到30,000订阅者)。

【讨论】:

以上是关于颤振 - 用户打开推送通知消息(FCM)后如何执行任务的主要内容,如果未能解决你的问题,请参考以下文章

在我的颤振(android)应用程序中 - Firebase 推送通知在一段时间后停止接收每个用户

单击推送通知时如何在我的颤振应用程序中打开特定页面

使用 Laravel 颤振 FCM

颤振:fcm ios 推送通知在发布模式下不起作用

如何使用 FCM 向我的数据库中的用户发送推送通知?安卓

如何使用消息 ID 跟踪 FCM 推送通知是不是已交付