react-native-push-notification / ios

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

Scheduled notifications are not handled when app is killed #252

Open Estebank94 opened 3 years ago

Estebank94 commented 3 years ago

Description

When I open a scheduled notification when the app is killed, the app opens and nothing happens. When I open a scheduled notification when the app is in foreground or background, the notification is handled.

This is the notification data I get when I open the app by tapping on a notification:

notification ios {"action": undefined, "badge": 0, "data": null, "finish": [Function finish], "fireDate": 1610466763000, "foreground": false, "id": undefined, "message": undefined, "reply_text": undefined, "soundName": "default", "title": undefined, "userInteraction": false}

I think there must be something wrong with the App Delegate but I followed the instructions and checked with the example provided.

AppDelegate.h

#import <UserNotifications/UNUserNotificationCenter.h>
...
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate, UNUserNotificationCenterDelegate>
...

AppDelegate.m

#import "AppDelegate.h"

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

#import <React/RCTLinkingManager.h>

#import "RNBootSplash.h"

...

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

...

@implementation AppDelegate

// 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 localNotification event
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
         withCompletionHandler:(void (^)(void))completionHandler
{
  [RNCPushNotificationIOS didReceiveNotificationResponse:response];
}

...

  // 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(UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge);
}

- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity
 restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler
{
  return [RCTLinkingManager application:application
                   continueUserActivity:userActivity
                     restorationHandler:restorationHandler];
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

@end

React Native version:

  SDKs:
    iOS SDK:
      Platforms: iOS 13.7, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
  npmPackages:
    @react-native-community/cli: Not Found
    react: 16.13.1 => 16.13.1 
    react-native: 0.63.4 => 0.63.4 
    @react-native-community/push-notification-ios": "^1.8.0"

Steps To Reproduce

  1. Schedule a local notification
  2. Kill App
  3. Open scheduled notification

Expected Results

The notification should be handled

bang9 commented 3 years ago

+1

kanelloc commented 3 years ago

Any workaround?

Estebank94 commented 3 years ago

I didn't find one yet...

cuttlas commented 3 years ago

Same problem :(

ninjz commented 3 years ago

@Estebank94 Are you opening the notification through an action on the notification or just by tapping the notification?

Also, what do you mean the notification should be handled? By what?

joaocosta9 commented 3 years ago

@ninjz do you know how I can handle an action when the app is killed, or is it not possible? Since the event listener is removed

ninjz commented 3 years ago

@joaocosta9 Two things:

  1. Make sure you're not using react-native-splash-screen as that ends up swallowing some events which prevents you from receiving the callbacks on the delegate. (This was a huge breakthrough for me which took days to figure out)
  2. Since getInitialNotification() always returns null. Store the notification action response in didReceiveNotification callback inside of AsyncStorage and retrieve that on app launch. Also, delay the call of the callback inside of didReceiveNotification to make sure there is enough time to handle everything you need to process the notification action.

For me, the biggest issue now is getting this to work with the Watch. Can't seem to consistently get the notification action response from it when the app has been backgrounded for some time (> ~30mins). Still investigating this issue and my guess so far is that it's due to some other dependency.

joaocosta9 commented 3 years ago

Hey @ninjz , thanks for your response. You are talking about the didReceiveNotificationResponse in the AppDelegate.m file correct?

ninjz commented 3 years ago

@joaocosta9 Yes, if you set the AppDelegate as the delegate for the UNUserNotificationCenter.currentNotificationCenter

cuttlas commented 3 years ago

I would really appreciate if somebody could share the code on how to store the didReceiveNotification response in the AsyncStorage

joaocosta9 commented 3 years ago

@cuttlas me too, I tried to find a way to do that, but I could not find one. Im sorry @ninjz, is there any way you can help us with this ? 😅

andrew-stupchuk commented 3 years ago

@joaocosta9 Two things:

  1. Make sure you're not using react-native-splash-screen as that ends up swallowing some events which prevents you from receiving the callbacks on the delegate. (This was a huge breakthrough for me which took days to figure out)
  2. Since getInitialNotification() always returns null. Store the notification action response in didReceiveNotification callback inside of AsyncStorage and retrieve that on app launch. Also, delay the call of the callback inside of didReceiveNotification to make sure there is enough time to handle everything you need to process the notification action.

For me, the biggest issue now is getting this to work with the Watch. Can't seem to consistently get the notification action response from it when the app has been backgrounded for some time (> ~30mins). Still investigating this issue and my guess so far is that it's due to some other dependency.

@ninjz do you have any progress with this?

webgev commented 2 years ago

+1