Google Cloud Functions Notifications iOS - ios

I was finishing up an app for somebody but needed some help with the script that I wrote for sending notifications via Cloud Functions for Firebase. Below this text you can find my code:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/Users/{userUid}/').onWrite(event => {
const followerUid = event.params.userUid;
const payload = {
notification: {
title: 'Update Received',
body: 'Please Check Your App',
badge: 1,
sound: 1,
}
};
return admin.database().ref('/Admin/notificationID').once('value').then(allTokens => {
if (allTokens.val()) {
// Listing all tokens.
const tokens = allTokens.value
return admin.messaging().sendToDevice(tokens, payload).then(response => {
});
};
});
});
Mainly there are only 3 issues that I am having. First of all, I am not sure if I am using the correct syntax for specifying the badge. Second of all, I don't know how to specify that I want a sound to be played for the notification. Lastly, I am unable to send the notification because the notificationID that is returned from the database is apparently incorrect even though I have a legible FCM ID stored in my database under /Admin/ with the key notificationID. I would appreciate it if one of you could help me fix these issues and get this app up and running.
Thanks,
KPS

The value for badge needs to be String:
Optional, string
Same in #1, sound value needs to be String:
Optional, string
The sound to play when the device receives the notification.
Sound files can be in the main bundle of the client app or in the Library/Sounds folder of the app's data container. See the iOS Developer Library for more information.
Hard to tell without any additional details. Are you positive that it's a valid registration token? Does it work when you send a message to it using the Firebase Console? If not, is it throwing an error?

Related

how do I debug push notifications for iOS with Firebase

Trying to get my push notifications working on iOS, starting with my own iOS device
I am able to find my token in Angular, send it to my python backend and store it in a database.
If I go to Compose notification in firebase:
https://console.firebase.google.com/project//notification/compose
I'm able to create the campaign and receive my notification on my phone. However if I hit 'Send test message', enter (or check) my FCM token from the database and hit 'Test' There is no result.
So I am doubting my method to receive my token / if the token is correct.
I'm using Angular, and in my service I'm calling:
PushNotifications.addListener('registration', (token: Token) => {
console.log('Push registration success, token: ' + token.value);
this.tokenvalue = token.value
this.LogOn(username, password, this.tokenvalue)
}); }
Its part of my login form, every time someone logs in the token gets retrieved in case its there:
import { PushNotifications, Token } from '#capacitor/push-notifications';
import { Capacitor } from '#capacitor/core';
(....)
onSubmit(): void {
const { username, password } = this.form;
const isPushNotificationsAvailable = Capacitor.isPluginAvailable('PushNotifications');
if (isPushNotificationsAvailable) {
PushNotifications.requestPermissions().then(result => {
if (result.receive === 'granted') {
// Register with Apple / Google to receive push via APNS/FCM
PushNotifications.register();
} else {
this.tokenvalue = ""
this.LogOn(username, password, this.tokenvalue)
}
});
PushNotifications.addListener('registration', (token: Token) => {
console.log('Push registration success, token: ' + token.value);
this.tokenvalue = token.value
this.LogOn(username, password, this.tokenvalue)
}); }
else {
this.tokenvalue = ""
this.LogOn(username, password, this.tokenvalue)
}
}
The actual token I'm now trying looks like this:
5BA41427198D463847....................80585EAFC3C2670226E22C082A
The 20 dots also represent actual characters like the other ones around it. It's 64 characters in total.
Hope you can help me, am I doing something wrong here? Do I miss a setting somewhere?
Fixed it eventually by going through this article:
https://capacitorjs.com/docs/guides/push-notifications-firebase
Lots of steps I already executed, but missed some changes in files available in Xcode. This changed the actual ID what was printed in the angular application to something that looks like this:
dz0yFZnpH0DkvTntwzrlx-:APA91bG................................................................................JYuH0-7yGReyaqQQUyRmObSa0Cld9QxEHYW9bjSaZQV0jNQjDHRSx
A 164 characters token that now worked when adding a test message as described in the question. Also the python part worked perfectly in connection to this. Used this one:
https://medium.com/#smbhuin/push-notification-firebase-python-8a65c47d3020
In Angular itself remarkably, no changes were necessary at all.
Happy to have this - for me - tough challenge behind me

Add deep link when creating Firebase message

