I'm developing an app that can receive push notifications which, in some circumstances, trigger background fetch operations. Therefore, I've enabled the remote-notification
background capability for my app.
When the app is suspended, push notifications cause the app to wake up and execute application:didReceiveRemoteNotification:fetchCompletionHandler
, the banner appears on the homescreen, and the notification remains in the Notification Center until the user taps it to launch the app. It works exactly as it should.
When the app is not running, a notification will launch the app as long as it was not force-quit by a user (see apple's documentation), and the app executes application:didFinishLaunchingWithOptions
and application:didReceiveRemoteNotification:fetchCompletionHandler
. The banner appears over the homescreen, but then the notification disappears. It does not remain in the Notification Center. Furthermore, if the device is locked, sometimes the notification disappears before it even finishes making the alert sound.
Interestingly, if I disable the remote notification background mode, everything works fine. In that situation, the app is not launched when the push notification arrives.
How can I prevent the notifications from disappearing when remote notification background mode is on, and an incoming notification launches the not-running app? Do I need to include something in application:didFinishLaunchingWithOptions
that lets the app know it's being launched in the background, and the notification shouldn't be discarded?
It seems like the push notifications were disappearing because when the app was launched in the background and executed application:didFinishLaunchingWithOptions:
it was re-registering for remote notifications. Re-registering seems to discard any queued messages.
My solution was to check if the app was being launched in the background due to a push notification before calling the push registration method. I'm using the Kinvey SDK, so the following code uses Kinvey's methods, but I strongly suspect this solution will apply to other push registration methods, including the standard UIApplication.registerForRemoteNotifications
.
The code that was causing my problem was:
func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
// Initialize Kinvey SDK singleton
KCSClient.sharedClient().initializeKinveyServiceForAppKey("myappid",
withAppSecret: "mysecret",
usingOptions: nil)
KCSPush.registerForPush()
// rest of method...
}
I solved the problem by changing it to:
func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
// Initialize Kinvey SDK singleton
KCSClient.sharedClient().initializeKinveyServiceForAppKey("myappid",
withAppSecret: "mysecret",
usingOptions: nil)
if let _ =
launchOptions?[UIApplicationLaunchOptionsRemoteNotificationKey] as? NSDictionary {
let appState: UIApplicationState = UIApplication.sharedApplication().applicationState
if appState == .Active || appState == .Inactive {
KCSPush.registerForPush()
}
} else {
KCSPush.registerForPush()
}
// rest of method...
}
Now when an app is launched into the background by an incoming push notification, it doesn't re-register for push, and the notification remains in the iOS Notification Center until the user taps it or launches the app manually.
I tried NOT registering for notifications in the event that the app is in the background, as proposed by the accepted answer here, but it did not fix this issue for me. I found that manually setting the application badge number was causing the notifications to disappear.
I had code in application:didFinishLaunchingWithOptions:
that checked the status of the user and would (amongst other things) either set the badge icon to 0 if there was no active user, or set it to a value I had saved in NSUserDefaults
in the event that there was an active user. Turns out that either one of these lines will cause the notification to disappear and stop playing the notification sound almost immediately. The reason it did not happen on subsequent pushes is because didFinishLaunching
was not being called again for quite a while.
tl;dr - Check to make sure you're not manually setting the application badge icon in any of the app lifecycle methods, or in didReceiveRemoteNotification
. If your notifications are only disappearing on the first received, take a real close look at didFinishLaunching
.