0

We are trying to implement a device to device notification system in firebase, but we experience a strange phenomena where we sometimes receive notifications and sometimes we do not. unfortunately, we could not identify what's the difference between the occasion.
We do however saw in the firebase documentation that we need to implement a service listener for the device token change(and add it to the manifest), and we think that maybe the problem is that we do not inform the server with that change.

The firebase functions code:

/*
 * Functions SDK : is required to work with firebase functions.
 * Admin SDK : is required to send Notification using functions.
 */

'use strict'

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);


/*
 * 'OnWrite' works as 'addValueEventListener' for android. It will fire the function
 * everytime there is some item added, removed or changed from the provided 'database.ref'
 * 'sendNotification' is the name of the function, which can be changed according to
 * your requirement
 */

exports.sendNotification = functions.database.ref('/notifications/{user_id}/{notification_id}').onWrite(event => {


  /*
   * You can store values as variables from the 'database.ref'
   * Just like here, I've done for 'user_id' and 'notification'
   */

  const user_id = event.params.user_id;
  const notification_id = event.params.notification_id;

  console.log('We have a notification from : ', user_id);

  /*
   * Stops proceeding to the rest of the function if the entry is deleted from database.
   * If you want to work with what should happen when an entry is deleted, you can replace the
   * line from "return console.log.... "
   */

  if(!event.data.val()){

    return console.log('A Notification has been deleted from the database : ', notification_id);

  }

  /*
   * 'fromUser' query retreives the ID of the user who sent the notification
   */

  const fromUser = admin.database().ref(`/notifications/${user_id}/${notification_id}`).once('value');

  return fromUser.then(fromUserResult => {

    const from_user_id = fromUserResult.val().from;

    console.log('You have new notification from  : ', from_user_id);

    /*
     * The we run two queries at a time using Firebase 'Promise'.
     * One to get the name of the user who sent the notification
     * another one to get the devicetoken to the device we want to send notification to
     */

    const userQuery = admin.database().ref(`Users/${from_user_id}/name`).once('value');
    const deviceToken = admin.database().ref(`/Users/${user_id}/device_token`).once('value');

    return Promise.all([userQuery, deviceToken]).then(result => {

      const userName = result[0].val();
      const token_id = result[1].val();

      /*
       * We are creating a 'payload' to create a notification to be sent.
       */

      const payload = {
        notification: {
          title : "New Friend Request",
          body: `${userName} has sent you request`,
          icon: "default",
          click_action : "in.tvac.akshaye.lapitchat_TARGET_NOTIFICATION"
        },
        data : {
          from_user_id : from_user_id
        }
      };

      /*
       * Then using admin.messaging() we are sending the payload notification to the token_id of
       * the device we retreived.
       */

      return admin.messaging().sendToDevice(token_id, payload).then(response => {

        console.log('This was the notification Feature');

      });

    });

  });

});

The send notification function

private void sendNotificationToCostumer() {
        final HashMap<String, String> notificationData = new HashMap<>();
        notificationData.put("from", currentUser.getUid());
        notificationData.put("type", "bid request");

        FirebaseDatabase.getInstance().getReference().child("notifications").child(curJobInflated.second.getPersonUid())
                .push().setValue(notificationData).
                addOnSuccessListener(new OnSuccessListener<Void>() {
                    @Override
                    public void onSuccess(Void aVoid) {
                        Toast.makeText(MapActivity.this, "sending notification to the costumer",
                                Toast.LENGTH_SHORT).show();
                    }
                });
    }

The firebase instance service (It is a copied code, and probably essential code here is missing

package com.rubz.dvir.rubz;

import android.util.Log;

import com.google.firebase.iid.FirebaseInstanceId;
import com.google.firebase.iid.FirebaseInstanceIdService;
import com.google.firebase.messaging.FirebaseMessaging;

public class MyFirebaseInstanceIdService extends FirebaseInstanceIdService {

    private static final String TAG = "MyFirebaseIIDService";
    private static final String FRIENDLY_ENGAGE_TOPIC = "friendly_engage";

    /**
     * The Application's current Instance ID token is no longer valid and thus a new one must be requested.
     */
    @Override
    public void onTokenRefresh() {
        // If you need to handle the generation of a token, initially or after a refresh this is
        // where you should do that.
        String token = FirebaseInstanceId.getInstance().getToken();
        Log.d(TAG, "FCM Token: " + token);
    }
}

Firebase messaging service implementation

package com.rubz.dvir.rubz;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.widget.Toast;

import com.google.firebase.messaging.RemoteMessage;

public class FirebaseMessagingService extends  com.google.firebase.messaging.FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);

        String messageTitle = remoteMessage.getNotification().getTitle();
        String messageBody = remoteMessage.getNotification().getBody();

        //get the click action
        String click_action = remoteMessage.getNotification().getClickAction();
        String dataMessage = remoteMessage.getData().get("message");
        //String dataFrom = remoteMessage.getData().get("from_id");

        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, getString(R.string.default_notification_channel_id))
                .setSmallIcon(R.drawable.menu_icon)
                .setContentTitle("new notification")
                .setContentText("Hi your bid has accepted")
                .setPriority(NotificationCompat.PRIORITY_DEFAULT);

        int mNotificationId = (int)System.currentTimeMillis();
        NotificationManager mNotifyMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);


        Intent resultIntent = new Intent(click_action);
        resultIntent.putExtra("message", dataMessage);
        //resultIntent.putExtra("dataFrom", dataFrom);

        PendingIntent resultPendingIntent = PendingIntent.getActivity(this,0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        mBuilder.setContentIntent(resultPendingIntent);
        mNotifyMgr.notify(mNotificationId, mBuilder.build());
    }
}

The relevant service declarations appear in the manifest.

update: when testing in debug mode we receive the notification in the "received" device, but somehow the notification doesn't inflate.

update2: the problem wasn't related to firebase at all, but to the notification usage in SDK>26
see Notification Not showing

Peter Haddad
  • 78,874
  • 25
  • 140
  • 134
DsCpp
  • 2,259
  • 3
  • 18
  • 46

1 Answers1

1

In your index.js file you have this:

const payload = {
    notification: {
      title : "New Friend Request",
      body: `${userName} has sent you request`,
      icon: "default",
      click_action : "in.tvac.akshaye.lapitchat_TARGET_NOTIFICATION"
    },
    data : {
      from_user_id : from_user_id
    }
  };

Here you are sending a notification payload, which will only send the notification is the phone is in foreground (opened and you are using it). So if the phone is in background you wont receive the notification even though in the firebase console you have status "ok"

To be able to get the notification, when phone is in background and in foreground, you need to use data payload, example:

data: {
      title : "New Friend Request",
      body: `${userName} has sent you request`,
      icon: "default",
      click_action : "in.tvac.akshaye.lapitchat_TARGET_NOTIFICATION"
    },

and then in FCM, you need to receive that data:

if (remoteMessage.getData().size() > 0) {

    title = remoteMessage.getData().get("title");
    body = remoteMessage.getData().get("body");
}

more info here:

https://firebase.google.com/docs/cloud-messaging/concept-options

Peter Haddad
  • 78,874
  • 25
  • 140
  • 134
  • Thanks, but it didn't solve the problem, actually, even when the app is running some of us don't get the notification, while one of us gets it (it's always one of the three that gets the notifications) – DsCpp Apr 20 '18 at 16:37
  • maybe its because of the device – Peter Haddad Apr 20 '18 at 17:13