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

时间:2019-08-26 01:22:50

标签: android firebase flutter dart google-cloud-functions

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

但是,我想提出一种方案,如果我的用户在手机上点击通知消息,则这些应用将打开视图或弹出并执行一些后台任务。

这可能吗?

谢谢

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

1)我使用typeScript创建google cloud函数的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:{通知:{body:[TEST-123]消息正文...,标题:[TEST-123] title ...},数据: {}}

     

I / flutter(30602)::: ==> onMessage:{通知:{body:[TEST-123]消息正文...,标题:[TEST-123] title ...},数据: {}}

     

I / flutter(30602):通知-{正文:[TEST-123]邮件正文...,标题:[TEST-123]标题...}

     

I / flutter(30602):数据-{}

     

I / flutter(30602):通知-{正文:[TEST-123]邮件正文...,标题:[TEST-123]标题...}

     

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的回答)

以下是我关于扑打的代码:

  _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.

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

3 个答案:

答案 0 :(得分:4)

当然,您也可以在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

因此,我认为问题出在某种程度上是您的代码,而不是我提供给您的解决方案。请清楚地寻找您可能遇到的问题。希望您能找到它并为您工作。

答案 1 :(得分: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

答案 2 :(得分:0)

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