Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

onNotification not being called when app was killed on iOS #1501

Closed
mathiasmoeller opened this issue Jul 3, 2020 · 49 comments
Closed

onNotification not being called when app was killed on iOS #1501

mathiasmoeller opened this issue Jul 3, 2020 · 49 comments

Comments

@mathiasmoeller
Copy link

Bug

I am sending local notifications using react-native-background-fetch. This works good. When the user clicks on a notification I redirect him to a certain screen. This always works in Android.
For iOS it is working when the app is in foreground or background. When the app was killed and the user clicks on a notification, the app launches but the onNotification handler is not being called.
I call PushNotification.configure from index.js, so timing should not be the issue.

I followed the fix here to get onNotification to work in foreground and background.

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: 4.00 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: the development branch of this repo for the latest Android notification action fixes

Steps To Reproduce

  1. Configure the onNotification handler in index.js
  2. Send a push notification while the app is killed
  3. Check if the onNotification handler was called when the notification is clicked

Describe what you expected to happen:

onNotification should be called when coming from Foreground/Background or when the app was killed

@mathiasmoeller mathiasmoeller changed the title onNotification not being called when app was killed on iOS onNotification not being called when app was killed on iOS Jul 3, 2020
@Dallas62
Copy link
Collaborator

Dallas62 commented Jul 3, 2020

Hi,
The behavior of iOS depends on when you put in AppDelegate,
Check the iOS repository for this.

@mathiasmoeller
Copy link
Author

Okay I will recreate the issue there!

@mathiasmoeller
Copy link
Author

@Dallas62
Copy link
Collaborator

Dallas62 commented Jul 3, 2020

I just saw your issue with AppDelegate, the Apple documentation say that:

application didReceiveLocalNotification:(UILocalNotification *)notification

Is deprecated, and there is other issues on ios repo, to repace with something like « willPresentNotification ».
But local notification in background doesn’t work

@mathiasmoeller
Copy link
Author

It works fine for me in the background. Just not when the app is killed.
Or what do you mean with with "local notification in background doesn’t work"?

@Dallas62
Copy link
Collaborator

Dallas62 commented Jul 3, 2020

In the new Notification SDK of Apple, local notifications doesn’t trigger the application if the user doesn’t interact with the notification .

@Dallas62
Copy link
Collaborator

Dallas62 commented Jul 3, 2020

Hi again, just to be sure, can you provide the content of .configure() ?

Reading your case and the version you are using, there might be a side affect of an Android change.

https://github.com/zo0r/react-native-push-notification/blob/dev/CHANGELOG.md

Now local scheduled notifications trigger onNotification before display #574.

@Dallas62 Dallas62 reopened this Jul 3, 2020
@mathiasmoeller
Copy link
Author

Sorry @Dallas62, I was very busy the whole week.
My .configure looks like this:

PushNotification.configure({
  onNotification: handleNotificationClick,
  onAction: handleNotificationActionClick
});

function handleNotificationClick(notification) {
  const id = Platform.OS === "ios" ? notification.data.id : notification.id;
  
  RootNavigation.navigate("Question", {
    showBackButton: false,
    notificationId: id
  });
}

function handleNotificationActionClick(notification) {
  let vote;
  if (notification.action === "Yes") {
    vote = 1;
  } else if (notification.action === "No") {
    vote = 3;
  } else {
    showToast("Unknown action clicked. Please vote manually.");
    PushNotification.invokeApp(notification);
    return;
  }

  // Do some stuff while the app should not launch...
}

For Android everything works fine (including the actions). iOS works fine if the app was in fore- or background.
When the app was killed in iOS, the whole app launches and onNotification is not triggered.

@mathiasmoeller
Copy link
Author

@Dallas62 any news? 😇

@Dallas62
Copy link
Collaborator

Hi @mathiasmoeller
Will try to look at it soon

@mathiasmoeller
Copy link
Author

Thanks a lot! 🙏

@mathiasmoeller
Copy link
Author

@Dallas62 any news? 😇 😬

@Dallas62
Copy link
Collaborator

Hi @mathiasmoeller, I'm on it 😉

@Dallas62
Copy link
Collaborator

Hi @mathiasmoeller
Can you provide a reproductive example ?
I'm not able to reproduce it... 😞

@Dallas62
Copy link
Collaborator

Dallas62 commented Jul 27, 2020

Hi again @mathiasmoeller
I probably found a bug in the way to get the Initial Notification when: PushNotification.configure({popInitialNotification: true /* default */})
You can quickly test: #1516

File & Line:

handlePopInitialNotification(AppState.currentState);

AppState.currentState is not passed in the current version, the function need to be changed too (to get the this context).

@mathiasmoeller
Copy link
Author

@Dallas62 I will test your fix ASAP! I think I will have time on Thursday. I will let you know if it fixes it

@mathiasmoeller
Copy link
Author

@Dallas62 I will try to test it today.
Should I install PR #1516 to test it? And should I set popInitialNotification to true or false? To be honest I didn't even understand what this flag is supposed to do ;)

