I have set up the Ionic/Capacitor app to receive push notifications following the capacitor tutorial,
I went through all the tutorial successfully and I receive test notifications sent from FCM both in foreground and background
I can successfully register to a topic I can receive notifications sent to the topic I can receive notifications sent to the token (test mode)
Now I'm trying to send notifications from a different device, I just created a two test button to send notification in multicast to an array of tokens and another button to send notification to a given topic
In both cases from my device I receive the notifications in foreground, but not in background
I believe is something wrong with the format I'm using to send the notifications that is not correct in case of background (I can receive those from the FCM test tool)
Client
const send = functions.httpsCallable('sendPushNotificationToUsers');
const sendToTopic = functions.httpsCallable('sendPushNotificationToTopic');
const sendNotification = useCallback(
({
to,
title,
body,
onClick
}) => {
setLoading(true);
send({
to,
title,
body,
onClick
})
.then(() => setSuccess(true))
.catch(() => setError(true))
.finally(() => setLoading(false));
}, [send],
);
const sendNotificationToTopic = useCallback(
({
topic,
title,
body,
onClick
}) => {
setLoading(true);
sendToTopic({
topic,
title,
body,
onClick
})
.then(() => setSuccess(true))
.catch(() => setError(true))
.finally(() => setLoading(false));
}, [sendToTopic],
);
Server / Functions
exports.sendPushNotificationToUsers = functions.https.onCall(
(data, context) => {
if (!context.auth) {
throw new functions.https.HttpsError(
'failed-precondition',
'The function must be called ' + 'while authenticated.',
);
}
db.collection('users_meta')
.doc(data.to)
.collection('messagingTokens')
.get()
.then(messagingTokens => {
if (messagingTokens && messagingTokens.size) {
const to = messagingTokens.docs.map(i => i.data().token);
console.log(to); // I get to this console log and the tokens are printed correctly in an array
admin.messaging().sendMulticast({
title: data.title,
body: data.body,
data: {
title: data.title,
body: data.body,
onClick: data.onClick || '',
},
tokens: to,
});
}
});
},
);
exports.sendPushNotificationToTopic = functions.https.onCall(
(data, context) => {
if (!context.auth) {
throw new functions.https.HttpsError(
'failed-precondition',
'The function must be called ' + 'while authenticated.',
);
}
admin.messaging().send({
data: {
title: data.title,
body: data.body,
onClick: data.onClick || '',
},
topic: data.topic,
});
},
);
Notifications handler
const initNative = useCallback(() => {
PushNotifications.register();
PushNotifications.requestPermission().then(result => {
if (result.granted) {
// Register with Apple / Google to receive push via APNS/FCM
PushNotifications.register();
} else {
// Show some error
}
});
PushNotifications.addListener(
'registration',
(token: PushNotificationToken) => {
const device = new DeviceUUID().get();
registerTokenToUser(device, token.value);
alert('Push registration success, token: ' + token.value);
},
);
PushNotifications.addListener('registrationError', (error: any) => {
alert('Error on registration: ' + JSON.stringify(error));
});
PushNotifications.addListener(
'pushNotificationReceived',
(notification: PushNotification) => {
alert(JSON.stringify(notification));
// this array fires correctly with the app in foreground, but nothing on the notifications tray with the app in background if sent from my send functions, works correctly if sent from FCM
},
);
// Method called when tapping on a notification
PushNotifications.addListener(
'pushNotificationActionPerformed',
(notification: PushNotificationActionPerformed) => {
alert(JSON.stringify(notification));
},
);
}, [PushNotifications, history, registerTokenToUser]);
Any suggestion? Thanks
I've found the error myself, for the notifications be visible in background mode the notification object needs to have "notification" key populated, that was missing in my case,
correct send function should be
exports.sendPushNotificationToUsers = functions.https.onCall(
(data, context) => {
if (!context.auth) {
throw new functions.https.HttpsError(
'failed-precondition',
'The function must be called ' + 'while authenticated.',
);
}
db.collection('users_meta')
.doc(data.to)
.collection('messagingTokens')
.get()
.then(messagingTokens => {
if (messagingTokens && messagingTokens.size) {
const to = messagingTokens.docs.map(i => i.data().token);
console.log(to); // I get to this console log and the tokens are printed correctly in an array
admin.messaging().sendMulticast({
title: data.title,
body: data.body,
notification: {
title: data.title,
body: data.body,
},
data: {
title: data.title,
body: data.body,
onClick: data.onClick || '',
},
tokens: to,
});
}
});
},
);
exports.sendPushNotificationToTopic = functions.https.onCall(
(data, context) => {
if (!context.auth) {
throw new functions.https.HttpsError(
'failed-precondition',
'The function must be called ' + 'while authenticated.',
);
}
admin.messaging().send({
notification: {
title: data.title,
body: data.body,
},
data: {
title: data.title,
body: data.body,
onClick: data.onClick || '',
},
topic: data.topic,
});
},
);