phonegap / phonegap-plugin-push

Register and receive push notifications
MIT License
1.94k stars 1.91k forks source link

Receive Notifications in Background #93

Closed christocracy closed 9 years ago

christocracy commented 9 years ago

This plugin is unable to receive notifications while in the background since it doesn't implement application:didReceiveRemoteNotification:fetchCompletionHandler:

Discussion

Use this method to process incoming remote notifications for your app. Unlike the application:didReceiveRemoteNotification: method, which is called only when your app is running in >the foreground, the system calls this method when your app is running in the foreground or background

Clearly this logic in didReceiveRemoteNotification is useless, since that method is only called in the foreground.

    if (appState == UIApplicationStateActive) {   // <-- Will always be true.
        PushPlugin *pushHandler = [self getCommandInstance:@"PushNotification"];
        pushHandler.notificationMessage = userInfo;
        pushHandler.isInline = YES;
        [pushHandler notificationReceived];
    } else {
        //save it for later
        self.launchNotification = userInfo;
    }
greg84 commented 9 years ago

I've been debugging this with xcode. The else block is hit when the application is started as a result of the user tapping a notification when the app is not in the foreground (i.e. in the task switcher). In this case the plugin invokes the javascript 'notification' event callback with details of the push message when the init method is called.

Out of interest, do you know if implementing the fetchCompletionHandler variant of this method would allow javascript to run inside the Cordova web view when the app is started in the background?

As a side note, after the app is force quit (double tap home, swipe up) and the device is locked, tapping a notification will bypass the didReceiveRemoteNotification event completely. Although this seems to be by design - see #50.

christocracy commented 9 years ago

I created a cordova plugin some time ago when using UrbanAirship to receive notifications in the background.

Implementing the fetchCompletionHandler variant does allow Javascript to run when the app is started in the background.

The important thing is that one must allow Javascript to signal the end of the fetchCompletionHandler, since one's push-callback might to an async xhr request to their server.

For example:

var pushPlugin = window.PushNotification;

pushPlugin.on('notification', function(data) {
    // do stuff with data
   .
   .
   .
   // Execute an Async xhr
   $.post({
       url: 'foo.com',
       callback: function() {
           pushPlugin.finish();  // <-- signal to native code that our task is complete.
       }
   });
});
cmartin81 commented 9 years ago

+1 for this feature

macdonst commented 9 years ago

@christocracy please feel free to send a PR with this functionality.

christocracy commented 9 years ago

When PhoneGap fixes their plugin and stops including static jar files (eg android-support-v4.jar), breaking other peoples' plugins, I'll consider contributing a PR.

cmartin81 commented 9 years ago

Are there any other good plugins for push I can use that does not break other plugins?

macdonst commented 9 years ago

@christocracy I'm in a bit a bind right now as PhoneGap build which I need to support does not support gradle yet. Once it does I already have a commit to make the change. I'd love for you to participate in this plugin. So if you can contribute code that would be great.

@cmartin81 I'd say this one is your best bet and I will resolve this compilation issue as quickly as I can.

christocracy commented 9 years ago

@macdonst When might PGB support gradle? It won't be soon enough, I'm afraid. I'm so tired of providing support for PGB users of my products.

Until PGB supports gradle, I strongly recommend my customers against using PhoneGap and point them towards more advanced build-services which do support grade, such as CloudFive

slorber commented 9 years ago

@christocracy what exactly do you mean by "receive notifications while in the background"?

Because on this issue I notice I can receive notifications only when the app is in foreground. When the app is closed or not in the foreground, nothing happens at all.

I don't know if this is what this issue is about but for me this is not an enhancement but a bug as it makes the plugin barely unusable :'(

christocracy commented 9 years ago

For ios in particular, an app can receive a push notification while the app is in the background. iOS can awaken the app in the background and provide exactly 30s of background running-time.

But only if the push-plugin implements the application:didReceiveRemoteNotification:fetchCompletionHandler: method variant

This plugin does not implement this variant thus an iOS app cannot be awakened in the background due to a push request.

An example usage of this feature could be a server which desires to know the geolocation of a device or devices. The server could send a silent "where are you?" push-request with a JSON-body only (e.g.: {"action":"getCurrentPosition"}). The app on the device would awaken, decode the JSON-body and choose to fetch the device's current-position and send it back to the server.

This is how Apple's "Find Friends" app works.

slorber commented 9 years ago

Ok so that seems nice for background sync but it may not be related to my problem :) thanks

