react-native-push-notification / ios

React Native Push Notification API for iOS.
MIT License
739 stars 284 forks source link

iOS Background Notification Not Working #138

Open princealirehman1 opened 4 years ago

princealirehman1 commented 4 years ago

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

francisleigh commented 4 years ago

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

IbrahimSalem0 commented 4 years ago

same issue with me and the same version of Firebase V7

ghasemikasra39 commented 4 years ago

Is this module compatible with react native firebase cloud messaging ?

martinop commented 3 years ago

Same for me :/ not working. Any solution?

hasansultan92 commented 3 years ago

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

axeljeremy7 commented 3 years ago

still same? i am also having the same issue.

ghost commented 3 years ago

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 commented 3 years ago

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

ospfranco commented 3 years ago

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.

ZaidQ797 commented 3 years ago

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

bodrius commented 3 years ago

the same issue

ospfranco commented 3 years ago

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

deep-link commented 3 years ago

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.

davevilela commented 3 years ago

Still no solution?

theRealSheng commented 3 years ago

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.

ravikiranavasarala commented 2 years ago

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.

HadesDev42 commented 2 years ago

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

emileswain commented 1 year ago

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.

CarloTamburrelli commented 1 year ago

@emileswain you just saved my day