I'm using the firebase Message class to create push notifications for a react native app. I want the notification to take users to a specific screen of the app. Right now tapping on the push notification just takes users to the last screen they were on before they back-grounded the app. I'm testing this on my iOS device. How can I embed a specific deep link in the message? Would I use setApnsConfig(ApnsConfig apnsConfig) or setFcmOptions(FcmOptions fcmOptions)?
I would use the APNS config since this is for an iOS app:
https://firebase.google.com/docs/reference/admin/java/reference/com/google/firebase/messaging/ApnsConfig.Builder
You could approach it different ways, but you could either include a URL in the header field, and use it for custom deep link logic, or you can have custom data in the putCustomData(String key, Object value) and then have your app process that info to deep link into the correct part of your app.
Your app would process this notification in the application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623013-application
I had integrated this feature in an app I made in react native aswell. Look at my solution below.
As you can see in the app I am waiting for a notification to come on and I check if it has a type available. My notifications are always routed to another page. In my case its the same page but I set a route as datatype in my payload.
After that you can use that route payload with your naviogator library in my case react-navigation to navigate to the correct screen.
You should chose which trigger works best for you ether onNotificationOpenedApp or getInitialNotification.
useEffect(() => {
// Assume a message-notification contains a "type" property in the data payload of the screen to open
messaging().onNotificationOpenedApp((remoteMessage) => {
console.log(
"Notification caused app to open from background state:",
remoteMessage
);
//navigation.navigate(remoteMessage.data.type);
});
// Check whether an initial notification is available
messaging()
.getInitialNotification()
.then((remoteMessage) => {
if (remoteMessage) {
console.log(
"Notification caused app to open from quit state:",
remoteMessage
);
const route = remoteMessage?.data?.route;
navigation.navigate(route, {
data: remoteMessage.data,
});
}
})
.catch((error) => console.log("Caught ", error));
}, []);

Firebase Cloud Messaging to Android works but iOS fails. How to structure payload for iOS?

I can send test notifications from Firebase console to my app both on iOS and Android. Therefore, my app is set up properly to receive push notifications on both platforms. However, when I use a cloud function to send notifications. Only, notifications on the Android device are received. No notifications show up on the iOS device. I suspect this may be related to the way that I create the payload in my cloud function. Maybe I am missing something for iOS. If you could give me some tips, that would be great.
I checked if the deviceToken for the iOS device is correct and it was correct.
I sent a test message using firebase console to the same deviceToken for the iOS device and the notification was delivered.
Therefore, I concluded my problem may arise from the cloud function I wrote. Thus, I share below the cloud function:
exports.notifToApp = functions.database.
ref(`/memInfo/{memId}/notifChoice/`).onWrite((snap, context) => {
//send only if exists and new notification OR if doesn't exist
if ((snap.before.exists() && (snap.after.val() !== snap.before.val())) || !snap.before.exists()) {
//get notification body
const notificationTitle = snap.after.val().memName;
const notificationText = snap.after.val().notifText;
//get and loop over notification subscribers
return admin.database().ref(`/notifics/${context.params.memId}/notifSubs/`).once("value", subs => {
if (subs.exists()) {
return subs.forEach(sub => {
//payload for notification
const payload = {
"notification":{
"title": notificationTitle,
"body": notificationText,
"sound": "default",
"click-action": "FCM_PLUGIN_ACTIVITY",
"priority": "high"
}
}
//deliver notification
return admin.messaging().sendToDevice(sub.val().deviceToken, payload).catch(e => {console.log(e);});
});
} else { //end: if returned any value
return 0;
}
});// end: get and loop over notification subscribers
} else { //end: send only if exists and new notification OR if doesn't exist
return 0;
}
});
I do not get any error messages. Function completes successfully with status "OK."
I test using two devices: one android and one iOS. Both device tokens are saved correctly in the database for the cloud function to retrieve and use for sending messages.
I see the notification on the Android device running my app. I wish the notification to show up on the iOS device running the same app.
Test message notification sent from the firebase console shows up on both devices correctly.
I realized that sendToDevice() used the legacy version of payload. I used send() in my function to use the newer version. (see answer: stackoverflow)
admin.messaging().send(payload).catch(e => console.log(e));
I changed the payload to include platform specific fields according to the latest guidelines (see firebase docs)
const payload = {
"token": sub.val().deviceToken,
"notification":{"title": notificationTitle,"body": notificationText},
"android": {"notification": {"sound": "default"}},
"apns": {"payload": {"aps": {"sound": "default"}}}
};
Now it works on both platforms.

