ios: iOS Background Notification Not Working
Bug report
Summary
I am trying to acheive Push Notifications for both Android & iOS (Foreground & Background). I followed the official firebase docs and was able to run it correctly on Android in all app states. Foreground, Background & Quit it works
But the same thing is only working in Foreground for IOS.
In background what i want is push notification from RestApi. And on foreground I am showing a LocalNotification which is working fine.
No Matter what I do it doesnot trigger the messaging().setBackgroundMessageHandler(async remoteMessage => {console.log(‘Message handled in the background!’, remoteMessage);});
Environment info
react-native info output:
System:
OS: Windows 10 10.0.18363
CPU: (8) x64 Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz
Memory: 2.67 GB / 11.88 GB
Binaries:
Node: 12.16.1 - C:\Program Files\nodejs\node.EXE
Yarn: 1.21.1 - C:\Program Files (x86)\Yarn\bin\yarn.CMD
npm: 6.13.4 - C:\Program Files\nodejs\npm.CMD
Watchman: Not Found
SDKs:
Android SDK:
API Levels: 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29
Build Tools: 24.0.2, 25.0.3, 26.0.1, 26.0.2, 28.0.2, 28.0.3, 29.0.0, 29.0.2
System Images: android-19 | Google APIs Intel x86 Atom, android-27 | Google APIs Intel x86 Atom, android-27 | Google Play Intel x86 Atom, android-28 | Google APIs Intel x86 Atom, android-28 | Google Play Int
el x86 Atom, android-29 | Google APIs Intel x86 Atom
Android NDK: Not Found
IDEs:
Android Studio: Version 3.5.0.0 AI-191.8026.42.35.6010548
Languages:
Java: 1.8.0_211 - C:\Program Files\Java\jdk1.8.0_211\bin\javac.EXE
Python: 2.7.17 - C:\Python27\python.EXE
npmPackages:
@react-native-community/cli: Not Found
react: 16.11.0 => 16.11.0
react-native: 0.62.2 => 0.62.2
npmGlobalPackages:
*react-native*: Not Found
`Package.json’
{
"name": "ABCAPP",
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"start": "react-native start",
"test": "jest",
"lint": "eslint ."
},
"dependencies": {
"@react-native-community/masked-view": "0.1.5",
"@react-native-community/push-notification-ios": "^1.2.2",
"@react-native-firebase/app": "^7.2.1",
"@react-native-firebase/iid": "^7.1.4",
"@react-native-firebase/messaging": "^7.1.5",
"@react-navigation/drawer": "^5.1.1",
"@react-navigation/material-bottom-tabs": "^5.1.6",
"@react-navigation/native": "5.2.1",
"@react-navigation/stack": "5.2.16",
"axios": "^0.19.2",
"expo-font": "^8.1.1",
"native-base": "2.13.8",
"react": "16.11.0",
"react-dom": "~16.9.0",
"react-native": "0.62.2",
"react-native-gesture-handler": "~1.5.0",
"react-native-notifications": "^3.2.2",
"react-native-reanimated": "~1.4.0",
"react-native-safe-area-context": "0.6.0",
"react-native-screens": "2.0.0-alpha.12",
"react-native-unimodules": "^0.9.1",
"react-native-vector-icons": "^6.6.0",
"react-native-web": "~0.11.7",
"react-redux": "^7.2.0",
"redux": "^4.0.5",
"redux-logger": "^3.0.6",
"redux-persist": "^6.0.0",
"redux-saga": "^1.1.3"
},
"devDependencies": {
"@babel/core": "^7.6.2",
"@babel/runtime": "^7.6.2",
"@react-native-community/eslint-config": "^0.0.5",
"babel-jest": "^24.9.0",
"eslint": "^6.5.1",
"jest": "^24.9.0",
"metro-react-native-babel-preset": "^0.58.0",
"react-test-renderer": "16.11.0"
},
"jest": {
"preset": "react-native"
}
}
Reproducible sample code
import React, {useEffect, useState} from 'react';
import {Provider} from 'react-redux';
import {createStore, applyMiddleware, compose} from 'redux';
import logger from 'redux-logger';
import createSagaMiddleware from 'redux-saga';
import AllSagas from './js/sagas';
import {persistStore, persistReducer} from 'redux-persist';
import {AsyncStorage, View, Image , Platform } from 'react-native';
import {PersistGate} from 'redux-persist/integration/react';
import reducer from './js/reducers';
import RootNavigator from './js/navigators/RootNavigator';
import messaging, {AuthorizationStatus} from '@react-native-firebase/messaging';
import {firebase} from '@react-native-firebase/iid';
import {Alert} from 'react-native';
import {Notifications} from 'react-native-notifications';
import PushNotificationIOS from "@react-native-community/push-notification-ios";
const persistConfig = {
key: 'root',
storage: AsyncStorage,
};
const persistedReducer = persistReducer(persistConfig, reducer);
let sagaMiddleware = createSagaMiddleware();
const middleware = [sagaMiddleware];
function configureStore(initialState) {
const enhancer = compose(applyMiddleware(...middleware, logger));
return createStore(persistedReducer, initialState, enhancer);
}
const store = configureStore({});
sagaMiddleware.run(AllSagas);
const persistor = persistStore(store);
// Uncomment in case you want to delete state from persistant storage.
// persistor.purge();
export default App = () => {
const [isReady, setisReady] = useState(false);
requestUserPermission();
getMyToken();
// Foreground Notification Listener;
useEffect(() => {
const unsubscribe = messaging().onMessage(async remoteMessage => {
// Alert.alert('A new FCM message arrived!', JSON.stringify(remoteMessage));
const { title , body } = remoteMessage.data;
if(Platform.OS === 'android'){
Notifications.postLocalNotification({
body: body,
title: title,
sound: 'default',
silent: false,
category: 'SOME_CATEGORY',
userInfo: {},
'google.message_id': '',
payload: {
body: body,
title: title,
sound: 'default',
silent: false,
category: 'SOME_CATEGORY',
'google.message_id': '',
},
});
}else if(Platform.OS==='ios'){
PushNotificationIOS.presentLocalNotification({
alertTitle: title,
alertBody: body
});
}
});
return unsubscribe;
},[]);
setTimeout(() => {
setisReady(true);
}, 3500);
if (!isReady) {
return (
<View style={{flex: 1}}>
<Image
source={require('./assets/images/gif_splash.gif')}
resizeMethod="auto"
resizeMode="cover"
style={{width: '100%', height: '100%'}}
/>
</View>
);
}
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<RootNavigator/>
</PersistGate>
</Provider>
);
};
async function requestUserPermission() {
const authStatus = await messaging().requestPermission({
alert: true,
announcement: false,
badge: true,
carPlay: true,
provisional: false,
sound: true,
});
const enabled =
authStatus === AuthorizationStatus.AUTHORIZED ||
authStatus === AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Authorization status:', authStatus);
}
}
const getMyToken = async () => {
const alarmFcmToken = await firebase.messaging().getToken(
firebase.app().options.messagingSenderId, // default to this app
'FCM',
); // defaults to 'FCM');
console.log('TOOOOOOOOOOOOOOKEEEEEEEEEEEN');
console.log(alarmFcmToken);
};
/**
* @format
*/
import React from 'react';
import {AppRegistry, Platform} from 'react-native';
import {Alert} from 'react-native';
import messaging from '@react-native-firebase/messaging';
import {Notifications} from 'react-native-notifications';
import App from './App';
import {name as appName} from './app.json';
// Register background handler
messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('Message handled in the background!', remoteMessage);
});
function HeadlessCheck({ isHeadless }) {
if (isHeadless) {
// App has been launched in the background by iOS, ignore
return null;
}
return <App />;
}
AppRegistry.registerComponent(appName, () => HeadlessCheck);
#import <React/RCTBridgeDelegate.h>
#import <UserNotifications/UNUserNotificationCenter.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate, UNUserNotificationCenterDelegate>
@property (nonatomic, strong) UIWindow *window;
@end
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#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>
#import <RNCPushNotificationIOS.h>
#import <UserNotifications/UNUserNotificationCenter.h>
#import <Firebase.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:@"HomeMediCare"
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];
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 [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
@end
Library version: ^1.2.2 iOS: 13.4.1
About this issue
- Original URL
- State: open
- Created 4 years ago
- Reactions: 7
- Comments: 19
Is this module compatible with
react native firebase cloud messaging?same issue with me and the same version of Firebase V7
Experiencing this also. No background notification being sent when soft-closing the app.
Just an FYI as this is pretty difficult to debug due to the way messaging works and the fact you will get different message/system behaviour depending on the message structure. Below works fairly consistently Note that i don’t have a
dataobject.Definitely doesn’t trigger background notifications. Doesn’t contain the
priority,badge, andcontent_availableproperties. This was my original message structure.Might trigger background notifications and badge count. But not always I’m still debuggin issues myself, and i’m actually using a different notification package, but this was such a nightmare, that i fellt the need to share.
Note, that here i have the priority fields and both a notification and data block, i’ve read in other posts for react native that if you have a notification “AND” a data block that firebase messagings setbackgroundhandler won’t trigger. if your using that. But haven’t confirmed that yet.
Anyway, my advice if this is a poblem, is to setup postman or some test endpoints with all the possible combinations of message.
I was able to just use the react-native-firebase latest without this push notification library.
Please make sure you send the data correctly in order to trigger the notification.
At my side, I have used the following format:
{ “to”: “TOKEN”, “data”:{ “title”:“Some title”, “message”:“Some text”, “vibrate”:1, “sound”:1, “channelId”: “TEST” }, “notification”: {. <-- Trigger notification “title”:“Some title”, “body”:“Some text”, “sound”: “default” }, “content_available”:true, <-- Trigger notification required for IOS “priority”:“high” }
setBackgroundMessageHandler just handle the message once the app opens due to the notification. It does not trigger when notification is received.
I can vouch iOS isn’t working for me either, I have been stuck with debugging for like 2 days now