parse-community / Parse-SDK-Flutter

The Dart/Flutter SDK for Parse Platform
https://parseplatform.org
Apache License 2.0
574 stars 191 forks source link

Push notification implementation in Flutter Parse SDK? #302

Closed guilhermedaldim closed 3 years ago

guilhermedaldim commented 4 years ago

Is it possible with the Flutter Parse SDK to send push notification?

Send a notification to a specific user with deviceToken and be able to handle it according to the notification payload?

In advance, thank you.

pastordee commented 4 years ago

I use firebase admin on the server side and then use cloud code to send a notification

guilhermedaldim commented 4 years ago

I can send and receive notifications with firebase admin, thanks @pastordee.

However, on android, when I get notifications in the foreground, the application crashes.

How did you set up your client application?

pastordee commented 4 years ago

I can send and receive notifications with firebase admin, thanks @pastordee.

However, on android, when I get notifications in the foreground, the application crashes.

How did you set up your client application?

` void configNotification() { print("onMessage: Initialization "); var android = new AndroidInitializationSettings('@drawable/ic_notifications'); var ios = new IOSInitializationSettings(); var platform = new InitializationSettings(android, ios); flutterLocalNotificationsPlugin.initialize(platform); // _firebaseMessaging.subscribeToTopic('all');

_firebaseMessaging.getToken().then((String token) {
    assert(token != null);
    updateParseInstallation(token);
  });

 _firebaseMessaging.requestNotificationPermissions(
    const IosNotificationSettings(sound: true, badge: true, alert: true)
  );
_firebaseMessaging.onIosSettingsRegistered.listen((IosNotificationSettings settings) {
    print("Settings registered: $settings");
  });

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

  },
  onLaunch: (Map<String, dynamic> message) async {
    print("onLaunch: $message");
    onLaunchNotificationsAlert(message); 
  },
  onResume: (Map<String, dynamic> message) async {
    print("onResume: $message");
    onResumeNotificationsAlert(message);
  },
);

} `

e.g `onMessageNotificationsAlert(Map<String, dynamic> message) async{ print("onMessageNotificationsAlert");

    Map notification = message['notification'];
    var body = notification['body'];
    var title = notification['title'];
    var view = notification['view'];
    var objectId = notification['objectId'];

}`

pamarcan commented 4 years ago

Thanks pastordee, how did you integrate firebase admin with parse server users?

It would be very useful for everyone to have a solution to send push notifications easily from the parse server.

RodrigoSMarques commented 4 years ago

Hi @pamarcan I am using OneSignal. I associate the OneSignal user with the user's ObjectID on the Parse Server. Using Cloud Code I send Push by activating the OneSignal API.

pastordee commented 4 years ago