Old message is not removing in iPhone notification try

I am using push plugin in ionic 3 app, everything is working fine but from my server end we are sending one message at a time and im receiving message to iPhone, but old message should overwrite with new message or once we receive new message then old message is clear automatically..
I'm not able to find anything related to this, please anybody help me to solve this.
const options: PushOptions = {
android: {},
ios: {
alert: 'true',
badge: true,
sound: 'false'
},
windows: {},
browser: {
pushServiceURL: 'http://push.api.phonegap.com/v1/push'
}
};
const pushObject: PushObject = this.push.init(options);
pushObject.on('notification').subscribe((notification: any) =>
console.log('Received a notification', notification));
It sounds like you aren't sending your messages configured to be "collapsible". By default each message will be distinct, not overwriting the last message. FCM documents this well:
https://firebase.google.com/docs/cloud-messaging/concept-options
Non-collapsible and collapsible messages
A non-collapsible message
denotes that each individual message is delivered to the device. A
non-collapsible message delivers some useful content, as opposed to a
collapsible message like a content-free "ping" to the mobile app to
contact the server to fetch data.
...
A collapsible message is a message that may be replaced by a new message if it has yet to be delivered to the device.
...
Or if you are not using FCM, here's a reference to Apple's APN docs directly.
To allow the coalescing of similar notifications, you can include a
collapse identifier within a notification request. Normally, when a
device is online, each notification request that you send to APNs
results in a notification delivered to the device. However, when the
apns-collapse-id key is present in your HTTP/2 request header, APNs
coalesces requests whose value for that key is the same. For example,
a news service that sends the same headline twice could use the same
collapse identifier value for both requests. APNs would then coalesce
the two requests into a single notification for delivery to the
device. For details on the apns-collapse-id key
Update with some code details:
public void sendMessage(String title, String body, Map<String, String> data, boolean shouldCollapse) {
PlatformConfiguration platformConfig = new PlatformConfiguration(30);
if (shouldCollapse)
messageBuilder.setAndroidConfig(platformConfig.getCollapsibleAndroidConfig("test")).setApnsConfig(platformConfig.getCollapsibleApnsConfig("test"));
...
public ApnsConfig getCollapsibleApnsConfig(String collapseKey) {
return getCoreApnsConfig().putHeader("apns-collapse-id", collapseKey)
.setAps(getNonCollapsibleApsBuilder().setCategory(collapseKey).setThreadId(collapseKey).build()).build();
}
public AndroidConfig getCollapsibleAndroidConfig(String collapseKey) {
return getCoreAndroidConfig().setCollapseKey(collapseKey)
.setNotification(
getNonCollapsibleAndroidNotificationBuilder().setTag(collapseKey).build()).build();
}

How can I set notification sound when app is not running in React-Native firebase

I'm trying to make notification ringing when app is not running in IOS.
Here is my code.
this.notificationListener = firebase.notifications().onNotification((notification: Notification) => {
// SET SYSTEM DEFAULT SOUND!
notification.setSound("default");
firebase.notifications().displayNotification(notification);
});
When app is in background or foreground ( Maybe I can say 'app is running'), notification rings well.
Should I need to use other listener?
Or should I need to add my own sound file for ringing?
Finally, I know how to do this.
This issue was not related to react-native-firebase, it was related to my server.
When server post message to app, server can set several options like sound, badge.
https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW1
If you set sound section to 'default', you can get default notification sound when notification is coming even if your app is on background.
I hope my answer can help react-native-firebase beginners like me.
Anyone Has issue with RNFIREBASE & REACT NATIVE, Try to send your notification via Firebase ADMIN SDK. That will work for Sure
//Notification Payload
const payload = {
notification: {
title: update.title,
body: update.body,
icon: "default",
badge: '1',
sound: 'default' // notification sound
},
};
//sending notification via Firebase Admin SDK
admin.messaging().sendToDevice('TOKEN_OR_TOKENS', payload)
.then( () => { return true; }).catch(function() {
console.log('error sendToDevice() ')
return null;
});

Resources