Closed aslanon closed 4 years ago
@bsonmez deleted the app and reinstalled again, what could change? The token I think. You may be addressing the old token.
Hey Mike. Thank you for the fast reply!
I'm 100% sure that I am replacing the newest token every time. I can see in the logs that I receive remote messages when the app in the foreground. When it goes in the background the notification is not triggered.
I apologize that I can't find the link but there's a great video on troubleshooting the cloud message delivery from the main video guy in all the firebase developer videos. My best pointer is to watch (or re-watch that) and my vague/weak pointer is that between foreground and background it's possible that one is using FCM direct and one is APNS and, maybe the one using APNS isn't setting the right priority to get through and wake the app up. Or maybe APNS is throttling you. Nothing concrete unfortunately, sorry
I apologize that I can't find the link but there's a great video on troubleshooting the cloud message delivery from the main video guy in all the firebase developer videos. My best pointer is to watch (or re-watch that) and my vague/weak pointer is that between foreground and background it's possible that one is using FCM direct and one is APNS and, maybe the one using APNS isn't setting the right priority to get through and wake the app up. Or maybe APNS is throttling you. Nothing concrete unfortunately, sorry
It also happens in Android as well.*
What do you think I'm missing? Or Could this be a bug? I think I'm not the only one who has experienced this issue.
*Edit. Sorry while quoting the previous part of the message's gone.
I honestly don't know. The Invertase crew just went through all of this while integrating Notifee and it all works. But it's not easy. And on iOS it's flaky because of the aforementioned APNS throttle issues etc. It's just not an easy area.
@bockc Everything mentioned in the rnfirebase.io docs is possible, and we got them working whilst reworking the messaging module. iOS can run JS code in the background (totally different from how Android works), it's something we had working. What are you doing to actually check it runs code in the background? I've seen users doing console logs - this wont work.
That being said, it was very painful. If we sent too many messages we'd get blocked by the device for a few hours and everything would just stop working - how can you document that?
For example, @Salakar was testing on an old iPhone (5s maybe?) whilst I was on a iPhone 7 - everything worked on both of them, but the older iPhone also experienced more frequent blocking of messages due to system resource issues.
What we didn't understand was that even on the latest iPhone/iPad with nothing installed, it still happened. Incredibly infuriating.
@bsonmez
I think there is no stability. It was working without making any changes before. But it doesn't work since I deleted the app and installed it again. I couldn't understand the reason.
Yep, it's not fun & there is practically nothing on Apple docs/forums to help :/
@Ehesp thinking about, simply having a page where you document that experience - while it's fresh in your mind with as many of those anecdotes as you can remember, is tremendously valuable as an external observer like myself - even after doing this for a year! I didn't know console.log didn't work in background for instance. And the obvious subtlety on background throttling between devices, showing how minor device differences affect it even. You're right that doesn't exist anywhere and simply a bloggy chronicle of it linked into the docs would avert an unbelievable (or totally believable maybe) volume of issues comments and new issues
@bsonmez as mentioned above; if it was working before and now it isn't without any changes made then it's most likely your device throttling the messages.
I posted a small guide above on how to see these being throttled using the Console
app on your Mac. Let me know your findings.
I previously summarised all the working scenarios here: https://github.com/invertase/react-native-firebase/issues/3367#issuecomment-607368063 - and as you can see they are all working, though subject to throttling, with older devices (e.g. my 5s) getting what appears to be random throttling (with no given reason) - of which we can't do anything about 🙈
The throttling scenarios that I know of:
Console
appI previously had this working on a device (foreground & background notifications) and then it suddenly appeared to stop working, and I could not see the granted permission in the iOS system settings - as mentioned by othrs above.
Make sure you are requesting permissions correctly. That was the issue for me. When I migrated from v5 to v6 my
hasPermission
check broke because now it returns a number (-1, 0, or 1) instead of a boolean to signify the permission status.
Resolved it for me. Explicitly checking for 1
, rather than a boolean check fixed the issue.
I solved like this. Before I was calling registerDeviceForRemoteMessages()
in main a component. I moved it to index.js and now it is working.
package.json
"@react-native-firebase/app": "^6.7.1",
"@react-native-firebase/messaging": "^6.7.1",
index.js
import 'react-native-gesture-handler';
import React, { useEffect } from 'react'
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
import messaging from '@react-native-firebase/messaging';
messaging().setBackgroundMessageHandler(remoteMessage => {
console.log('Message handled in the background!', remoteMessage);
});
function HeadlessCheck({isHeadless}) {
useEffect(
React.useCallback(()=>{
(async()=>{
console.log("registration", await messaging().registerDeviceForRemoteMessages());
})()
})
)
if (isHeadless) {
// App has been launched in the background by iOS, ignore
return null;
}
return <App />;
}
AppRegistry.registerComponent(appName, () => HeadlessCheck);
Can you show some code of how you request permission? If that's fixed your problems then the docs need updating.
Hey, I am having the same issue, we had it working perfectly yesterday, we made no changes to the notification code and it stopped working today. This is quite frustrating and is currently holding back the release of our app. I am not sure how to proceed without stable notifications. I am happy to provide any information that is needed and will respond to emails if I can.
@thehappydinoa see my comment above: https://github.com/invertase/react-native-firebase/issues/3367#issuecomment-624104860
I will try to explain every thing. My code was working perfect last week and today it wasn't. I spent too much effort to solve it. And finally I combined some thing I found and it worked. I don't know all is necessary or not but this way is working. Yes, it is time to explain.
First to make it together I will add the code from my previous post.
package.json
...
"@react-native-firebase/app": "^6.7.1",
"@react-native-firebase/messaging": "^6.7.1",
....
index.js
import 'react-native-gesture-handler';
import React, { useEffect } from 'react'
import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
import messaging from '@react-native-firebase/messaging';
messaging().setBackgroundMessageHandler(remoteMessage => {
console.log('Message handled in the background!', remoteMessage);
});
function HeadlessCheck({isHeadless}) {
useEffect(
React.useCallback(()=>{
(async()=>{
console.log("registration", await messaging().registerDeviceForRemoteMessages());
})()
})
)
if (isHeadless) {
// App has been launched in the background by iOS, ignore
return null;
}
return <App />;
}
AppRegistry.registerComponent(appName, () => HeadlessCheck);
AppDelegate.m.
...
#import <UserNotifications/UserNotifications.h>
#import <Firebase.h>
#import <FirebaseInstanceID/FirebaseInstanceID.h>
#import <FirebaseMessaging.h>
...
...
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
//I ADDED BELOW CODE
// Use Firebase library to configure APIs
[FIRApp configure];
if ([UNUserNotificationCenter class] != nil) {
// iOS 10 or later
// For iOS 10 display notification (sent via APNS)
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert |
UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
[[UNUserNotificationCenter currentNotificationCenter]
requestAuthorizationWithOptions:authOptions
completionHandler:^(BOOL granted, NSError * _Nullable error) {
// …
}];
} else {
// iOS 10 notifications aren’t available; fall back to iOS 8–9 notifications.
UIUserNotificationType allNotificationTypes =
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[application registerUserNotificationSettings:settings];
}
[application registerForRemoteNotifications];
[FIRMessaging messaging].delegate = self;
[[FIRInstanceID instanceID] instanceIDWithHandler:^(FIRInstanceIDResult * _Nullable result,
NSError * _Nullable error) {
if (error != nil) {
NSLog(@"Error fetching remote instance ID: %@", error);
} else {
NSLog(@"Remote instance ID token: %@", result.token);
NSString* message =
[NSString stringWithFormat:@"Remote InstanceID token: %@", result.token];
}
}];
[FIRMessaging messaging].autoInitEnabled = YES;
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
NSLog(@"FCM registration token: %@", fcmToken);
// Notify about received token.
NSDictionary *dataDict = [NSDictionary dictionaryWithObject:fcmToken forKey:@"token"];
[[NSNotificationCenter defaultCenter] postNotificationName:
@"FCMToken" object:nil userInfo:dataDict];
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
// With “FirebaseAppDelegateProxyEnabled”: NO
- (void)application:(UIApplication *)application
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[FIRMessaging messaging].APNSToken = deviceToken;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
//Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
}
@end
App.tsx
export default function App() {
useEffect(() => {
// Assume a message-notification contains a "type" property in the data payload of the screen to open
messaging().onMessage(async remoteMessage => {
console.log("Message received when application in show",remoteMessage)
});
messaging().onNotificationOpenedApp(remoteMessage => {
console.log(
'Notification caused app to open from background state:',
remoteMessage.notification,
);
});
// Check whether an initial notification is available
messaging()
.getInitialNotification()
.then(remoteMessage => {
if (remoteMessage) {
console.log(
'Notification caused app to open from quit state:',
remoteMessage.notification,
);
}
});
}, []);
return (
<React.Fragment>
<StatusBar backgroundColor="#F0F5F9" barStyle='dark-content' />
<Navigation />
</React.Fragment>
);
}
And the last, In one component, for me it is Home.tsx and it is a functional component. In Class component I guess you can use componentDidMount
fucntion instead of useEffect
function
export function Home(){
/*
State definitions here.
*/
.....
const getFCMToken = async () => {
try {
const authorized = await messaging().hasPermission();
const fcmToken = await getToken();
if (authorized) return fcmToken;
await messaging().requestPermission();
return fcmToken;
} catch (error) {
console.log(error);
}
};
const registerAppWithFCM = async () => {
let fcmToken: any = await Services.getData('fcmToken') //READING FROM ASYNC STORAGE
if (fcmToken.result === undefined) {
console.log("registration", await messaging().registerDeviceForRemoteMessages());
}
}
const getToken = async () => {
try {
const token = await messaging().getToken();
console.warn("taken token", token)
if (token) return token;
} catch (error) {
console.log(error);
}
};
useEffect(
React.useCallback(()=>{
(async()=>{
let fcmToken = await getFCMToken()
await Services.storeData("fcmToken", fcmToken) //WRITING TO ASYNC STORAGE
// HERE, I AM SENDING TO BACKEND SERVICE TO MATCH WITH DEVICE ID AND TOKEN IN MY DATABASE.
})()
registerAppWithFCM()
})
)
}
In Home.tsx
I am asking for permission directly. If you want, you can call getFCMToken()
funtion in an event e.g. onPress()
of Button
.
I wish it is helpful. As I said I am not sure all above is necessary but It is working.
@yusufozcan I tried using that code exactly and it did not work. Do you have any other suggestions?
@Salakar I tried that and received logs, but nothing related to notifications, besides granting them permissions. What would next steps look like?
I was able to get background and foreground notifications working using the following code in my AppDelegate.m
:
#import <UserNotifications/UserNotifications.h>
#import <Firebase.h>
#import <FirebaseInstanceID/FirebaseInstanceID.h>
#import <FirebaseMessaging.h>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([FIRApp defaultApp] == nil) {
[FIRApp configure];
}
if ([UNUserNotificationCenter class] != nil) {
// iOS 10 or later
// For iOS 10 display notification (sent via APNS)
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert |
UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
[[UNUserNotificationCenter currentNotificationCenter]
requestAuthorizationWithOptions:authOptions
completionHandler:^(BOOL granted, NSError * _Nullable error) {
// …
}];
} else {
// iOS 10 notifications aren’t available; fall back to iOS 8–9 notifications.
UIUserNotificationType allNotificationTypes =
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[application registerUserNotificationSettings:settings];
}
[application registerForRemoteNotifications];
[FIRMessaging messaging].delegate = self;
[[FIRInstanceID instanceID] instanceIDWithHandler:^(FIRInstanceIDResult * _Nullable result,
NSError * _Nullable error) {
if (error != nil) {
NSLog(@"Error fetching remote instance ID: %@", error);
} else {
NSLog(@"Remote instance ID token: %@", result.token);
NSString* message = [NSString stringWithFormat:@"Remote InstanceID token: %@", result.token];
}
}
];
[FIRMessaging messaging].autoInitEnabled = YES;
...
}
- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
NSLog(@"FCM registration token: %@", fcmToken);
NSDictionary *dataDict = [NSDictionary dictionaryWithObject:fcmToken forKey:@"token"];
[[NSNotificationCenter defaultCenter] postNotificationName: @"FCMToken" object:nil userInfo:dataDict];
}
/Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
}
I also removed FirebaseAppDelegateProxyEnabled: YES
from my Info.plist
@yusufozcan Thank you! It worked by changing only AppDelegate.m
as you mentioned.
That's super weird if that's working for you, that's what the messaging module should be doing.
I'd be careful just pasting native code into your own delegates, that looks like it's been copied and pasted from somewhere different and may cause other issues.
We'd like to get things working without you needing to do that, because it shouldn't be needed.
@thehappydinoa @bsonmez @yusufozcan Would any of you be able to share the full project with us? There must be something else iOS specific causing it not to work for you which we could look for. We'd love to nail why so others dont have these issues.
This code works for me. It's slightly edited to what was in the documentation to include an explicit check for the permission status. It's using redux-saga
, but if it's helpful to you I can share a version with async / await
.
import { call, take, fork } from 'redux-saga/effects';
import { eventChannel } from 'redux-saga';
import AsyncStorage from '@react-native-community/async-storage';
import messaging from '@react-native-firebase/messaging';
import { Alert } from 'react-native';
// On Android, you do not need to request user permission. This method
// can still be called on Android devices; however, and will always
// resolve successfully.
function* checkPermissions() {
const status = yield call([messaging(), messaging().hasPermission]);
switch (status) {
case messaging.AuthorizationStatus.NOT_DETERMINED:
case messaging.AuthorizationStatus.DENIED: {
console.log('User has notification permissions disabled');
yield call(requestPermission);
break;
}
case messaging.AuthorizationStatus.AUTHORIZED: {
console.log('User has notification permissions enabled.');
yield call(getToken);
break;
}
case messaging.AuthorizationStatus.PROVISIONAL: {
// The app is currently authorized to post non-interrupting user notifications
// platform ios iOS >= 12 only
console.log('User has provisional notification permissions.');
break;
}
default: {
// TODO: Handle
break;
}
}
}
function* getToken() {
let fcmToken = yield call(
[AsyncStorage, AsyncStorage.getItem],
'@mxvue:fcmToken',
);
if (!fcmToken) {
fcmToken = yield call([messaging(), messaging().getToken]);
if (fcmToken) {
// user has a device token
yield call(
[AsyncStorage, AsyncStorage.setItem],
'@mxvue:fcmToken',
fcmToken,
);
}
}
console.log('fcmToken', fcmToken);
}
// Triggers a native permission dialog requesting the user's permission
// On Android, you do not need to request user permission. This method
// can still be called on Android devices; however, and will always
// resolve successfully.
function* requestPermission() {
const status = yield call([messaging(), messaging().requestPermission]);
switch (status) {
case messaging.AuthorizationStatus.NOT_DETERMINED:
case messaging.AuthorizationStatus.DENIED: {
console.log('User has notification permissions disabled');
break;
}
case messaging.AuthorizationStatus.AUTHORIZED: {
console.log('User has notification permissions enabled.');
yield call(getToken);
break;
}
case messaging.AuthorizationStatus.PROVISIONAL: {
// The app is currently authorized to post non-interrupting user notifications
// platform ios iOS >= 12 only
console.log('User has provisional notification permissions.');
break;
}
default: {
// TODO: Handle
break;
}
}
}
function createFirebaseNotificationsChannel() {
return eventChannel(emit => {
const unsubscribe = messaging().onMessage(async remoteMessage =>
emit(remoteMessage),
);
return unsubscribe;
});
}
function* watchForFirebaseNotifications() {
const firebaseNotificationsChannel = yield call(
createFirebaseNotificationsChannel,
);
while (true) {
const remoteMessage = yield take(firebaseNotificationsChannel);
// TODO: Handle messages and present on the UI
console.log('NOTIFICATION:', remoteMessage);
Alert.alert('A new FCM message arrived!', JSON.stringify(remoteMessage));
}
}
function* notificationsSaga() {
yield fork(watchForFirebaseNotifications);
yield call(checkPermissions);
}
export default notificationsSaga;
Also, using the above code I did not have to make any modifications to the project such as changing the AppDelegate.m
- everything worked following the documentation.
Can u show me a example project in git!! I'm trying use It but, dont show :(
@thehappydinoa @bsonmez @yusufozcan Would any of you be able to share the full project with us? There must be something else iOS specific causing it not to work for you which we could look for. We'd love to nail why so others dont have these issues.
@Ehesp Hey Elliot. I guess I'm not allowed to share the full project, but I'd like to give information on my side. I can say that everything is the same as documentation except AppDelegate.m
. I updated it as @yusufozcan suggested and also there is one only extra FBSDK. The rest of the file is the same.
Another weird point was when I applied AppDelegate.m
the solution, I started receiving the notifications immediately and there was no setBackgroundMessageHandler function implemented yet. However, the app was giving a yellow box warning. Then I implemented it as @yusufozcan mentioned in index.js
and stopped giving the warning and started working how it suppose to work.
If you need more information, I'd like to share.
@Ehesp Hey Elliot. I guess I'm not allowed to share the full project, but I'd like to give information on my side. I can say that everything is the same as documentation except AppDelegate.m. I updated it as @yusufozcan suggested and also there is one only extra FBSDK. The rest of the file is the same.
We're thinking it's more of a project problem than actual code, e.g. some project setting disabled which is preventing things from working.
Is it not possible at all to share it? We'd even be fine signing an NDA or something to try and get this solved, or even screenshare. There's all sorts of settings which iOS can apply to break things (e.g. disabling Swizzling).
Another weird point was when I applied AppDelegate.m the solution, I started receiving the notifications immediately and there was no setBackgroundMessageHandler function implemented yet.
setBackgroundMessageHandler
doesn't need to be in place for notification to show, or at least it shouldn't need to be.
@thehappydinoa @bsonmez @yusufozcan Would any of you be able to share the full project with us? There must be something else iOS specific causing it not to work for you which we could look for. We'd love to nail why so others dont have these issues.
I already shared all the codes related with firebase notifications. I can't share all the project because it is belongs to one client of me.
I tried everything in there comments, but I can't receive message from background process.
Hi guys, I'm having also trouble with Notification. On my Simulator everything works fine, but on a real device I'm always get an error.
My Backend Server responds for real Devices.
registration-token-not-registered
Yes I am registering the device. Funny thing here:
"registerDeviceForRemoteMessages" not found But the deprecated function works ..
"@react-native-firebase/app": "^6.7.1", "@react-native-firebase/messaging": "^6.7.1",
I will follow this Issue and try the change of the AppDelegate.m
I've tried many kind of changes to AppDelegate.m and I still can't receive background notification (Foreground was fine). But setting FirebaseAppDelegateProxyEnabled to YES really solved the issue although I see ppl saying that shouldn't be necessary O.O
I still can't receive notifications in the background.
I've tried many kind of changes to AppDelegate.m and I still can't receive background notification (Foreground was fine). But setting FirebaseAppDelegateProxyEnabled to YES really solved the issue although I see ppl saying that shouldn't be necessary O.O
I confirm this has worked with me after adding FirebaseAppDelegateProxyEnabled
with YES.
why is that? and what kind of difference does it make now, when its set to True?
I've tried many kind of changes to AppDelegate.m and I still can't receive background notification (Foreground was fine). But setting FirebaseAppDelegateProxyEnabled to YES really solved the issue although I see ppl saying that shouldn't be necessary O.O
I confirm this has worked with me after adding
FirebaseAppDelegateProxyEnabled
with YES. why is that? and what kind of difference does it make now, when its set to True?
in what part you add FirebaseAppDelegateProxyEnabled
with YES.?
can you show a example?
@ccanalesb You add it in info.plist
Okay y'all, I got it working. I did not add any FirebaseAppDelegateProxyEnabled
to my Info.plist
I followed Google's Guide on setting up notifictions and receiving notifictions. Here is my working AppDelegate.m
(Check the "I added" comments for the important code):
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
// We use these, but you don't have to.
#import "RNBootSplash.h"
#import <CodePush/CodePush.h>
// Start I added
#import <RNCPushNotificationIOS.h>
#import <UserNotifications/UNUserNotificationCenter.h>
@import Firebase;
// End I added
#if DEBUG
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
static void InitializeFlipper(UIApplication *application) {
FlipperClient *client = [FlipperClient sharedClient];
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
[client addPlugin:[FlipperKitReactPlugin new]];
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
[client start];
}
#endif
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#if DEBUG
InitializeFlipper(application);
#endif
// Start I added
[FIRApp configure];
if ([UNUserNotificationCenter class] != nil) {
// iOS 10 or later
// For iOS 10 display notification (sent via APNS)
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert |
UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
[[UNUserNotificationCenter currentNotificationCenter]
requestAuthorizationWithOptions:authOptions
completionHandler:^(BOOL granted, NSError * _Nullable error) {
// ...
}];
} else {
// iOS 10 notifications aren't available; fall back to iOS 8-9 notifications.
UIUserNotificationType allNotificationTypes =
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[application registerUserNotificationSettings:settings];
}
[application registerForRemoteNotifications];
[FIRMessaging messaging].delegate = self;
[[FIRInstanceID instanceID] instanceIDWithHandler:^(FIRInstanceIDResult * _Nullable result,
NSError * _Nullable error) {
if (error != nil) {
NSLog(@"Error fetching remote instance ID: %@", error);
} else {
NSLog(@"Remote instance ID token: %@", result.token);
}
}];
[FIRMessaging messaging].autoInitEnabled = YES;
// End I added
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"appname"
initialProperties:nil];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
[RNBootSplash initWithStoryboard:@"BootSplash" rootView:rootView];
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
// Start I added
- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
NSLog(@"FCM registration token: %@", fcmToken);
// Notify about received token.
NSDictionary *dataDict = [NSDictionary dictionaryWithObject:fcmToken forKey:@"token"];
[[NSNotificationCenter defaultCenter] postNotificationName:
@"FCMToken" object:nil userInfo:dataDict];
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[FIRMessaging messaging].APNSToken = deviceToken;
[RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
[RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings];
}
// Required for the notification event. You must call the completion handler after handling the remote notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
[[FIRMessaging messaging] appDidReceiveMessage:userInfo];
[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
// Required for the registrationError event.
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
[RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
}
// Required for the localNotification event.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
[RNCPushNotificationIOS didReceiveLocalNotification:notification];
}
// Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
NSDictionary *userInfo = notification.request.content.userInfo;
[[FIRMessaging messaging] appDidReceiveMessage:userInfo];
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
}
// End I added
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
return [CodePush bundleURL];
#endif
}
@end
For anyone still having troubles: delete pods
folder and podfile.lock
. After fresh install everything works fine without any changes in appDelegate.m
and info.plist.
Okay y'all, I got it working. I did not add any
FirebaseAppDelegateProxyEnabled
to myInfo.plist
I followed Google's Guide on setting up notifictions and receiving notifictions. Here is my workingAppDelegate.m
(Check the "I added" comments for the important code):#import "AppDelegate.h" #import <React/RCTBridge.h> #import <React/RCTBundleURLProvider.h> #import <React/RCTRootView.h> // We use these, but you don't have to. #import "RNBootSplash.h" #import <CodePush/CodePush.h> // Start I added #import <RNCPushNotificationIOS.h> #import <UserNotifications/UNUserNotificationCenter.h> @import Firebase; // End I added #if DEBUG #import <FlipperKit/FlipperClient.h> #import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h> #import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h> #import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h> #import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h> #import <FlipperKitReactPlugin/FlipperKitReactPlugin.h> static void InitializeFlipper(UIApplication *application) { FlipperClient *client = [FlipperClient sharedClient]; SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults]; [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]]; [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]]; [client addPlugin:[FlipperKitReactPlugin new]]; [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]]; [client start]; } #endif @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { #if DEBUG InitializeFlipper(application); #endif // Start I added [FIRApp configure]; if ([UNUserNotificationCenter class] != nil) { // iOS 10 or later // For iOS 10 display notification (sent via APNS) [UNUserNotificationCenter currentNotificationCenter].delegate = self; UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert | UNAuthorizationOptionSound | UNAuthorizationOptionBadge; [[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:authOptions completionHandler:^(BOOL granted, NSError * _Nullable error) { // ... }]; } else { // iOS 10 notifications aren't available; fall back to iOS 8-9 notifications. UIUserNotificationType allNotificationTypes = (UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge); UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil]; [application registerUserNotificationSettings:settings]; } [application registerForRemoteNotifications]; [FIRMessaging messaging].delegate = self; [[FIRInstanceID instanceID] instanceIDWithHandler:^(FIRInstanceIDResult * _Nullable result, NSError * _Nullable error) { if (error != nil) { NSLog(@"Error fetching remote instance ID: %@", error); } else { NSLog(@"Remote instance ID token: %@", result.token); } }]; [FIRMessaging messaging].autoInitEnabled = YES; // End I added RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"appname" initialProperties:nil]; rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIViewController *rootViewController = [UIViewController new]; rootViewController.view = rootView; [RNBootSplash initWithStoryboard:@"BootSplash" rootView:rootView]; self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; return YES; } // Start I added - (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken { NSLog(@"FCM registration token: %@", fcmToken); // Notify about received token. NSDictionary *dataDict = [NSDictionary dictionaryWithObject:fcmToken forKey:@"token"]; [[NSNotificationCenter defaultCenter] postNotificationName: @"FCMToken" object:nil userInfo:dataDict]; } - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { [FIRMessaging messaging].APNSToken = deviceToken; [RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; } - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { [RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings]; } // Required for the notification event. You must call the completion handler after handling the remote notification. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { [[FIRMessaging messaging] appDidReceiveMessage:userInfo]; [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; } // Required for the registrationError event. - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error]; } // Required for the localNotification event. - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { [RNCPushNotificationIOS didReceiveLocalNotification:notification]; } // Called when a notification is delivered to a foreground app. -(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { NSDictionary *userInfo = notification.request.content.userInfo; [[FIRMessaging messaging] appDidReceiveMessage:userInfo]; completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge); } // End I added - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; #else return [CodePush bundleURL]; #endif } @end
for imports of userNotification block! you used @community based notificaion ios package?
Are there any breaking changes in v.7 of firebase/messaging
?
I was considering upgrading but didn't find any info if it's backward compatible with v.7.
My current version is
"@react-native-firebase/app": "6.4.0-rc4",
@alex-mironov From that version not that I know of - the version you are on was the major thing for messaging because of #3339 (which you're probably aware of or you would not have been on an RC I think and talking about messaging), after that one the bump to v7 was not an actual user-facing breaking change, it was an internal cross-versioning thing as the monorepo transitioned from lockstep versioning to independent versioning. So you shouldn't have any problems.
@mikehardy thank you. Just updated so far so good ✌︎
Tried everything on this thread nothing works. I can still receive foreground messages but background messages don't work.
And those with edited AppDeligate.m file I didn’t see any where in the documentation with that information.
Hi, i resolved this way:
1.- yarn remove @react-native-firebase/messaging 2.- go to ios directory, comment this line in the pod file: // pod 'RNFBMessaging', :path => '../node_modules/@react-native-firebase/messaging' and do "pod install" 3.- Delete the app 4.- Shutdown the device (Apagar dispositivo en español) Sorry my english not good 5.- Turn on the device 6.- Install your app 7.- Send push notification, works for me.
@davidcort may you share your AppDelegate
@davidcort the steps u described are basically removing firebase messaging from the app and deleting it from Podfile
@hishamhadraoui I did not understand you, do you mean that these steps works ?
@030131550542 what I mean is that the steps that he described are basically just removing firebase messaging, I don't think that will work, to be honest. nevertheless, without these steps, it worked for me by deploying the application to Testflight, the remote notification worked for both when quitted or in the background. That didn't work in the simulator only when the app was active, but in Testflight they worked in every state. but I do believe u need to add the APNS certificate that u create in apple into ur main folder of ios
Testing cloud messaging in the simulator is effectively pointless. Only test cloud messaging in real devices.
I still can't get notifications in background mode, in foreground work normal. RN 0.62.2.
It didn't help me:
1) Any manipulations with FirebaseAppDelegateProxyEnabled
;
2) Clear/Reinstall all dependences/Reboot phone
I use package.json
"@react-native-firebase/app": "^7.1.0",
"@react-native-firebase/crashlytics": "^7.1.0",
"@react-native-firebase/messaging": "^7.1.0",
When run pod install
Fabric (1.10.2)
Installing Firebase (6.25.0)
Installing FirebaseAnalytics (6.5.1)
Installing FirebaseAnalyticsInterop (1.5.0)
Installing FirebaseCore (6.7.1)
Installing FirebaseCoreDiagnostics (1.3.0)
Installing FirebaseCoreDiagnosticsInterop (1.2.0)
Installing FirebaseInstallations (1.2.0)
Installing FirebaseInstanceID (4.3.4)
Installing FirebaseMessaging (4.4.1)
Only after updating AppDelegate.m from this comment, resolved my problem. Big thanks @thehappydinoa!
@mikehardy I uploaded .p8 into firebase console. Is it enough for handling certificate. Am I need to create .p12 (development or production) ?
so here it goes, I have been through almost all of the things in the comments above
I was on 7.0.1 before then shifted to 7.1.0 version of firebase packages I even upgraded RN version to 0.62.2 to try a solution provided above had no luck
NOTE! yes, I tested on a real device! asked on the invertase Discord!
EDIT
I uploaded the version to test flight and then sent a notification and it did come in the background too! guess its with apple APNs thingy! I hope it helps!
but still not able to have notifications in the background while testing/debugging! that is a drag
I don't know if it is might be the same error, but I also had the same problem and apparently it has been solved by sending the notification
payload, as it seems the push notification is not being shown on the iOS when it is data only (even with "priority" : "high" and "content_available": true).
I am using these libs below, and now I am able to receive push with the default lib configuration and a real device (12.4.4). On iOS emulator I don't receive them.
"@react-native-firebase/app": "^7.1.0",
"@react-native-firebase/messaging": "^7.1.0",
"@notifee/react-native": "^0.5.1",
Here is what makes my iOS app starts receiving push on Background/Killed state:
POST in: https://fcm.googleapis.com/fcm/send Authorization: key=#Your Firebase project Server key for iOS Content-Type: application/json
{
"priority" : "high",
"content_available": true,
"notification": {
"body" : "notification - body",
"title": "notification - title"
},
"data": {
"body" : "Data - body",
"title": "Data - title"
},
"to": "your device token"
}
With this payload I do not receive any notification on background/killed state:
{
"priority" : "high",
"content_available": true,
"data": {
"body" : "Data - body",
"title": "Data - title"
},
"to": "your device token"
}
Without notification in the payload, the SDK will not show it, no.
Whether it is delivered and/or your app is started with data-only / no-notification depends on if you are being throttled etc (watch the Xcode logs on a real device connected to Xcode
With the notification in the payload the firebase SDK will show the notification but your app won't get a chance to process the data payload until the user clicks.
It's a complicated set of "is this is set, then this happens..." and it's not possible to recommend any given JSON FCM payload as "the solution" because someone else's requirements might be different.
For anyone who struggling this matter, check this out. For me its worked https://github.com/invertase/react-native-firebase/issues/3699#issuecomment-638110794
Issue
Hello, notifications run while the app is on the foregound, but I didn't receive any messages when the app is in the background or killed.
There are a lot of documentation but I can't solve this problem. What am I doing wrong?
Project Files
Javascript
Click To Expand
#### `package.json`: ```json "dependencies": { "@react-native-community/push-notification-ios": "^1.1.0", "@react-native-firebase/app": "^6.4.0-rc4", "@react-native-firebase/messaging": "^6.4.0-rc4", "react": "16.9.0", "react-native": "0.61.5", "react-native-push-notification": "^3.1.9", } ```
iOS
Click To Expand
#### `ios/Podfile`: - [ ] I'm not using Pods - [x] I'm using Pods and my Podfile looks like: ```ruby platform :ios, '10.0' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' target 'Myapp' do # Pods for Myapp pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector" pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec" pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired" pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety" pod 'React', :path => '../node_modules/react-native/' pod 'React-Core', :path => '../node_modules/react-native/' pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules' pod 'React-Core/DevSupport', :path => '../node_modules/react-native/' pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS' pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation' pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob' pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image' pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS' pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network' pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings' pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text' pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration' pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/' pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact' pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi' pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor' pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon" pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon" pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga' pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' pod 'react-native-orientation', :path => '../node_modules/react-native-orientation' target 'MyappTests' do inherit! :search_paths # Pods for testing end use_native_modules! end target 'Myapp-tvOS' do # Pods for Myapp-tvOS target 'Myapp-tvOSTests' do inherit! :search_paths # Pods for testing end end ``` #### `AppDelegate.m`: ```objc /** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #import "AppDelegate.h" #import
#import
#import
#import
#import
#import
#import "Orientation.h"
@implementation AppDelegate
// Required to register for notifications
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
[RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings];
}
// Required for the register event.
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
[RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
// Required for the notification event. You must call the completion handler after handling the remote notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
// Required for the registrationError event.
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
[RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
}
// Required for the localNotification event.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
[RNCPushNotificationIOS didReceiveLocalNotification:notification];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"Myapp"
initialProperties:nil];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[FIRApp configure];
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
return YES;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
@end
```
Environment
Click To Expand
**`react-native info` output:** ``` info Fetching system and libraries information... System: OS: macOS 10.15.1 CPU: (4) x64 Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz Memory: 2.36 GB / 16.00 GB Shell: 5.7.1 - /bin/zsh Binaries: Node: 12.13.0 - /usr/local/bin/node Yarn: 1.19.1 - /usr/local/bin/yarn npm: 6.12.0 - /usr/local/bin/npm Watchman: 4.9.0 - /usr/local/bin/watchman SDKs: iOS SDK: Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1 IDEs: Xcode: 11.3.1/11C504 - /usr/bin/xcodebuild npmPackages: react: 16.9.0 => 16.9.0 react-native: 0.61.5 => 0.61.5 npmGlobalPackages: react-native-cli: 2.0.1 ``` - **Platform that you're experiencing the issue on**: - [x ] iOS - [ ] Android - [ x] **iOS** but have not tested behavior on Android - [ ] **Android** but have not tested behavior on iOS - [ ] Both - **`react-native-firebase` version you're using that has this issue:** - `none // because I removed when I use to 6.4.0-rc4` - **`Firebase` module(s) you're using that has the issue:** - `e.g. Instance ID` - **Are you using `TypeScript`?** - `N`
Think
react-native-firebase
is great? Please consider supporting all of the project maintainers and contributors by donating via our Open Collective where all contributors can submit expenses. [Learn More]React Native Firebase
andInvertase
on Twitter for updates on the library.