@pamarcan

  1. npm firebase admin
  2. in my main.js in the cloud folder var admin = require("firebase-admin"); var serviceAccount = require("/path-to-/serviceAccountKey.json"); admin.initializeApp({ credential: admin.credential.cert(serviceAccount), databaseURL: "https://***********.firebaseio.com" });

               `
                  var options = {
            priority: "high",
            timeToLive: 60 * 60 * 24
        };
        var payloadIOS ={
    
            notification: {
                title: title,
                body: theMessage,
                view: "woeGroup",
                objectId: post.id
            }
    
        };
        var payloadAndroid ={
    
            notification: {
                title: title,
                body: theMessage,
                view: "woeGroup",
                objectId: post.id
            }
    
        };

    `

       `
        var pushQueryFCM = new Parse.Query(Parse.Installation);
    pushQueryFCM.notEqualTo('userId', user.id);// the user posting is not in the channels
    pushQueryFCM.equalTo('channels', publicId);
        pushQueryFCM.find({useMasterKey:true})
        .then((pushQuery) => {
    
            for (i = 0; i < pushQuery.length; i++) {
    
                var deviceType =  pushQuery[i].get('deviceType');
                var token = pushQuery[i].get('deviceToken');
    
                if(deviceType == "ios" && token != ""){
    
                    admin.messaging().sendToDevice(token, payloadIOS,options)
                    .then(function(response){
                        console.log("messaging=>**********successfully" + response);
                    })
                    .catch(function(error){
                        console.log("messaging=>********** Got an error " + error.code + " : " + error.message);
                    });
    
                }else if(deviceType == "android" && token != ""){
    
                    admin.messaging().sendToDevice(token, payloadAndroid,options)
                    .then(function(response){
                        console.log("messaging=>**********successfully" + response);
                    })
                    .catch(function(error){
                        console.log("messaging=>********** Got an error " + error.code + " : " + error.message);
                    });
    
                }//
    
            }
        })
        .catch(function(error){
            console.log("messaging=>********** Got an error  pushQueryFCM " + error.code + " : " + error.message);
        });

`

  1. In your pubspec.yaml firebase_messaging flutter_local_notifications

  2. main.dart FirebaseMessaging _firebaseMessaging = FirebaseMessaging(); FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;

    ` void configNotification() { print("onMessage: Initialization "); var android = new AndroidInitializationSettings('@drawable/ic_notifications'); var ios = new IOSInitializationSettings(); var platform = new InitializationSettings(android, ios); flutterLocalNotificationsPlugin.initialize(platform);

    _firebaseMessaging.getToken().then((String token) { assert(token != null); updateParseInstallation(token); });

    _firebaseMessaging.requestNotificationPermissions( const IosNotificationSettings(sound: true, badge: true, alert: true) ); _firebaseMessaging.onIosSettingsRegistered.listen((IosNotificationSettings settings) { print("Settings registered: $settings"); });

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

    }, onLaunch: (Map<String, dynamic> message) async { onLaunchNotificationsAlert(message); }, onResume: (Map<String, dynamic> message) async { onResumeNotificationsAlert(message); }, );

    }

Future updateParseInstallation(token) async{

print("updateParseInstallationt $token"); var installation = await ParseInstallation.currentInstallation(); installation.set("deviceToken", token); var apiResponse = await installation.save(); if(apiResponse.success){ print("updateParseInstallationt initInstallation updated ${apiResponse.result}"); } }

`

pamarcan commented 4 years ago

Wow! thanks a lot pastordee

GursheeshSingh commented 4 years ago

I don't think local messaging is needed, only in case you want to show user a notification if app is opened and in foreground. Firebase messaging does not display notification if app is opened and in foreground.

pastordee commented 4 years ago

I don't think local messaging is needed, only in case you want to show user a notification if app is opened and in foreground. Firebase messaging does not display notification if app is opened and in foreground.

Because firebase doesn’t display notification in app that’s why you need something like Flushbar so you can use that to show the in app message yourself

GursheeshSingh commented 4 years ago

Firebase does show notifications.

As explained in their official documentation- https://pub.dev/packages/firebase_messaging#receiving-messages

If app is in foreground, it doesn't show notifications.

MungaraJay commented 4 years ago

Hello @phillwiggins @RodrigoSMarques @RodrigoSMarques @guilhermedaldim @pamarcan

Is there any updates related to push notifications with parse sdk in flutter?

Can we implement push notifications using parse server sdk for flutter as well?

Waiting for reply.

Thanks.

RodrigoSMarques commented 4 years ago

@MungaraJay To use the native functionality it is necessary to use Platform Channel and I do not see the need. Use Firebase Cloud Messaging that has the plugin ready and does the same. Retrieve the Token from the device with FCM, save the token in Class Installation. Send Push Notification through Parse and receive it on the device through FCM.

vinnytwice commented 3 years ago

To use the native functionality it is necessary to use Platform Channel and I do not see the need.

@RodrigoSMarques
Basically EU companies can't send anything at all to USA..so for push notifications I'd have to avoid FCM altogether. I'm in the middle of moving away from Firebase as GDPR is very restrictive about UE data sent abroad. I see you're using OneSignal, are you UE based? Parse seems to offer all I'm currently using for my app and I can host a Parse server on UE Server providers..

Thanks.

fischerscode commented 3 years ago

@vinnytwice As far as I know, OneSignal uses FCM in the background. But I might be wrong.

RodrigoSMarques commented 3 years ago

We are closing issues that have been open for a long time without activity. This will make it easier to organize things from now on. If the problem persists, please open a new issue. Thanks.

gadgetreviews commented 2 years ago