larsar commented 9 years ago

+1

berndartmueller commented 9 years ago

Does this mean that right now this plugin can not handle push notifications when app is in background?

christocracy commented 9 years ago

Without a doubt, this plugin can only receive a Push notification while running in the foreground.

On Saturday, September 5, 2015, Bernd Artmüller notifications@github.com wrote:

Does this mean that right now this plugin can not handle push notifications when app is in background?

— Reply to this email directly or view it on GitHub https://github.com/phonegap/phonegap-plugin-push/issues/93#issuecomment-137955991 .

Snet form Gmail Mobile

berndartmueller commented 9 years ago

Hmm, is there a simple way to fix this myself? I tried to enable "Remote notifications" but that did not work.

christocracy commented 9 years ago

No simple way. It needs an obj-c method implemented including some careful handling of the completionHandler callback, as I clearly documented above, including an example usage from one of my plugins.

berndartmueller commented 9 years ago

Ok, but the deprecated plugin https://github.com/phonegap-build/PushPlugin also does not implement the "application:didReceiveRemoteNotification:fetchCompletionHandler:" method, nevertheless background notifications are working.

christocracy commented 9 years ago

You're not understanding.

Speaking of iOS, in particular, With your app running in background, you will see a notification appear, of course. This is done automatically by the OS.

However, your JavaScript callback is not being executed. What if the push notification has a JSON payload that your app needs to decode and respond-to?

The JavaScript callback cannot be executed in the background with this plugin.

On Saturday, September 5, 2015, Bernd Artmüller notifications@github.com wrote:

Ok, but the deprecated plugin https://github.com/phonegap-build/PushPlugin also does not implement the "application:didReceiveRemoteNotification:fetchCompletionHandler:" method, nevertheless background notifications are working.

— Reply to this email directly or view it on GitHub https://github.com/phonegap/phonegap-plugin-push/issues/93#issuecomment-137958359 .

Snet form Gmail Mobile

berndartmueller commented 9 years ago

Oh sorry, then we are talking about different things. I'm sending push notifications to my unlocked iOS device (app is in background) and would like them to display with a banner. iOS receives the notification but does not display it with a banner (like WhatsApp).

christocracy commented 9 years ago

If you want to execute a js callback in background due to push, this plugin won't do it

On Saturday, September 5, 2015, Bernd Artmüller notifications@github.com wrote:

Oh sorry, then we are talking about different things. I'm sending push notifications to my unlocked iOS device (app is in background) and would like them to display with a banner. iOS receives the notification but does not display it with a banner (like WhatsApp).

— Reply to this email directly or view it on GitHub https://github.com/phonegap/phonegap-plugin-push/issues/93#issuecomment-137959991 .

Snet form Gmail Mobile

slorber commented 9 years ago

@christocracy I'm trying to understand a little better to know if issue #109 is a duplicate or not

I'm thinking of different usecases:

Receiving notifications in foreground:

No problem here.

Receiving notification in background and notification to the user:

When the user clicks on the notification, the app should open and the notification callback be triggered.

Receiving notification in background, and executing callback while still in background

As far as I understand this is your usecase no? I understand that you want to be able to run js code for 30 seconds inside the Cordova app, without even putting this app in foreground.

I think #109 is more about the 2nd case, as the user mention he "opens the app" while you never open the app in your usecase

christocracy commented 9 years ago

My concern is use-case #3.

On Monday, September 7, 2015, Sébastien Lorber notifications@github.com wrote:

@christocracy https://github.com/christocracy I'm trying to understand a little better to know if issue #109 https://github.com/phonegap/phonegap-plugin-push/issues/109 is a duplicate or not

I'm thinking of different usecases: Receiving notifications in foreground:

No problem here. Receiving notification in background and notification to the user:

When the user clicks on the notification, the app should open and the notification callback be triggered. Receiving notification in background, and executing callback while still in background

As far as I understand this is your usecase no? I understand that you want to be able to run js code for 30 seconds inside the Cordova app, without even putting this app in foreground.

I think #109 https://github.com/phonegap/phonegap-plugin-push/issues/109 is more about the 2nd case, as the user mention he "opens the app" while you never open the app in your usecase

— Reply to this email directly or view it on GitHub https://github.com/phonegap/phonegap-plugin-push/issues/93#issuecomment-138254852 .

