react-native-firebase: onNotificationOpenedApp and getInitialNotification not working on iOS - ios

I'm using Cloud Messaging from react-native-firebase 7.0.1.
I do not want to store iOS device tokens in firebase, so I'm using getAPNSToken() method and then storing it on my backend.
I'm able to send notification on a device and after pressing it, the application opens.
But when I'm trying to get message from getInitialNotification() or onNotificationOpenedApp() it always returns null/undefined.
It works every time on Android.
PushHandler.js
import React from 'react';
import messaging from '#react-native-firebase/messaging';
export default class PushHandler extends React.Component {
constructor(props) {
super(props);
this.messageApp = messaging();
}
componentDidMount() {
this.messageApp.onNotificationOpenedApp(remoteMessage => {
if (remoteMessage) { // <- always null on iOS
// handle notification
}
});
this.messageApp.getInitialNotification().then(initialMessage => {
if (initialMessage) { // <- always undefined on iOS
// handle notification
}
});
}
render() {
return null;
}
}

Just realized that according to the docs, these functions only work when sending and receiving notifications via FCM, which is why you aren't seeing these work when sending them manually through APNS.
This package will allow for leverage getInitialNotification and the other function: https://github.com/react-native-community/push-notification-ios

It used to work before. I mean, for the RNFirebase 5.x.x versions.
For some reason, the maintainers of the library decided to only send those events up to the JS layer when it's a Firebase Cloud Message coming through.
Here is the IF statement:
https://github.com/invertase/react-native-firebase/blob/master/packages/messaging/ios/RNFBMessaging/RNFBMessaging%2BUNUserNotificationCenter.m#L89
I removed the IF statement it seems to be working as before.
But yeah, that's the new behavior of the RN-Firebase library.

Related

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.

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;
});

Twitter crashes after Tweet

I'm using:
window.open(`twitter://post?text=${caption}`, "_system");
to post tweets from my Ionic 2 app.
This successfully opens the app and creates the tweet.
After the post the twitter just crashes and my app crashes too.
I could get this log from Android Studio:
https://www.dropbox.com/s/o1d9cr6htug4ai6/Screenshot%202017-01-26%2018.05.09.png?dl=0
This happens both with Android and iOS phones.
Anyone has seen this issue?
Thanks
Why not use InAppBrowser ?
import {InAppBrowser} from 'ionic-native';
...
let browser = new InAppBrowser('https://ionic.io', '_system');
But the better solution you want is ionic built in social sharing plugin
import { SocialSharing } from 'ionic-native';
// Check if sharing via email is supported
SocialSharing.canShareViaEmail().then(() => {
// Sharing via email is possible
}).catch(() => {
// Sharing via email is not possible
});
// Share via email
SocialSharing.shareViaTwitter(message, image, url).then(() => {
// Success!
}).catch(() => {
// Error!
});

Pushplugin- Unable to register the device (IOS)

I am using Phonegap Pushplugin for my push notifications. Added logs in both methods. didRegisterForRemoteNotificationsWithDeviceToken method never got executed. It is not even failing on didFailToRegisterForRemoteNotificationsWithError. Not sure what is the issue here.
I uploaded IOS distribution certificate (Not APN) to steroids build service and uploaded APN Prod profile to AdHoc build. I am getting the prompt for push notifications and I can see that notifications are enabled for my app. Issue is, I am not getting the token.
Looked at the following link for debugging steps
Plugin link
I am using the following code for registration.
function registerDevice(){
var pushNotification = window.plugins.pushNotification;
pushNotification.register(
tokenHandler,
errorHandler, {
"badge":"true",
"sound":"true",
"alert":"true",
"ecb":"onNotificationAPN"
});
}
var onNotificationAPN = function(event) {
var pushNotification = window.plugins.pushNotification;
if ( event.alert )
{
navigator.notification.alert(event.alert);
}
if ( event.sound )
{
var snd = new Media(event.sound);
snd.play();
}
if ( event.badge )
{
pushNotification.setApplicationIconBadgeNumber(successHandler, errorHandler,
event.badge);
}
}
function tokenHandler (result) {
steroids.logger.log("Tokenhandler called with result");
steroids.logger.log(result);
alert(result);
}
function errorHandler (error) {
steroids.logger.log("errorHandler called with result");
steroids.logger.log(error);
alert('error = ' + error);
}
Any help is appreciated.
Update- 07/30/14
I downloaded PersistentConnectionLogging.mobilecondig and I was able see the generated token. I was able to send a notification to my phone using this token.
tokenHandler and onNotificationAPN still not getting fired. Issue is clearly on Cordova side or in my Javascript.
Is this plugin even working on Cordova 3.1/3.5 ? It is frustrating that there is no community support on this plugin.
Any ideas.
Here's how i'm implementing push notifications:
Handle the certificates. Tutorial
Register and get the token. Tutorial
Store the token using NSUserDefaults.
Create a custom plugin and pass the token from objective-c to javascript by creating a custom plugin using a JS bridge. Tutorial

Resources