I have an application that sends users push notifications whenever db item is changed. However, the problem is whenever I send a notification it creates a new item in the notifications drawer. But what I want to do is to stack or group these notifications so there will be only one item for all of them which says something like "9 items have changed".
How can I do this with Ionic 3, phonegap push plugin and firebase?
Here is my current code:
const options: PushOptions = {
android: {
senderID: SENDER_ID
},
ios: {
alert: 'true',
badge: true,
sound: 'false'
},
windows: {},
browser: {
pushServiceURL: 'http://push.api.phonegap.com/v1/push'
}
},
pushObject: PushObject = this.push.init(options);
pushObject.on('registration').subscribe((registration: any) => {
this.afDatabase.list('/users')
.update(`/${user.uid}/devices/${registration.registrationId}/`, {isKept: true});
});
pushObject.on('error').subscribe(error => alert('Error with Push plugin' + JSON.stringify(error)));
And what I have at the firebase functions:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const _ = require('lodash');
admin.initializeApp(functions.config().firebase);
exports.onItemsListItemAdd = functions.database.ref('/items-list/{item_id}').onCreate(event => {
let payload = {
notification: {
title: 'Items list',
body: `Added: ${event.data.val().itemName} [${event.data.val().itemNumber}]`,
icon: 'default'
}
};
return sendToDevices(payload);
});
exports.onItemsListItemUpdate = functions.database.ref('/items-list/{item_id}').onUpdate(event => {
let payload = {
notification: {
title: 'Items list',
body: `Updated: ${event.data.val().itemName} [${event.data.val().itemNumber}]`,
icon: 'default'
}
};
return sendToDevices(payload);
});
exports.onItemsListItemDelete = functions.database.ref('/items-list/{item_id}').onDelete(event => {
let payload = {
notification: {
title: 'Items list',
body: `Deleted: ${event.data.previous.val().itemName} [${event.data.previous.val().itemNumber}]`,
icon: 'default'
}
};
return sendToDevices(payload);
});
function sendToDevices(payload) {
const deviceTokens = admin.database().ref('/users').once('value');
return deviceTokens.then(allTokens => {
if (allTokens.val()) {
// Listing all tokens.
const tokens = _(allTokens.val())
.mapValues(user => user.devices)
.values()
.map(device => Object.keys(device))
.flatten()
.value();
// 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(allTokens.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
}
});
}
After looking through the official documentation and a little of experimnting I've finally found the answer. Basically what I needed to do is to replace "notification" field with "data" field in my push notification and give it different properties. Please note that the given code works if and only if you totally remove "notification" field.
Here is the current payload:
let payload = {
data: {
title: 'Items list',
message: `Added: ${event.data.val().itemName} [${event.data.val().itemNumber}]`,
style: 'inbox',
summaryText: 'There are %n% notifications'
}
};
Where "style" property makes Ionic stack the notifications.
If you don't use "style" property, each new notification will replace the previous one.
If you use "notification" property instead of "data" it will create new notification in the notifications shade for each push.
Also note that you can add collapseKey option to your requestto show only the latest message to your user if messages were not arrive yet. You can do it like that:
const options = {
collapseKey: 'sl_update'
};
admin.messaging().sendToDevice(tokens, payload, options);
I hope this will help someone.
For more info see https://github.com/phonegap/phonegap-plugin-push/blob/master/docs/PAYLOAD.md#stacking