0

I am developing a chat app and so, I need to send notifications that new messages have been received. For that, I am using Firebase Functions. I'm using the sendToDevice function, that needs a token to send a notification. The problem is, I can't seem to retrieve token of the user that sent the message. This is my .js code:

const functions = require('firebase-functions');

const admin = require('firebase-admin');

admin.initializeApp(functions.config().firebase);


exports.sendNotification = functions.database.ref("/chats/{id}/messages/{messageId}/content")
.onWrite((change,context) => {
    var content = change.after.val();

    var payload = {
        data:{
            title: "Stranger has sent you a message",
            text: content
        }
    };

    // Here I need to the ID of the person who sent the message
    // And then compare this Id with the two Ids of the to users that are in the conversation
    // If the two Ids are different, then save the other Id as the token
    // So that I can send a notification to the other user.
    const senderId = database.ref("/chats/{id}/messages/{id}/sender/{senderId}");



    admin.messaging().sendToDevice(senderId, payload)
    .then(function(response){
        console.log("Successfully sent message: ", response);
        return null;
    })
    .catch(function(error){
        console.log("Error sending message: ", error);
    })
});

As you can see, I am checking for any changes in the messages/content child. That as the content of my notification.

Then, I am trying to retrieve the message sender ID so I can know who sent the message and retrieve the other user Id to notify him.

This might be a little confusing so here is my Firebase Realtime Database:

enter image description here

What am I doing wrong so this piece of code works as it should? This is the activity I have in android to receive the message:

class MyFirebaseInstanceId : FirebaseMessagingService() {
    override fun onMessageReceived(p0: RemoteMessage) {
        if(p0.data.size > 0){
            val payload :Map<String, String> = p0.data

            sendNotification(payload)

        }
    }

    private fun sendNotification(payload: Map<String, String>) {
        val builder = NotificationCompat.Builder(this)
        builder.setSmallIcon(R.drawable.common_google_signin_btn_icon_disabled)
        builder.setContentTitle(payload.get("username"))
        builder.setContentText(payload.get("email"))

        val intent = Intent(this, MainActivity::class.java)
        val stackBuilder = TaskStackBuilder.create(this)

        stackBuilder.addNextIntent(intent)

        val resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)

        builder.setContentIntent(resultPendingIntent)

        val notificationManager =  (getSystemService(Context.NOTIFICATION_SERVICE)) as NotificationManager

        notificationManager.notify(0, builder.build())
    }
}
2
  • Please note that with database.ref("/chats/{id}/messages/{id}/sender/{senderId}") you are not getting a field value, but just a Reference. You need to use the once() method. Also note that you need to return admin.messaging().sendToDevice(senderId, payload)..., see firebase.google.com/docs/functions/terminate-functions Commented Feb 16, 2020 at 14:03
  • @RenaudTarnec can you give me an example of how to use .once() function? That awnsers my question and I'd like to give you a green check mark. Commented Feb 16, 2020 at 14:11

1 Answer 1

1

Following our comments above, here is how to use the once() and val() methods in your Cloud Function:

//.....
const refSenderId = database.ref("/chats/{id}/messages/{id}/sender/{senderId}");

return refSenderId.once('value')
 .then(dataSnapshot => { 
     const senderId = dataSnapshot.val();
     return admin.messaging().sendToDevice(senderId, payload)
 })
.then(function(response){
    console.log("Successfully sent message: ", response);
    return null;
})
.catch(function(error){
    console.log("Error sending message: ", error);
    return null;   // <- Note the return here.
})
//.....
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! Quick question, can I use another .once() inside that one to retrieve another value?
Yes, but you need to correctly chain the different promises returned by the asynchronous methods. developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/… and firebase.google.com/docs/functions/terminate-functions. You can add your new code at the bottom of your question (by editing the question) and I will review it if you want.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.