react-native-push-notification / ios

React Native Push Notification API for iOS.
MIT License
745 stars 285 forks source link

Notification event listener is not called when app was killed #143

Open mathiasmoeller opened 4 years ago

mathiasmoeller commented 4 years ago

Bug report

Summary

I am sending local push notifications (using react-native-background-fetch) to my app. I am using react-native-push-notifications for this which uses this repo under the hood. I followed the issue here to get it working for notifications when the app is in foreground or background. When the app is killed and I click on the notification, the app is being started but the handler registered via PushNotificationIOS.addEventListener(type, handler); is not called. Neither for the event type localNotification nor notification.

The listeners are registered in index.js.

Since background and foreground notifications are working I assume that the issue is in my AppDelegate configuration or a bug. Help is very welcome.

Environment info

react-native info output:

info 
  React Native Environment Info:
    System:
      OS: macOS 10.15.5
      CPU: (12) x64 Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
      Memory: 1.65 GB / 32.00 GB
      Shell: 5.7.1 - /bin/zsh
    Binaries:
      Node: 10.16.3 - ~/.nvm/versions/node/v10.16.3/bin/node
      npm: 6.13.6 - ~/.nvm/versions/node/v10.16.3/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 13.5, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
      Android SDK:
        API Levels: 23, 26, 27, 28, 29
        Build Tools: 23.0.1, 26.0.3, 27.0.3, 28.0.3, 29.0.3
        System Images: android-29 | Google APIs Intel x86 Atom, android-29 | Google APIs Intel x86 Atom_64
    IDEs:
      Xcode: 11.5/11E608c - /usr/bin/xcodebuild
    npmPackages:
      react: 16.8.3 => 16.8.3 
      react-native: 0.59.5 => 0.59.5 
    npmGlobalPackages:
      react-native-cli: 2.0.1

Library version: 1.2.2

Steps to reproduce

Send push notification when the app is killed and check if the registered handler is called.

Reproducible sample code

My AppDelegate.m looks the following:

/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
#import <Firebase.h>
#import <GoogleMaps/GoogleMaps.h>
#import "AppDelegate.h"

#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>

#import <Fabric/Fabric.h>
#import <Crashlytics/Crashlytics.h>
#import "Orientation.h"

#import <UserNotifications/UserNotifications.h>
#import <RNCPushNotificationIOS.h>

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  [FIRApp configure];
  [GMSServices provideAPIKey:@"XXX"];
  NSURL *jsCodeLocation;

  [Fabric with:@[[Crashlytics class]]];

  jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];

  RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"iosl"
                                               initialProperties:nil
                                                   launchOptions:launchOptions];
  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];

  // Define UNUserNotificationCenter
  UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
  [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound + UNAuthorizationOptionBadge)completionHandler:^(BOOL granted, NSError * _Nullable error) {
    if (granted) {
      center.delegate = self;
    }
  }];

  return YES;
}

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

// 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];
}
// IOS 10+ Required for local notification tapped event
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)(void))completionHandler
{
  [RNCPushNotificationIOS didReceiveNotificationResponse:response];
  completionHandler();
}

/* part of react-native-orientation package, see https://github.com/yamill/react-native-orientation#Configuration */
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
  return [Orientation getOrientation];
}

@end

My AppDelegate.h:

/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

#import <UIKit/UIKit.h>
#import <UserNotifications/UNUserNotificationCenter.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate, UNUserNotificationCenterDelegate>

@property (nonatomic, strong) UIWindow *window;

@end

Thanks a lot!

MobileAppVault commented 4 years ago

@mathiasmoeller I've fixed that behavior by adding these lines to my app:

async componentDidMount() {
    const NotificationMessage = await PushNotificationIOS.getInitialNotification();
    if (NotificationMessage) {
      this._localNotificationHandler(NotificationMessage);
    } else {
      PushNotificationIOS.addEventListener(
        'localNotification',
        this._localNotificationHandler,
      );
    }
mathiasmoeller commented 4 years ago

Hey @MobileAppVault, thanks for the suggestion. Sadly, getIntialNotification does not return anything for me when the app was killed :/ Could you maybe show me your AppDelegate?

rkostrab commented 4 years ago

I am confirming that PushNotificationIOS.getInitialNotification() returns always null after tapping the notification in the notification center (and of course while an app is killed).

v. 1.3.0

MobileAppVault commented 4 years ago

@mathiasmoeller

here is my AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

// ...

// Define UNUserNotificationCenter
  UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
  center.delegate = self;

  return YES;
}
//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);
}

// 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];
}
// IOS 10+ Required for localNotification event
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)(void))completionHandler
{
  [RNCPushNotificationIOS didReceiveNotificationResponse:response];
  completionHandler();
}
// IOS 4-10 Required for the localNotification event.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
 [RNCPushNotificationIOS didReceiveLocalNotification:notification];
}

It works for me an my changes are already in production. https://itunes.apple.com/us/app/picr-tell-your-story-in-pics/id778479025?mt=8

rkostrab commented 4 years ago

It seems, this issue is related to this one.

You can close this issue.

mathiasmoeller commented 4 years ago

@rkostrab you linked this issue in your comment, was that on purpose? Because for me the issue still exists ;)

rkostrab commented 4 years ago

@mathiasmoeller sorry, I've already fixed the link. Thanks

oogushikun commented 3 years ago

@mathiasmoeller did you ever solve this?

pktippa commented 3 years ago

@mathiasmoeller is this still open or anyone found a fix for this?

mathiasmoeller commented 3 years ago

I stopped working on the project using react-native so I don't know if there is any progress here. Sorry :/

bharatmodi777 commented 1 year ago

Is there any update on this issue? I am facing same issue.