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

When iOS removes the App from memory, the first push notification user taps is not sent correctly to the App by the plugin #803

Open
5 tasks done
rideo-eduardmorales opened this issue May 10, 2023 · 0 comments

Comments

@rideo-eduardmorales
Copy link

rideo-eduardmorales commented May 10, 2023

Checklist

  • I have read the issue reporting guidelines
  • I confirm this is a suspected bug or issue that will affect other users
  • I have reproduced the issue using the example project or provided the necessary information to reproduce the issue.
  • I have read the documentation thoroughly and it does not help solve my issue.
  • I have checked that no similar issues (open or closed) already exist.

Current behavior:
It happens when iOS removes the App from memory. It that case, the App and plugin don't behave like a "regular cold boot" (where the push notification is handled correctly), or a regular "app resume" (it also works OK). In this "removed from memory" scenario (as we call it), the plugin sends the sendNotification before the App executes the bootstrap (located in the app.component.ts constructor), so the push notification is lost, and the app never gets it. Then, if the user taps on another App push notification in the system tray, since the App has already been bootstrapped, everything works OK again.

Expected behavior:
When iOS has removed the App from memory, the first push notification the user taps from the system tray, has to be passed correctly from the plugin to the App.

Steps to reproduce:
It's a bit tricky to reproduce, since to force iOS to remove the App from memory, we minimize our App, open like 10 other apps (i.e. feedly, google maps, photos, etc.), and then tap a push notification in the system tray to open our App again. It's clearly visible when iOS had removed the App from memory, since there will be a short delay, no splash screen is shown but the app starts from the homepage again.
In this "removed from memory" state, to see the logs, we use Xcode > Devices > Console, and, when we have opened these 10 other apps, we press "pause" and "play" in Xcode console to restore the log stream, since when the App is removed from memory, it also closes the console stream to Xcode.

Environment information

  • Cordova CLI version
    • 11.0.0
  • Cordova platform version
  • Plugins & versions installed in project (including this plugin)
    • cordova-plugin-firebasex Version 16.0.0
  • Dev machine OS and version
    • OSX
      • 13.3.1
  • Device details
    • iPhone XR
  • OS details
    • iOS 16
  • Node JS version
    • 16.14.0
  • XCode version
    • 13

Related code:
We are no experts in Objective C, but we have tried to modify "AppDelegate+FirebasePlugin.m" adding a semaphore to avoid sendNotification in FirebasePlugin.m to be called before the App has been bootstrapped after iOS removed it from memory. The idea was to wait until the app is in foreground, and then resume the process, but, although it looks to have improved a bit, it still fails sometimes, and we don't know why.

The changes we have tried are:

AppDelegate+FirebasePlugin.m:410

Change this:

        mutableUserInfo = [response.notification.request.content.userInfo mutableCopy];
        
        NSString* tap;
        if([self.applicationInBackground isEqual:[NSNumber numberWithBool:YES]]){
            tap = @"background";
        }else{
            tap = @"foreground";
            
        }
        [mutableUserInfo setValue:tap forKey:@"tap"];

to this:

       mutableUserInfo = [response.notification.request.content.userInfo mutableCopy];

        // START fix
        NSLog(@":::AppDelegate+FirebasePlugin.m, before delay %d", [self.applicationInBackground isEqual:[NSNumber numberWithBool:YES]]);

        // Add delay to avoid the following semaphore to break app resume
        NSLog(@":::AppDelegate+FirebasePlugin.m:delay start");
        double delayInSeconds = 1;
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            NSString* tap;
            NSLog(@":::AppDelegate+FirebasePlugin.m:delay end");

            // Semaphore to avoid sending the notification before the App has bootstrapped after iOS removed it from memory (TBF-45)
            dispatch_semaphore_t sema = dispatch_semaphore_create(0);
            [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillEnterForegroundNotification
                object:nil
                queue:nil
                usingBlock:^(NSNotification *note) {
                    dispatch_semaphore_signal(sema);
                }];
            while (self.applicationInBackground == @(YES)) {
                dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
            }
            [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillEnterForegroundNotification object:nil];

            tap = @"foreground";

            // Remove the original conditional since the semaphore waits for the app to be in foreground
//             if([self.applicationInBackground isEqual:[NSNumber numberWithBool:YES]]){
//                 tap = @"background";
//             }else{
//                 tap = @"foreground";
//             }

            NSLog(@":::AppDelegate+FirebasePlugin.m after delay %d", [self.applicationInBackground isEqual:[NSNumber numberWithBool:YES]]);
            // END fix

            [mutableUserInfo setValue:tap forKey:@"tap"];

And add logs to see when these methods are called in
FirebasePlugin.m:523

- (void)onMessageReceived:(CDVInvokedUrlCommand *)command {
    NSLog(@":::FirebasePlugin.m:onMessageReceived");
    ...
}

FirebasePlugin.m:572

- (void)sendNotification:(NSDictionary *)userInfo {
    NSLog(@":::FirebasePlugin.m:sendNotification");
        ...
}
@rideo-eduardmorales rideo-eduardmorales changed the title When iOS removes the App from memory, the first push notification user taps, is not sent to the App correctly by the plugin When iOS removes the App from memory, the first push notification user taps is not sent to the App correctly by the plugin May 11, 2023
@rideo-eduardmorales rideo-eduardmorales changed the title When iOS removes the App from memory, the first push notification user taps is not sent to the App correctly by the plugin When iOS removes the App from memory, the first push notification user taps is not sent correctly to the App by the plugin May 11, 2023
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

1 participant