We are using the Firebase function for push notifications. We've directly trigger and scheduled trigger push notifications. For that, we are using the Firebase function with typescript. Since users are getting increase we are using Topic based push notifications. create and subscribe happening from the mobile end like the following:
If the user is already subscribed, I unsubscribe that user and subscribe to the topic that the user has newly chosen.
if (name !== undefined) {
const nameLower = name.toLowerCase()
if (countryName) {
isSubscribe ? await messaging().subscribeToTopic(nameLower) : await messaging().unsubscribeFromTopic(nameLower)
}
}
if (platform) {
isSubscribe ? await messaging().subscribeToTopic(platform) : await messaging().unsubscribeFromTopic(platform)
}
mIds?.forEach(async element => {
if (element) {
isSubscribe ? await messaging().subscribeToTopic(element) : await messaging().unsubscribeFromTopic(element)
}
});
arrIds?.forEach(async element => {
const createTopic = `${element?.tId}-${element?.rId}`
if (createTopic) {
isSubscribe ? await messaging().subscribeToTopic(createTopic) : await messaging().unsubscribeFromTopic(createTopic)
}
});
Above is doing subscribe and unsubscribe when onboarding. Once the user is onboarded, To show foreground notification and to catch click on notification I am having following NotificationCenter.ts
useEffect(() => {
// Showing foreground notification
const unsubscribe = messaging().onMessage((remoteMessage) => {
if (remoteMessage.notification) {
showMessage({
message: remoteMessage.notification.title,
description: remoteMessage.notification.body,
type: "success",
duration: 3000,
statusBarHeight: StatusBar.currentHeight,
onPress: () => {
remoteMessage?.data?.Id && details(remoteMessage?.data?.Id)
},
})
}
})
return () => {
unsubscribe()
}
}, [])
useEffect(() => {
// setting iOS batch count to 0
return notifee.onForegroundEvent(({ type, detail }) => {
switch (type) {
case EventType.PRESS:
notifee.setBadgeCount(0)
detail.notification?.data && details(detail.notification?.data?.Id as string)
break
}
})
}, [])
useEffect(() => {
//Initial notification
messaging()
.getInitialNotification()
.then((remoteMessage) => {
if (remoteMessage) {
remoteMessage.data.Id && details(remoteMessage.data.Id)
}
})
}, [])
useEffect(() => {
//Notification open
messaging().onNotificationOpenedApp((remoteMessage) => {
remoteMessage.data.Id && details(remoteMessage.data.Id)
})
}, [])
const details = (Id: string) => {
// detail function
client.notificationDetails(true)
navigate("detailsScreen", { Id })
}
Then we're using onWrite firebase function event to send notifications(system handle notification) to react native app like the following: (we are using up to 5 conditions. Not using more than 5 conditional expression(OR) due to firebase restriction)
//Making condition dynamically
if (global.length > 0) {
condition = `'${data?.IdString}' in topics`;
} else {
condition = fireb.docs.reduce(
(cnd, data, i) =>
`${cnd}${i > 0 ? ' || ' : ''}'${details?.Id[0]}-${
data.data().refId
}' in topics`,
'',
);
// Example topic 1: "xxxxxxx-xxxxx-<firebase doc id>' in topics || 'xxxxxxx-xxxxx-<firebase doc id>' in topics";
// Example topic 1: "xxxxxxx-xxxxx-<firebase doc id>' in topics
}
const message = {
notification: {
title: `${name} - ${title}`,
body: details?.heading?.body,
},
apns: {
payload: {
aps: {
sound: 'default',
badge: 1,
},
},
},
data: {refId: `${data?.Id}`},
condition: condition, //Dynamically made condition
};
//send topic based push notification
const response = await admin.messaging().send(message);
In the dev and stage environment, we never had any duplicate notifications yet. (there is a small number of users and topics. So not many subscribers). But in prod, we are publishing content to the created topics, and many users are subscribed(1k-10k). Not often but from time to time we are getting duplicated notifications. Today our app got 10 notifications but two notifications get duplicated. One got four duplicates and another got two duplicated. I am checking all logs in the cloud function but it has triggered once and there are no logs that indicate it over-triggered(more than once). I have done many testing but couldn't figure it out. If anyone sees a bug in the above code that make notification duplication, please help us with the answer!!!
Mobile message SDK - "@react-native-firebase/messaging": "^16.4.0"
Node.js Admin SDK - "@google-cloud/tasks": "^3.1.0", "firebase-admin": "^10.0.2", "firebase-functions": "^3.18.0",
Is it a bug in Firebase Admin SDK?