web-dev-qa-db-ja.com

flutter-ユーザーがプッシュ通知メッセージ(FCM)を開いた後にタスクを実行する方法

firebase cloud messaging (FCM)があり、ユーザーにメッセージを送信できます。

ただし、ユーザーが携帯電話で通知メッセージをタップすると、アプリがビューを開くかポップアップになり、バックグラウンドタスクを実行するというシナリオを作りたいと思います。

これは可能ですか?

ありがとうございました

=== Shady Boshraの提案に従って質問を更新

1)TypeScriptを使用してgoogleクラウド関数の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 /フラッター(30602):データ-{}

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

I /フラッター(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の値を取得できません

8
coderInrRain

もちろん、Flutterでも実行できます。

まず、マニフェストにこれらのコードを設定してください

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

バックエンドのJSONの通知本文(node.js)にタグ要素を追加します。

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は、アプリが完全に終了した場合に発生します。

更新

質問が更新されましたので、以下から検討してください 記事

•通知メッセージ-タイトルとメッセージ本文で構成され、デバイスに到着すると通知システムをトリガーします。つまり、ステータスバーにアイコンが表示され、通知シェードにエントリが表示されます。このような通知は、ユーザーに表示したい情報メッセージを送信するときに使用する必要があります。

例:

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"
  }
};

ですから、通知とデータを同時に送信する3番目のものを使用すると思います。

以下のように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

だから私は問題が私にあなたに与える解決策ではなくあなたのコードに何らかの形であると信じています。発生する可能性のある問題を明確に探してください。あなたがそれを見つけて、うまくいくことを願っています。

5
Shady Boshra

はい、それはネイティブで可能ですが、私はフラッターではわかりません。バックスタックを使用して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
Saeiddjawadi

最も簡単な方法は、 OneSignal を使用していて、Firebaseを使用してプッシュ通知を送信するためのバックエンドを構築する十分な時間がない場合、ただし、OneSignalのサブスクライバーには制限があります(30,000サブスクライバーまで無料)。

1
anunixercoder