I have some important Android fixes to do but I hope I will be able to do it in the afternoon.

@Dallas62
Copy link
Collaborator

Hi @mathiasmoeller
You can test the fix by installing this PR and focus on this part as the PR may contains breaking changes (data structure).
You can set popInitialNotification to true, this allow onNotification to be triggered when the application is opened using a notification.

@mathiasmoeller
Copy link
Author

Sadly I still could not get it to work when the app is killed.
I tried it with registering PushNotification.configure in index.js and with PushNotificationIOS.getInitialNotification also in index.js. Both did not work

@Dallas62
Copy link
Collaborator

PushNotificationIOS.getInitialNotification is not working ?
This is really strange, can you provide AppDelegate ?

@mathiasmoeller
Copy link
Author

mathiasmoeller commented Jul 30, 2020

Yes it does not return anything.
This is my AppDelegate:

/**
 * 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

@Dallas62
Copy link
Collaborator

This is really strange, I think this is a problem with the AppDelegate or project configuration, but not sure.
Some people seems to encounter this bug only in debug, is it your case ?

Take care, in both issue (this and ios one) you let an API key.

@mathiasmoeller
Copy link
Author

I found something, maybe it's useful.
I installed the current develop branch since you merged #1516.
I am using react-native-boundary to monitor geofences and send local notifications in case of an event.
The following happens:

  • The app is killed
  • The user leaves a geofence and react-native-boundary triggers some code inside my app
  • Therefore the app starts in background
  • While doing this, it runs PushNotificationIOS.getInitialNotification() which is in my index.js file. It resolves to null (since there is no notification yet)
  • My code triggers a local notification using react-native-push-notification
  • The user clicks on this notification
  • PushNotificationIOS.getInitialNotification() in index.js is not triggered again
  • The onNotification handler which was registered in index.js also does not get called

Does this maybe describe the situation a bit better? (I know its not the most simple one 😉 )

@mathiasmoeller
Copy link
Author

@Dallas62 I tried the new 5.0.1 release.
I guess instead of PushNotificationIOS.getInitialNotification I should use PushNotification.popInitialNotification now right?
I added it to my index.js file.
But the behaviour stays the same as described in my last comment. It gets called when the app starts in background due to geofencing events and a local notification is shown. During this app start PushNotification.popInitialNotification is called and the callback is called with undefined. When the user clicks the notification, the app comes to foreground but PushNotification.popInitialNotification is not called again.

Any ideas? Thank you so much already!

@Dallas62
Copy link
Collaborator

Dallas62 commented Aug 13, 2020

Hi @mathiasmoeller
If the app is considered already started, the initial notification should be always undefined (in case it's not a notification that start the app).
What's strange in your case is that the notification doesn't trigger onNotification.

I guess instead of PushNotificationIOS.getInitialNotification I should use PushNotification.popInitialNotification now right?
I added it to my index.js file.

Yes, but it's to unify notification format, result is based on PushNotificationIOS.getInitialNotification.

I don't know which accuracy you expect between geolocalisation and notification, but did you tried to schedule a notification ?
This will probably let the background process exit before triggering the notification. Starting with 60s to be sure that the application is exited then reduce the timing.
It's not the expected behavior but a workaround until we found a solution.

@mathiasmoeller
Copy link
Author

@Dallas62 thanks for the clarification.

60s should not be an issue for my use case I think. I could try that! But I'd prefer to get onNotification to work 😁 I don't get why it works when the app is in the background after being opened regularly but not when it is in background after starting in this headless background mode.

@mathiasmoeller
Copy link
Author

@Dallas62 maybe I have made some mistakes while setting up @react-native-community/push-notification-ios.
Do I have to follow the whole setup guide for this library or does react-native-push-notification already contain the important parts and setup?

@Dallas62
Copy link
Collaborator

Actually there is nothing for iOS on the repository (expect JS implementation).
So for iOS it's the setup of RNC package.
A mistake in the installation can be the root cause, or a missing notification method in the AppDelegate. But when I look at your AppDelegate, I don't see anything special.

If you have a small reproducible example, I can try to look directly.

@mathiasmoeller
Copy link
Author

I can try to set up an example. But I don't think I have time for that in the next days. Let's see.

I made another interesting observation:
App starts in foreground, moved to background (e.g. by pressing the home button), a notification is shown, the notification is clicked -> onNotification gets called

App starts in background, a notification is shown (not clicked), I open the app manually, I click the notification now -> onNotification is not called.

So the problem seems to be that when the app starts in background, the listeners do not get attached properly?

I have logs that tell me that PushNotification.configure gets called when starting in background. So this part seems fine, any ideas?

@Dallas62
Copy link
Collaborator

Dallas62 commented Aug 13, 2020

You can try to attach listener on iOS library:
https://github.com/react-native-community/push-notification-ios#addeventlistener

  • localNotification
  • notification

If it's triggered; there is an issue on this library or the use of .configure()
Else, this is due to a bug in iOS library or mis-configuration
In any case, this will help for investigations

@mathiasmoeller
Copy link
Author

I tested it with the ios implementation. The behaviour is exactly the same. So I guess it is for sure not an issue of react-native-push-notification.

@mathiasmoeller
Copy link
Author

scheduling the notification sadly does not help :/

@mathiasmoeller
Copy link
Author

Okay I build a sample project. This issue is: there it works...... FML! I did everything exactly the same way as I did it in my project.

I found another log in XCode:

2020-08-14 13:05:42.436163+0200 iosl[37997:1282420] -[RNFirebaseNotifications sendJSEvent:name:body:] [Line 411] Multiple notification open events received before the JS Notifications module has been initialised

This sounds like it is an issue. Problem is, that I call PushNotification.configure directly in index.js. There is no earlier point in time....
Do you maybe have any idea what it could be @Dallas62 ? Sorry for spamming you so much 😁

@Dallas62
Copy link
Collaborator

Hi @mathiasmoeller
This message doesn't come from this library or the iOS one. It's probably related to the invertase one.

@stevenasi
Copy link

Had the same issue.

only happened on simulator but works fine on real device.

try to stop debugging or remove the app from simulator and re install it again.

@mathiasmoeller
Copy link
Author

@stevenasi thanks for the suggestion! It's just hard to test without the simulator since my events are triggered by background events 😁 But I will give it a try for sure!

@mathiasmoeller
Copy link
Author

@stevenasi oh wow for me it is even worse. On the real device not even while the app is in fore- or background the notification handler is called! ARGH!

@stevenasi
Copy link

@mathiasmoeller did you try to uninstall the app from the device and re-install it again because that what was causing the problem in my case.

@oogushikun
Copy link

was this ever resolved? having this issue when I send a silent notification, the app wakes up from a kill state but doesn't call onNotification. This works well in android

@CamWalker
Copy link

CamWalker commented Dec 20, 2020

Also having a similar issue. Nothin gets called anything from a killed state.

@csokdara-thefoundry-app

I could confirm this bug, it seems to work in release build but not in debug. What strange is in release build the payload that is passed down doesn't include title and message only the action property.

@amirmn72
Copy link

amirmn72 commented Feb 11, 2021

After 2 days i fined the answer.
react-native-push-notification/ios#24 (comment)
when onRegister Called PushNotificationIOS.getInitialNotification returned the notification data

@sazzadiproliya
Copy link

Hi Friends, i have found solution. Please check below methods.

Add this code in below file.
AppDelegate.m

  • (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
    ..............

    if (launchOptions != nil)
    {
    NSDictionary* userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
    if (userInfo != nil)
    {
    [self performSelector:@selector(callNotification:) withObject: userInfo afterDelay:10];
    }
    }

.................
}

create new file methods in same class....

-(void) callNotification: (NSDictionary*) userInfo {
[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo];
}

Modify below File from framework
RNCPushNotificationIOS.m

  • (void)handleRemoteNotificationReceived:(NSNotification *)notification {
    .............
    remoteNotification[@"notificationData"] = notification.userInfo[@"notification"];
    .............
    }

Update above line on this methods.

Now Check, you will data on onNotification method......

Hope this work for you....

@NitishSystango
Copy link

@SazzadIp Your solution works and it's a good one also I tried without framework changes and it's working on that case also.
You only need to add below code will also works.

Add this code in below file.
AppDelegate.m

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

if (launchOptions != nil)
{
NSDictionary* userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (userInfo != nil)
{
[self performSelector:@selector(callNotification:) withObject: userInfo afterDelay:10];
}
}

.................
}

create new file methods in same class....

-(void) callNotification: (NSDictionary*) userInfo {
[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo];
}

@FrontendTerminator
Copy link

I faced the same problem and for me the solution was to turn off the debug mode on the real device and after that the onNotification method started working.

@akshayhalasangiremitbee

I faced the same problem and for me the solution was to turn off the debug mode on the real device and after that the onNotification method started working.

How did you do that?

@FrontendTerminator
Copy link

I faced the same problem and for me the solution was to turn off the debug mode on the real device and after that the onNotification method started working.

How did you do that?

It doesn't work on simulator and when you use debug mode.

@littlecircle0730
Copy link

@SazzadIp Your solution works and it's a good one also I tried without framework changes and it's working on that case also. You only need to add below code will also works.

Add this code in below file.
AppDelegate.m

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

if (launchOptions != nil)
{
NSDictionary* userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (userInfo != nil)
{
[self performSelector:@selector(callNotification:) withObject: userInfo afterDelay:10];
}
}

.................
}

create new file methods in same class....

-(void) callNotification: (NSDictionary*) userInfo {
[RNCPushNotificationIOS didReceiveRemoteNotification:userInfo];
}

It doesn't work for me.
I tried to open a local push notification.
Everything works fine if I put the app in the foreground or background but does not work when I killed the app.

@Dallas62
Copy link
Collaborator

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests