Keywords: iOS Push Notifications | App Lifecycle | UIApplicationDelegate
Abstract: This article provides a comprehensive guide on detecting whether an iOS app was launched or opened from a push notification. It covers the complete detection scheme from cold launch to background wake-up by analyzing the app lifecycle and UIApplicationDelegate methods. Based on high-scoring Stack Overflow answers with supplementary information, it offers practical code examples and best practice recommendations.
In iOS app development, accurately detecting whether an app was launched from a push notification is a common but error-prone requirement. This article explains in detail how to implement this functionality in different app states based on the UIApplicationDelegate protocol.
App Lifecycle and Push Notifications
Understanding the iOS app lifecycle is essential for correctly handling push notification launch detection. An app can be in several states: completely closed (cold launch), suspended in the background, or running in the foreground. The arrival of push notifications and user interactions trigger different delegate methods.
Detection During Cold Launch
When the app is completely closed (either terminated by the system or manually by the user), tapping a push notification triggers a cold launch. In this case, the application:didFinishLaunchingWithOptions: method is called, and the launchOptions parameter contains the push notification information.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if (launchOptions != nil) {
NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification) {
NSLog(@"App launched from remote push notification");
// Handle push notification logic
[self handleNotification:notification];
}
}
return YES;
}
For local push notifications, use the UIApplicationLaunchOptionsLocalNotificationKey key to retrieve the notification information. This approach applies when the app is relaunched via push notification after being terminated by the system or manually killed by the user.
Detection During Background Wake-up
When the app is running in the background, tapping a push notification wakes up the app and brings it to the foreground. In this scenario, application:didFinishLaunchingWithOptions: is not called; instead, the application:didReceiveRemoteNotification: method is triggered.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
if (application.applicationState == UIApplicationStateInactive || application.applicationState == UIApplicationStateBackground) {
NSLog(@"App opened from push notification while in background");
// Handle push notification logic
[self handleNotification:userInfo];
}
}
By checking the application.applicationState property, you can distinguish whether the app received the notification while in the foreground (UIApplicationStateActive) or was opened from the background via notification (UIApplicationStateInactive or UIApplicationStateBackground). For local push notifications, the corresponding delegate method is application:didReceiveLocalNotification:.
Complete Lifecycle Handling Solution
In practical development, more complex scenarios need to be handled. According to testing, the sequence of app lifecycle method calls in iOS 10 and above is as follows:
- Opening from push after system termination:
didFinishLaunchingWithOptions(with options) →didReceiveRemoteNotification:fetchCompletionHandler:(background mode) →applicationWillEnterForeground→didReceiveRemoteNotification:(inactive state) →applicationDidBecomeActive - Opening from push after user kill:
didFinishLaunchingWithOptions(with options) →didReceiveRemoteNotification:(completion handler version only) →applicationDidBecomeActive - Opening from push while in background:
didReceiveRemoteNotification:fetchCompletionHandler:(background mode) →applicationWillEnterForeground→didReceiveRemoteNotification:(inactive state) →applicationDidBecomeActive
A robust implementation requires maintaining state variables in the AppDelegate to track push notification information:
@interface AppDelegate ()
@property (nonatomic, strong) NSDictionary *notificationUserInfo;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.notificationUserInfo = nil;
if (launchOptions != nil) {
NSDictionary *notification = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (notification) {
self.notificationUserInfo = notification;
}
}
return YES;
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
self.notificationUserInfo = nil;
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
if (application.applicationState == UIApplicationStateInactive) {
self.notificationUserInfo = userInfo;
}
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
if (self.notificationUserInfo) {
[self openViewFromNotification:self.notificationUserInfo];
self.notificationUserInfo = nil;
}
}
- (void)openViewFromNotification:(NSDictionary *)userInfo {
// Open the appropriate view based on push notification content
NSLog(@"Opening view from push notification: %@", userInfo);
}
@end
Handling Special Cases
One special case to note: when the app is running in the foreground and the user is viewing it via the app switcher, if a push notification is received at this moment, only the didReceiveRemoteNotification: method is called, while applicationWillEnterForeground and didFinishLaunchingWithOptions are not invoked. In this scenario, additional state management is required to ensure proper handling.
Best Practice Recommendations
- Always handle the final response logic for push notifications in
applicationDidBecomeActive, as this is when the app truly becomes active. - Use state variables to track push notification information to avoid logical errors in the complex sequence of lifecycle method calls.
- For push notifications requiring background refresh, implement the
application:didReceiveRemoteNotification:fetchCompletionHandler:method. - Test all possible scenarios: push notification handling in cold launch, warm launch, background suspension, foreground running, etc.
Through the methods described above, developers can accurately detect whether an iOS app was launched from a push notification and execute corresponding business logic based on different app states and push types.