web-dev-qa-db-fra.com

flutter - Comment faire une tâche après l'ouverture de l'utilisateur Push push notif message (FCM)

J'ai firebase cloud messaging (FCM) et je peux envoyer un message à mon utilisateur.

Cependant, je veux créer un scénario selon lequel si mon utilisateur appuie sur un message de notification sur son téléphone mobile, les applications ouvriront une vue ou apparaîtront et effectueront une tâche d'arrière-plan.

est-ce possible?

Merci

=== Mettre à jour la question comme suggéré par Shady Boshra

1) Je crée la base de feu de la fonction Google Cloud en utilisant 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) Je mets à jour mon code d'applications mobiles/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;
},

puis j'essaie d'envoyer Push notif lorsque les applications sont en mode ouvert.

Cependant, quand j'essaye de le déboguer, je ne peux pas trouver le contenu des données. il donne un retour en dessous de la réponse:

I/flutter (30602): :: ==> onMessage: {notification: {corps: [TEST-123] corps du message ..., titre: [TEST-123] titre ...}, données: {}}

I/flutter (30602): :: ==> onMessage: {notification: {corps: [TEST-123] corps du message ..., titre: [TEST-123] titre ...}, données: {}}

I/flutter (30602): notification - {corps: [TEST-123] corps du message ..., titre: [TEST-123] titre ...}

I/flutter (30602): données - {}

I/flutter (30602): notification - {corps: [TEST-123] corps du message ..., titre: [TEST-123] titre ...}

I/flutter (30602): données - {}

comme vous pouvez le voir, le contenu de data est vide.

=== Update 2

Si je modifie data en supprimant les guillemets doubles, il renvoie une erreur lors de l'exécution de 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

== Mise à jour 3 (réponse à la réponse de Shady Boshra)

voici mon code sur le flottement:

  _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());
...

après avoir envoyé Push notif, je viens de recevoir le message ci-dessous dans le débogage:

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.

comme vous pouvez le voir, je ne peux pas obtenir la valeur de link à l'intérieur data

8
coderInrRain

Bien sûr, vous pouvez aussi le faire sur Flutter.

Tout d'abord, je suppose que vous définissez ces codes dans votre manifeste

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

Dans votre corps de notification en JSON dans le backend (node.js), ajoutez l'élément tag.

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

Et dans le code Dart, assurez-vous de définir ce code dans la première page 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
    },
  );

La plupart de ma réponse est de cela blog .

Il est mentionné dans le blog lorsque les rappels se déclenchent, alors décidez de près dans lequel définir votre code.

onMessage se déclenche lorsque l'application est ouverte et s'exécute au premier plan.

onResume se déclenche si l'application est fermée, mais fonctionne toujours en arrière-plan.

onLaunch se déclenche si l'application est complètement terminée.

Mettre à jour

comme votre question a été mise à jour, veuillez considérer ce qui suit article

• Messages de notification - se composent d'un titre et d'un corps de message et déclenchent le système de notification à l'arrivée sur l'appareil. En d'autres termes, une icône apparaîtra dans la barre d'état et une entrée apparaîtra dans l'ombre de notification. Ces notifications doivent être utilisées lors de l'envoi d'un message d'information que vous souhaitez que l'utilisateur voie.

ex:

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

• Messages de données - contiennent des données sous forme de paires clé/valeur et sont livrés directement à l'application sans déclencher le système de notification. Les messages de données sont utilisés lors de l'envoi de données en silence à l'application.

ex:

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

• Messages combinés - Contiennent une charge utile comprenant à la fois des notifications et des données. La notification est affichée à l'utilisateur et les données sont transmises à l'application.

ex:

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

Donc, je pense que vous utiliserez le troisième, qui envoie des notifications et des données en même temps.

Vous pouvez simplement accéder aux données en utilisant Dart comme ci-dessous.

message['data']['account']

Update 2

Comme vous avez mis à jour votre question et que ma solution n'a pas fonctionné correctement avec vous. J'ai décidé de le tester moi-même, et devinez quoi! Cela fonctionne très bien avec vos mêmes codes.

Mon code backend 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);
    });

et le code 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);
    }
  }

et la sortie de la console

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

Je crois donc que le problème est en quelque sorte dans vos codes, pas dans la solution que je vous donne. Veuillez rechercher clairement le problème que vous pourriez avoir. J'espère que vous le trouverez et que vous travaillerez bien pour vous.

5
Shady Boshra

Oui c'est possible en natif mais je ne suis pas sûr en flutter. Vous pouvez créer un PendingIntent avec une pile arrière.

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

Ensuite, vous devez passer le PendingIntent à la notification.

vérifiez ce lien: https://developer.Android.com/training/notify-user/navigation

2
Saeiddjawadi

La méthode la plus simple consiste à utiliser OneSignal si vous n'avez pas le temps de créer le backend pour envoyer des notifications Push à l'aide de Firebase, cependant, OneSignal a une limite sur son abonné (gratuit jusqu'à 30 000 abonnés).

1
anunixercoder