I have chat app with firebase database and Firebase cloud messaging. I can send firebase notification via console but in real scenario it should be automatic. To make automatic notification,My friend wrote Index.js (Added in cloud functions) file for me but its not sending notifications.
As per our logic function should trigger whenever there is any new entries (in any node or in any room) and fetch these values by firebase function and make post request to FCM server to make notification to receiver device (get value of receiver device from token_To).
- Message
- Message_From
- Time
- Type
- token_To
Index.js
var functions = require('firebase-functions');
var admin = require('firebase-admin');
var serviceAccount = require('./demofcm-78aad-firebase-adminsdk-4v1ot-2764e7b580.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "/"
})
// // Create and Deploy Your First Cloud Functions
// //
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
// response.send("Hello from Firebase!");
// });
exports.setUserNode = functions.auth.user().onCreate(event => {
// ...
});
exports.notifyMsg = functions.database.ref('/{chatroom}/{mid}/')
.onWrite(event => {
if (!event.data.val()) {
return console.log('Message Deleted');
}
const getDeviceTokensPromise = admin.database().ref('/{chatroom}/{mid}/token_to').once('value');
return Promise.all([getDeviceTokensPromise]).then(results => {
const tokensSnapshot = results[0];
if (!tokensSnapshot.hasChildren()) {
return console.log('There are no notification tokens to send to.');
}
const payload = {
notification: {
title: 'You have a new Message!',
body: event.data.val().Message
}
};
const tokens = Object.keys(tokensSnapshot.val());
return admin.messaging().sendToDevice(tokens, payload).then(response => {
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
});
});
Firebase function Log
How can i fetch above mentioned values of any newly added node in same room(9810012321-9810012347) or any other room(9810012321-9810012325) from database and send it to FCM to make notification
Thanks in Advance.
I have chat app with firebase database and Firebase cloud messaging. I can send firebase notification via console but in real scenario it should be automatic. To make automatic notification,My friend wrote Index.js (Added in cloud functions) file for me but its not sending notifications.
As per our logic function should trigger whenever there is any new entries (in any node or in any room) and fetch these values by firebase function and make post request to FCM server to make notification to receiver device (get value of receiver device from token_To).
- Message
- Message_From
- Time
- Type
- token_To
Index.js
var functions = require('firebase-functions');
var admin = require('firebase-admin');
var serviceAccount = require('./demofcm-78aad-firebase-adminsdk-4v1ot-2764e7b580.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://demofcm-78aad.firebaseio./"
})
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google./docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
// response.send("Hello from Firebase!");
// });
exports.setUserNode = functions.auth.user().onCreate(event => {
// ...
});
exports.notifyMsg = functions.database.ref('/{chatroom}/{mid}/')
.onWrite(event => {
if (!event.data.val()) {
return console.log('Message Deleted');
}
const getDeviceTokensPromise = admin.database().ref('/{chatroom}/{mid}/token_to').once('value');
return Promise.all([getDeviceTokensPromise]).then(results => {
const tokensSnapshot = results[0];
if (!tokensSnapshot.hasChildren()) {
return console.log('There are no notification tokens to send to.');
}
const payload = {
notification: {
title: 'You have a new Message!',
body: event.data.val().Message
}
};
const tokens = Object.keys(tokensSnapshot.val());
return admin.messaging().sendToDevice(tokens, payload).then(response => {
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
});
});
Firebase function Log
How can i fetch above mentioned values of any newly added node in same room(9810012321-9810012347) or any other room(9810012321-9810012325) from database and send it to FCM to make notification
Thanks in Advance.
Share Improve this question asked Dec 20, 2017 at 0:35 androidXPandroidXP 1,7194 gold badges29 silver badges60 bronze badges4 Answers
Reset to default 2What i did is created a Message node and I believe doing this by users key. ie, having the receiver(toId) and sender (fromId) key to send the notification. Hope it helps.
exports.sendMessageNotification = functions.database.ref('/messages/{pushId}')
.onWrite(event => {
let message = event.data.current.val();
console.log('Fetched message', event.data.current.val());
let senderUid = message.fromId;
let receiverUid = message.toId;
let promises = [];
console.log('message fromId', receiverUid);
console.log('catch me', admin.database().ref(`/users/${receiverUid}`).once('value'));
if (senderUid == receiverUid) {
//if sender is receiver, don't send notification
//promises.push(event.data.current.ref.remove());
return Promise.all(promises);
}
let messageStats = message.messageStatus;
console.log('message Status', messageStats);
if (messageStats == "read") {
return Promise.all(promises);
}
let getInstanceIdPromise = admin.database().ref(`/users/${receiverUid}/pushToken`).once('value');
let getSenderUidPromise = admin.auth().getUser(senderUid);
return Promise.all([getInstanceIdPromise, getSenderUidPromise]).then(results => {
let instanceId = results[0].val();
let sender = results[1];
console.log('notifying ' + receiverUid + ' about ' + message.text + ' from ' + senderUid);
console.log('Sender ', sender);
var badgeCount = 1;
let payload = {
notification: {
uid: sender.uid,
title: 'New message from' + ' ' + sender.displayName,
body: message.text,
sound: 'default',
badge: badgeCount.toString()
},
'data': {
'notificationType': "messaging",
'uid': sender.uid
}
};
badgeCount++;
admin.messaging().sendToDevice(instanceId, payload)
.then(function (response) {
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
});
});
});
const getDeviceTokensPromise = event.data.child('token_To');
should be there instated of getting data from database reference.
or
with fixed path without wildcard like below
const getDeviceTokensPromise = admin.database().ref('/${chatroom}/${mid}/token_to').once('value');
where chatroom and mid is variable which contain value
Second thing:
if (!tokensSnapshot.exists()) {
should in replace of
if (!tokensSnapshot.hasChildren()) {
third thing:
I am not sure about push notification tokenId but is it required to do?
const tokens = Object.keys(tokensSnapshot.val());
may be we can use directly like below to send push notification
const tokens = tokensSnapshot.val();
You could store all device tokens in a node called tokens like in my example. Tokens could be an array if you would like one user to be able to get notifications on multiple devices. Anyway, store them by their UID.
This works for both Andriod and iOS.
Here is my code:
function loadUsers() {
let dbRef = admin.database().ref('/tokens/' + recieveId);
console.log(recieveId)
let defer = new Promise((resolve, reject) => {
dbRef.once('value', (snap) => {
let data = snap.val();
console.log("token: " + data.token)
//userToken = data.token
resolve(data.token);
}, (err) => {
reject(err);
});
});
return defer;
}
Next we create the notification. I created a lastMessage node to capture just the last message sent in the chat. It is just updated every time a new message is sent in a chat between two users. Makes it easy to get the value. Also makes it easy to show the message on the Conversations screen where there is a list of users who are in a conversation with the current user.
exports.newMessagePush =
functions.database.ref('/lastMessages/{rcId}/{sendId}').onWrite(event => {
if (!event.data.exists()) {
console.log("deleted message")
return;
}
recieveId = event.params.rcId
//let path = event.data.adminRef.toString();
// let recieveId = path.slice(53, 81);
return loadUsers().then(user => {
console.log("Event " + event.data.child("text").val());
let payload = {
notification: {
title: event.data.child("name").val(),
body: event.data.child("text").val(),
sound: 'default',
priority: "10",
}
};
return admin.messaging().sendToDevice(user , payload);
});
});
To implement this logic on your current data structure, just change this line:
let dbRef = admin.database().ref('/tokens/' + recieveId);
and this line:
exports.newMessagePush =
functions.database.ref('/lastMessages/{rcId}/{sendId}').onWrite(event
=> {
to your token location:
let dbRef =
admin.database().ref('/${chatroom}/${mid}/token_to');
and your conversation location:
exports.notifyMsg = functions.database.ref('/{chatroom}/{mid}/')
.onWrite(event => {
Then just change the notification payload be the message you want to display and throw in your error handling on the end of the sendToDevice function, as you did in your code.
Hopefully you figured all this out already but if not maybe this will help you or others trying to use Cloud Functions for notifications.
let payload = {
notification: {
uid: sender.uid,
title: 'New message from' + ' ' + sender.displayName,
body: message.text,
sound: 'default',
badge: badgeCount.toString()
},
'data': {
'notificationType': "messaging",
'uid': sender.uid
}
};
There are two types of FCMs. 1) Data 2) Notification
For detailed overview : FCM Reference
You have to fix your payload for both FCMS. And for Data FCM you have to extract Data in your FCM Service (Client) and generate a push notification according to your need.