ios icon indicating copy to clipboard operation
ios copied to clipboard

iOS Background Notification Not Working

Open princealirehman1 opened this issue 5 years ago • 19 comments

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

princealirehman1 avatar Jun 16 '20 18:06 princealirehman1

Experiencing this also. No background notification being sent when soft-closing the app.

francisleigh avatar Jun 26 '20 21:06 francisleigh

same issue with me and the same version of Firebase V7

IbrahimSalem0 avatar Jun 30 '20 02:06 IbrahimSalem0

Is this module compatible with react native firebase cloud messaging ?

ghasemikasra39 avatar Jul 09 '20 08:07 ghasemikasra39

Same for me :/ not working. Any solution?

martinop avatar Sep 08 '20 20:09 martinop

I can vouch iOS isn't working for me either, I have been stuck with debugging for like 2 days now

hasansultan92 avatar Sep 13 '20 11:09 hasansultan92

still same? i am also having the same issue.

axeljeremy7 avatar Oct 01 '20 15:10 axeljeremy7

Actually whenever I’m switching current application to any other apps, local notification is not working but when I back to current application, It works. I want local notifications to be work in any scenario, within the application and also while I’m switching to other application. Please Help.... here's the lib and version in my app: "@react-native-community/push-notification-ios": "^1.5.0", "react-native-push-notification": "^5.1.1", "react": "16.11.0", "react-native": "0.62.2",

ghost avatar Oct 08 '20 10:10 ghost

I have local notification issue in iOS => local notification working fine in android for foreground & background, also local notification click event work but In Case of iOS local notification work in only foreground, not in background, also not working click event of notification. I need perfect solution for local notification working fine both iOS & Android, and also working their click event. Help...

ghost avatar Oct 08 '20 10:10 ghost

Facing the same issue with the basic setup, when the app is in the foreground everything works fine, both presentLocalNotification and scheduleLocalNotification, however once I schedule a local notification and soft close the app nothing happens.

ospfranco avatar Oct 09 '20 08:10 ospfranco

I'm facing the same issue receiving notifications on Android either in background or foreground, On iOS getting notifications in the foreground but not in background

ZaidQ797 avatar Nov 12 '20 04:11 ZaidQ797

the same issue

bodrius avatar Dec 23 '20 13:12 bodrius

My issue turned out to be I was generating the ID myself a 32 bit unsigned integer, but somehow it was not correct it was overflowing, after I changed to generate a 31 bit integer, everything started working in a stable manner

ospfranco avatar Dec 23 '20 15:12 ospfranco

same issue, i used firebase react native messaging and onmessage also called, but with ios nothing comes out. even app is closed. i used react-native-push-notification @react-native-community/push-notification-ios @react-native-firebase/messaging.

deep-link avatar Dec 25 '20 06:12 deep-link

Still no solution?

davevilela avatar Mar 02 '21 19:03 davevilela

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.

theRealSheng avatar Apr 06 '21 08:04 theRealSheng

Facing the same issue... When the app is killed(removed from the background) on notification gets triggered after receiveing a notification, but when app is in the background nothing happens.

ravikiranavasarala avatar Jun 06 '22 05:06 ravikiranavasarala

Still not working guys ? I have the same problem...

HadesDev42 avatar Aug 17 '22 14:08 HadesDev42

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 data object.

{
    "to": "{{myID}}",
    "notification": {
        "title": "Working Good",
        "body": "backgroudn noti",
        "badge": "1"
    },
    "priority": "high",
    "badge": "1",
    "content_available": true
}

Definitely doesn't trigger background notifications. Doesn't contain the priority, badge, and content_available properties. This was my original message structure.

{
    "to": "myID",
    "notification": {
        "title": "payload.title1",
        "body": "payload.body"
    },
    "data": {
        "link": "payload.link"
    },
    "apns": {
        "payload": {
            "aps": {
                "mutable-content": 1
            }
        }
    }
}

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.

{
    "to": "myID",
    "notification": {
        "title": "payload.title",
        "body": "payload.body"
    },
    "data": {
        "link": "payload.link"
    },
    "apns": {
        "payload": {
            "aps": {
                "mutable-content": 1
            }
        }
    },
    "priority":"high",
    "badge":"1",
    "content_available":true
}

Anyway, my advice if this is a poblem, is to setup postman or some test endpoints with all the possible combinations of message.

emileswain avatar Mar 24 '23 18:03 emileswain

@emileswain you just saved my day

CarloTamburrelli avatar Apr 30 '23 10:04 CarloTamburrelli