Snet form Gmail Mobile

alexislg2 commented 9 years ago

Concern of https://github.com/phonegap/phonegap-plugin-push/issues/109 is indeed use-case 2. https://github.com/phonegap/phonegap-plugin-push/issues/109 is therefore not a duplicate of https://github.com/phonegap/phonegap-plugin-push/issues/93

AndersNederhoed commented 9 years ago

+1

cmellinas commented 9 years ago

+1

GabrielFerraz commented 9 years ago

+1

ghost commented 9 years ago

+1 any advance on this issue

christocracy commented 9 years ago

Crickets is all you'll get from @phonegap. I clearly described exactly what needs to be done.

I could implement it in 3 hours but I'm not touching this plugin until they support grade and stop including static jars.

fredgalvao commented 9 years ago

It does now, @christocracy . Since https://github.com/phonegap/phonegap-plugin-push/commit/6b5bebb85c94cca0a734c743b37a50fccc57c8c7, this project has been enabled to work with gradle dependencies properly, so if that was the only concern blocking this feature, we're on our way to freedom :smile:

slorber commented 9 years ago

@christocracy

About your code snippet

var pushPlugin = window.PushNotification;

pushPlugin.on('notification', function(data) {
    // do stuff with data
   .
   .
   .
   // Execute an Async xhr
   $.post({
       url: 'foo.com',
       callback: function() {
           pushPlugin.finish();  // <-- signal to native code that our task is complete.
       }
   });
});

As far as I understand, this feature may allow that callback to run into the background.

Maybe we should use another separate callback then no?

Having stuff running in the background does it mean there's nothing to be shawn in status bar? If there is still something to be shawn in status bar, when user clicks on that notification isn't it supposed to run the "notification" callback (thus making it run twice?)

Just an idea, but IMHO I think there should be a separate callback. To prevent concurrency issues I think the callback should provide a mean to tell the plugin the end (not global pushPlugin.finish())

Also the callback could provide the absility to tell the plugin wether or not this notification has been totally handled in the background (ie weither or not we should show something in the status bar). Maybe we should not show the statusbar notification until the done() method has been called.

In the end something like that:

var pushPlugin = window.PushNotification;

pushPlugin.on('backgroundNotification', function(data,doneCallback) {
   $.post({
       url: 'foo.com',
       callback: function() {
           // use showInStatusBar: false if all the stuff has been done in background and you don't want the user to be notified at all
           doneCallback({ showInStatusBar: true });
       }
   });
});

pushPlugin.on('notification', function(data) {
    // do stuff with data
});

Just some ideas, I don't really know how it works on iOS so....

cmartin81 commented 9 years ago

In my case I want to check if the user is still logged in and display a local notification with content that is fetched from the server (and not display a message if the user is signed out).

I agree that we should have a separate method for backgroundNotification.

fredgalvao commented 9 years ago

@slorber 's approach seems reasonable. +1 on that. Such an event and feature would make me not need to edit GCMIntentService.java with some custom code of mine and also make my new custom code work on both ios and android. I'm looking foward to that!

garrettlangley commented 9 years ago

@macdonst what is the expected timeline for this fix?

GabrielePrestifilippo commented 9 years ago

+1

armellarcier commented 9 years ago

+1

dabaaaz commented 9 years ago

+1

VincentPuget commented 9 years ago

+1

cmartin81 commented 9 years ago

I am really looking forward to this fix!

silasakk commented 9 years ago

+1

kales0 commented 9 years ago

+1 !

uriva commented 9 years ago

+1

elliotdennis commented 9 years ago

+1

ramyacl commented 9 years ago
      -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary*)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{}

How to call the above method in ios?

VioletaCalvo commented 9 years ago

+1

macdonst commented 9 years ago

It's coming, pull branch issue93 if you want to test. You'll need to send "content-available: 1" in your "aps" payload.

christocracy commented 9 years ago

93 is Looking good :)

GabrielePrestifilippo commented 9 years ago

With #93, is it working just on iOS or also with Android?

macdonst commented 9 years ago

@GabrielePrestifilippo yeah, it will work with iOS and Android. I need to document it.

macdonst commented 9 years ago

@christocracy cool, thanks for the review. I need to clean it up but I hope to have it out by Monday.

silasakk commented 9 years ago

android cannot trigger notification when background process but ios OK push.on('notification', function (data) {

});