I am not sure if the information at this issue is obsolete or not but I am able to send push notification at android without need of firebase admin, just only with parse server. But on iOS, it is not working. I get following error on parse server error log.

ERR! parse-server-push-adapter APNS APNS error transmitting to device <token> with status 400 and reason BadDeviceToken

As far as I understand I need to add some code to AppDelegate.swift at iOS code of flutter. When I added the code to AppDelegate.swift as described in this link, I get compile errors. I think this document needed to be updated. This document might be created for an older version of XCode and/or Swift.

https://docs.parseplatform.org/tutorials/ios-push-notifications/

Nidal-Bakir commented 2 years ago

@pastordee I was talking with the back4app support team and they told me the following: NOTE: I did not try this solution yet but will in a few days (on android) and return here to write about it and edit this comment. Edit: yes it's working but it will send (Data) type of notifications

At the moment, we do not have a guide for it, but, you can try using the following plugin:

https://pub.dev/packages/firebase_messaging

You can also use this code as a reference to save the device token:

final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
void configNotification() {
   var android = AndroidInitializationSettings(‘mipmap/ic_launcher’);
   var ios = IOSInitializationSettings();
   var platform = InitializationSettings(android, ios);
   flutterLocalNotificationsPlugin.initialize(platform);
   _firebaseMessaging.configure(
     onMessage: (Map<String, dynamic> message) async {
       print(“onMessage: $message”);
       showNotification(message);
     },
     onLaunch: (Map<String, dynamic> message) async {
       print(“onLaunch: $message”);
     },
     onResume: (Map<String, dynamic> message) async {
       print(“onResume: $message”);
     },
   );
   _firebaseMessaging.requestNotificationPermissions(
       const IosNotificationSettings(sound: true, badge: true, alert: true));
   _firebaseMessaging.onIosSettingsRegistered
       .listen((IosNotificationSettings settings) {
     print(“Settings registered: $settings”);
   });
   _firebaseMessaging.getToken().then((String token) {
     assert(token != null);
     final ParseInstallation instalattion = await ParseInstallation.currentInstallation ();
     instalation.deviceToken = token;
     await installation.save ();
   });
 }
 showNotification(Map<String, dynamic> msg) async {
   var data = jsonDecode(msg[“data”][“data”]);
   var android = AndroidNotificationDetails(
     ‘aaaaaaaa’,
     “yyyyyyyyyyy”,
     “Yyyyyyyyyyyyyyy”,
   );
   var iOS = IOSNotificationDetails();
   var platform = NotificationDetails(android, iOS);
   await flutterLocalNotificationsPlugin.show(
       0, data[“Title”], data[“alert”], platform);
 }

You have to call the configNotification method inside the flutter view. You will collect the token using the initState() method.

After, to send the push you can use Cloud Code.

This is a Cloud Code function that you can use as a reference:

Parse.Cloud.define("sendPush", function (request, response) {
const userId = request.params.userId;
const title = request.params.title;
const message = request.params.message;
sendPush(userId, title, message);
response.success();
});
function sendPush(user, title, message) {
   var oneWeekAway = new Date(new Date().getTime() + 7 * 24 * 60 * 60 * 1000);
// Find devices associated with the recipient user
var destinationUser = new Parse.User();
destinationUser.id  = user;
var userQuery = new Parse.Query(Parse.User).get(destinationUser);
const payloadData = {
  "alert": message,
  "title": title,
  "badge": "Increment",
  "sound": "default",
};
console.log('Push Title / Message: ' + title + " / " + message);
var queryInstall = new Parse.Query(Parse.Installation);
queryInstall.matchesQuery("user", userQuery);
// Send the push notification to results of the query
Parse.Push.send({
  where: queryInstall,
  expiration_time: oneWeekAway,
  data: payloadData,
  notification: payloadNotification
}, {
    useMasterKey: true,
    success: function () {
      // Push was successful
      console.log('Push was sent successfully.');
      return true;
    },
    error: function (error) {
      // Push was unsucessful
      console.log('Push failed to send with error: ' + error.message);
      return false;
    }
  });
}

But you can also use the dashboard instead of the Cloud Code function. Follow the initial steps provided in order to set up the push, and then try to use the dashboard for this.