Firebase increase badge count with iOS - firebase

I'm developing an app with Firebase and I implemented push notifications right. And now I'm trying to show badge icon but I can't find a good information to do that. I read I should work on the server side and the example code is something like this.
"aps" :
{
"alert" : "Your notification message",
"badge" : badgecount ,
"sound" : "bingbong.aiff"
}
But I don't know where to add the code in my function.
This is how my function looks like:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.pushNotifications = functions.database.ref('/messages/{messageId}')
.onCreate(event => {
const data = event.data;
const fromId = data.fromId;
const toId = data.toId;
const message = data.message;
console.log(fromId + ' sent a message to' + toId);
return admin.database().ref('/users/' + fromId).once('value', snapshot => {
var user = snapshot.val();
var payload = {
notification: {
title: user.username,
body: message
}
}
admin.messaging().sendToDevice(user.fcmToken, payload)
.then(function(response) {
// See the MessagingDevicesResponse reference documentation for
// the contents of response.
console.log("Successfully sent message:", response);
})
.catch(function(error) {
console.log("Error sending message:", error);
});
})
Can someone give me an advice how to do this?

The "apns" object goes in the payload object as a sibling to notification:
var payload = {
notification: {
title: user.username,
body: message
},
apns: {
// badge and other ios only data here here
}
}
I would also suggest returning the admin.messaging() method: return admin.messagins().sendToDevice().ect. It might not be required, but Firebase suggests returning all thenable references.

Related

how to avoid duplicate Push Notification

importScripts('https://www.gstatic.com/firebasejs/8.4.3/firebase-app.js')
importScripts('https://www.gstatic.com/firebasejs/8.4.3/firebase-messaging.js')
firebase.initializeApp({...config});
const messaging = firebase.messaging();
messaging.onBackgroundMessage(function (payload) {
console.log('sw-fb', payload);
const notificationTitle = payload.notification.title;
const notificationOptions = {
body:"something Body",
data:{...}
};
return self.registration.showNotification(notificationTitle, notificationOptions);
},
Here i am trying to show push notification from firebase, but for every single notification getting two notifications. 1st one is the default one and 2nd one is from my service worker.
can anyone help me to fix the duplicate default notification.
to avoid default notification ,when sending through fcm need to send notification data as below
var payload = {
notification:{},
data: {
title:'title',
body:'something body',
image:path,
icon...},
token: registrationToken
};
messaging.send(payload).then((result) => {console.log(result)})
and update srviceworker as
messaging.onBackgroundMessage((payload) => {
const { data }= payload;
const notificationTitle = data?.title;
const notificationOptions =
{ image:data.image, title:data.title, body: data.body, icon:data.icon }
self.registration.showNotification(notificationTitle, notificationOptions);
});

Send notification to all user who have a specific location using Firebase Cloud Functions

I have a trigger that fires when an item is creating. Therefore, i want to see that when the item is created, all users who have a location that was saved in the item will receive a notification
import functions = require('firebase-functions');
import admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotification = functions.firestore
.document('itens/{itenId}').onCreate((snap, context) => {
//You get the values of the newly created doc as follows:
const data = snap.data();
const name = data.name;
const location = data.location;
const payload = {
notification: {
title: "Avana - Está bater",
body: `Podes encontrar : ${name} em ${location}`, //Here we use value
sound: "default"
}
};
const options = {
priority: "high",
};
admin.messaging().sendToTopic("newItem", payload, options)
.then(function (response) {
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
});
console.log("Notification sent!");
return null;
});
your solution is Firebase Geofire:
https://firebase.googleblog.com/2013/09/geofire-location-queries-for-fun-and.html
https://medium.com/google-cloud/firebase-is-cool-geofire-is-just-awesome-b7f2be5e0f0f#.x78gjws28

Firebase Cloud Functions Error with CanonicalRegistrationTokenCount

I am trying to send a signup notification to my app after registration and user has been saved in db. I am using firebase cloud functions for this purpose.
I have gotten the device token from firebaseinstanceidservice and saved that in the user's db with the path users/userid/deviceToken and referenced this path in the function like below code:
exports.sendNotification = functions.database.ref("users/{userId}/{instanceId_token}")
I have tried logging the devicetoken just to be sure but in cloud console, I keep getting other attributes for that log like : sendNotification
deviceToken name, sendNotification
deviceToken userId instead of the alphanumeric value saved in db. Is this path wrong?
Here's my full code:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification =
functions.database.ref("users/{userId}/{instanceId_token}")
.onWrite((changes, context) => {
const userId = context.params.userId;
console.log("user-id", userId);
const notificationToken = context.params.instanceId_token;
console.log("deviceToken", notificationToken);
var payload = {
data: {
title: "Welcome to My Group",
message: "You may have new messages"
}
};
return admin.messaging().sendToDevice(notificationToken, payload)
.then(function (response) {
return console.log("Successfully sent message: ", response);
})
.catch(function (error) {
return console.log("Error sending message: ", error);
})
});
Also, the function shows this mildly positive message, after the admin.messaging callback:
Successfully sent message: { results: [ { error: [Object] } ],
canonicalRegistrationTokenCount: 0,
failureCount: 1,
successCount: 0,
multicastId: 8880906162831350000 }
How do I resolve this, I am using an android client?
Here's my db structure:
You should trigger you function on the upper node, as follows. And access the instanceId_token through changes.after.val().
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification =
functions.database.ref("users/{userId}")
.onWrite((changes, context) => {
const userId = context.params.userId;
console.log("user-id", userId);
const notificationToken = changes.after.val().instanceId_token;
console.log("deviceToken", notificationToken);
var payload = {
data: {
title: "Welcome to My Group",
message: "You may have new messages"
}
};
return admin.messaging().sendToDevice(notificationToken, payload)
.catch(function (error) {
console.log("Error sending message: ", error);
})
});
In case you add the instanceId_token ONLY AFTER having created the user, then you should trigger with onUpdate() (which "triggers when data is updated", while onWrite() "triggers when data is created, updated, or deleted").
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification =
functions.database.ref("users/{userId}")
.onUpdate((changes, context) => {
const userId = context.params.userId;
console.log("user-id", userId);
const notificationToken = changes.after.val().instanceId_token;
console.log("deviceToken", notificationToken);
if (notificationToken === undefined) {
console.log("notificationToken === undefined");
return false;
} else {
var payload = {
data: {
title: "Welcome to My Group",
message: "You may have new messages"
}
};
return admin.messaging().sendToDevice(notificationToken, payload)
.catch(function (error) {
console.log("Error sending message: ", error);
})
}
});
Also note that you should not do
return admin.messaging().sendToDevice(notificationToken, payload)
.then(function (response) {
return console.log("Successfully sent message: ", response);
})
.catch(function (error) {
return console.log("Error sending message: ", error);
});
because in this case you are not returning a promise "that resolves when all the async work is done in the function". (see the answer of this question)
So just return the promise returned by sendToDevice (see doc), as follows:
return admin.messaging().sendToDevice(notificationToken, payload)
.catch(function (error) {
console.log("Error sending message: ", error); // here no return
});

How do you get to the values of ALL the tokens on your server?

I'd like to get the collection of ALL my FCM user iOS device tokens from this path in my Firebase Database:
BootCamp/Notifications/iOS
At this location, an autoIDChild is created to store the users' device tokens as "deviceToken".
I've been trying to follow the cloud_functions example at this link, but as my use-case is different it's been a little tough to figure out. Here's my cloud-function code in JS:
exports.iOSPush = functions.database.ref('/BootCamp/Bulletins/date').onWrite((snapShot, context) =>{
let tokensSnapShot
let tokens
//here, I attempt to get access to all iOS tokens on my server
const getTokens = admin.database().ref('/BootCamp/Notifications/iOS/{key}').once('value');
return Promise.all([getTokens]).then( (results) => {
tokensSnapShot = results[0]
tokens = Object.keys(tokensSnapShot)
const payload = {
notification:{
title: 'congrats it works',
body: 'Cloud function noti for ios',
sound: 'default',
badge: '1'
}
};
//tokens value in the console log is: "node_,ref_,index_". I was expecting an array of tokens:/
return admin.messaging().sendToDevice(tokens, payload)
})
});
How do I get to these iOS tokens on my server?
It finally occurred to me that I had to name the childPath the same as the device token instead of a randomly generated childID.
Please check this example:
return Promise.all([admin.database().ref(`/users/${user}/account/tokensArray`).once('value')]).then(results => {
const tokens = results[0];
if (!tokens.hasChildren()) return null;
let payload = {
notification: {
title: 'title',
body: 'message',
icon: 'icon-192x192.png'
}
};
const tokensList = Object.keys(tokens.val());
return admin.messaging().sendToDevice(tokensList, payload);
});

Notifications not showing up on database trigger

I am using firebase cloud functions for sending notifications to users when database trigger is called.The registration token is saved in firebase database. The problem is that inspite of registration tokens getting saved, the notifications are not showing up in these devices.
This is index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/Blog').onWrite(event => {
const title = event.data.child('title').val();
const token_no = event.data.child('token_no').val();
const getDeviceTokensPromise = admin.database().ref(`/Token/${token_no}`).once('value');
const getBody=admin.database().ref(`/Blog`).once('value');
return Promise.all([getDeviceTokensPromise,getBody]).then(results => {
const tokensSnapshot = results[0];
const notify=results[1];
if (!tokensSnapshot.hasChildren()) {
return console.log('There are no notification tokens to send to.');
}
console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.');
// Notification details.
const payload = {
notification: {
title: 'You have a new Alert!',
body: `${notify.child('title').val()}`,
}
};
// Listing all tokens.
const tokens = Object.keys(tokensSnapshot.val());
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
// Cleanup the tokens who are not registered anymore.
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);
});
});
});
Database snapshot:
"Token" : {
"token_no" : {
"ctxjePemYZE:APA91bFJXXyTkyvXOlSY...4VbWu7Vbf7itwbwZu9umSvg_tdB1lKD1d8g" : "true",
"dgVszInjIW0:APA91bFZE3Av5unZTgp...RUeYb-CUhWjO1otqguhE9NTQZ8XgK6nRIW5" : "true"
}
}
Update 2:
Your code uses Object.keys(tokensSnapshot.val()) to get the tokens. That means the tokens must be the keys under token_no, not the values. Like this:
"Token" : {
"-KoWsMn9rCIitQeNvixr" : {
"dK1FjGbNr6k:APA91b...S8JK2d69JpO" : "123" // token is the key, value is not significant; could be "123", true, or 0.
},
...
}
Update:
You should review the documentation for the Event parameter of a database trigger to get a better understanding of the params and data properties. params provide acces to the wildcards in the trigger reference, data is the snapshot. In your code, you want to get values from the snapshot.
Add these changes:
const title = event.data.child('title').val();
const desp = event.data.child('desp').val();
const token_no = event.data.child('token_no').val()
const payload = {
notification: {
title: 'You have a new Alert!',
body: `${Post.child('title').val()}`, // <= CHANGED
//icon: follower.photoURL
}
};
Running the code you posted, with these changes, I am able to send and receive a notification.
There are two problems. The first is this statement:
const getDeviceTokensPromise = admin.database().ref(`/Token/{token_no}`).once('value');
token_no is not defined. And when you do define it and want to substitute its value, you will need to add a $:
`/Token/${token_no}`
The second problem is that Post is not defined, which causes function execution to fail. Check your function logs:
const payload = {
notification: {
title: 'You have a new Alert!',
body: `${Post.title}`,
//icon: follower.photoURL
}
};

Resources