My app doesn't receive GCM push notifications if it has been in the background for a long time (ex: overnight). If the app is restarted (double tap home, swipe away, restart app) then the queued messages get delivered.
Our app receives a data payload, and then constructs an iOS local notification with the contents of the payload.
It is working for the following scenarios: app in foreground, app in background (hit home button), app is killed (double tap home, swipe away app).
Payload
{
"data": {
"title":"Test Title",
"message": "Message body",
},
"content_available":true,
"priority": "high"
}
Why would it work if the app is killed but not when it's been in the background for a long time. Is it a difference between the app being terminated vs suspended?
Okay I did some testing and here's what appears to be happening.
Test cases
note: We were doing some things that GCM doesn't do in their in their example. We connect to GCM on app startup (not applicationDidBecomeActive and we do not disconnect from GCM during applicationDidEnterBackground)
App in background, device is not awake
trigger GCM message, nothing happens
when device is woken (press hold button), didReceiveRemoteNotification gets called, which creates a local notification
App is killed (double tap home, swipe app away), device is not awake
trigger GCM message, nothing happens
when device is woken, the apps didFinishLaunchingWithOptions executes
because we were connecting to GCM here, it also calls didReceiveRemoteNotification
So why doesn't it work when the app is in the background for a long time?
My theory is GCM sets up some background task when it's set up for the first time. This background task listens for GCM messages and executes didFinishLaunchingWithOptions if the app is terminated. However when an app is suspended, it can be terminated without warning. If this happens I theorize that this background task for whatever fails to execute, and since the app is terminated there's no connection to GCM.
Solution
Probably use the (ctrl-f) Hybrid messages with both notification and data payload
Related
Can FCM silent notification start up a closed iOS app?
Request Type: POST
Request URL: https://fcm.googleapis.com/fcm/send
Request Headers:
Authorization -> key=MY_KEY
Content-Type -> application/json
Request Body:
{
"to": "/topics/my_topic",
"content_available": true,
"data": {
"contentAvailable": 1
},
"priority": 10
}
However, this payload does not start up my iOS app if the user closes it.
How to make the iOS to start my app whenever a silent notification is received?
It's the expected behavior to not launch the app. I mean why should it? The user for some reason has decided to kill the app. They don't want battery or bandwidth getting used for it anymore!
From documentation.
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. In addition, if you enabled the remote notifications
background mode, the system launches your app (or wakes it from the suspended state) and puts it in the background state when a remote notification arrives. However, the system does not automatically launch your app if the user has force-quit it. In that situation, the user must relaunch your app or restart the device before the system attempts to launch your app automatically again
For non-silent notifications. They would get delivered to the device. But not to the app.
If you force-quite your Whatsapp on your iPhone and your mother sends you a message, then your iPhone would show it among its notifications. However it won't trigger any of your AppDelegate methods. AppDelegate methods are only triggered if the app is not user terminated.
According to Apple's documentation on remote notifications:
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. In addition, if you enabled the remote notifications
background mode, the system launches your app (or wakes it from the
suspended state) and puts it in the background state when a remote
notification arrives. However, the system does not automatically
launch your app if the user has force-quit it. In that situation, the
user must relaunch your app or restart the device before the system
attempts to launch your app automatically again.
In my case (iOS 7.1.1) remote notification is not delivered to the app after the app was killed (swipe up from Recent Apps List) and the phone was restarted. If I open the app, notifications get delivered as expected. What am I missing?
Edit: To avoid any misunderstanding. What I expect is the following flow:
User kills the app;
User restarts the phone;
App server sends a new message;
OS attempts to launch the app and deliver the notification.
The problem is that you are a developer, and your usage is not typical. What you do: Launch the app, swipe it out, turn off the phone (not standby, but turned off), reboot, enter your passcode, make your server send a notification. That doesn't work.
For some reason, notifications sent within 90 seconds or so after rebooting the phone are not received. Wait 90 seconds, then you send the notification, and it should be received. Since there is no relation between the time the phone of the user is rebooted and the time you send the notification, this is only a problem for developers and testers, not for real users.
From the article you linked, for the method you're referencing (application:didReceiveRemoteNotification:)
If the app is not running when a remote notification arrives, the
method launches the app and provides the appropriate information in
the launch options dictionary. The app does not call this method to
handle that remote notification. Instead, your implementation of the
application:willFinishLaunchingWithOptions: or
application:didFinishLaunchingWithOptions: method needs to get the
remote notification payload data and respond appropriately.
Are you checking for your remote notification payload in the options dictionary for the will/didFinishLaunchingWithOptions:?
I couldn't find anywhere how to debug a silent remote notification.
I know that a normal remote notification can be debugged by setting the project scheme to "wait for executable to be launched" but since a silent remove notification doesn't open the app, it didn't work.
I'm also not sure which method should be called when i get a silent remote notification.
Already tried:
-application:didFinishLaunchingWithOptions
-application:didFinishLaunching
-application:didReceiveRemoteNotification
-application:didReceiveRemoteNotification:fetchCompletionHandler
-application:handleActionWithIdentifier:forRemoteNotification:completionHandler
None of these worked...
This is my payload:
{
"aps": {
"content-available": 1,
"sound":"silent.wav"}
}
Can anyone help me with that?
What's happening is you've got an incorrect payload. In order for it to be considered a silent push notification that will trigger a background fetch, the only thing allowed in the "aps" dictionary is "content-available":1. Since you have a sound, the system ignores the content-available part and sends it on as a regular notification. And since there's no "alert" portion, there's no notification to interact with and no way to launch your app. Remove the sound part and your notification will come through -application:didReceiveRemoteNotification:fetchCompletionHandler
It makes no difference if your app is running in the background or hasn't been started on the device. If the app is not running, iOS will wake it up and deliver the notification after the app launches in the background. If it's been run but it's backgrounded or it's running in the foreground, the notification will simply be delivered to your app. No matter what it still goes to the same method.
There are two other requirements for this to work:
Your device has to have background fetch enabled for your app.
You can't have killed the app manually by swiping up from the multitasking UI. If you do this, iOS will NEVER wake up the app until it is ran by the user again.
I have an app that registers itself to be woken up in the background when an APNS notification is received (i.e., the remote-notification setting for UIBackgroundModes). In the vast majority of cases this works fine. An APNS notification comes in, the app is woken up and a call to my app delegate's application:didReceiveRemoteNotification:fetchCompletionHandler: is made.
In some cases the APNS is received by the user but the app never gets woken up. It seems to only happen when the device has been inactive for a while (overnight, left behind for a weekend, etc). Once the user launches the app then everything is back to normal and subsequent APNS notifications again trigger the background wake-up.
Does anybody have an idea about what could trigger this?
My app is receiving remote notifications (APNS) and is working for all the common scenarios:
App is not running (didFinishLaunchingWithOptions:)
App is running and active (didReceiveRemoteNotification:)
App is running, the phone is locked and I unlock the device as soon as I get the notification (didReceiveRemoteNotification:)
However, not if I in the last case choose not to unlock the device immediately (with the slider) and I wait until the screen goes black again. The message/notification is still shown in the lock screen, but the slider can now only unlock the device and when I do, didReceiveRemoteNotification: doesn't get called at all.
I’m afraid this is the intended behaviour. Quote the Local and Push Notification Programming Guide, part Scheduling, Registering, and Handling Notifications:
If the action button is tapped (…), the system launches the
application and the application calls its delegate’s
application:didFinishLaunchingWithOptions: method (…); it passes in
the notification payload (…). If the application icon is tapped (…),
the application calls the same method, but furnishes no information
about the notification.