Since iOS 10 and with the UserNotifications framework, detecting wether the user launched the app organically or from a local/remote notification is a bit different than before.
Let’s say I’ve to send an event to my analytics service when user launches the app, I do this using one of these three calls:
- Analytics.trackAppLaunched(source: .organic)
- Analytics.trackAppLaunched(source: .localNotification)
- Analytics.trackAppLaunched(source: .remoteNotification)
I have a NotificationController class that will be the UNUserNotificationCenter delegate. After experimenting a bit with it, I noticed that userNotificationCenter(:didReceive:withCompletionHandler:) is called after application(:didLaunchWithOptions:) but before applicationDidBecomeActive(_:).
In order to not send the event multiple times, we simply need to set a flag when we handle a notification during launch, I called it handledLaunchAnalytics.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func applicationDidBecomeActive(_ application: UIApplication) { | |
let notificationController = NotificationController.shared | |
// Track app launch if the notificationController didn't already do it | |
if !notificationController.handledLaunchAnalytics { | |
Analytics.trackAppLaunched(source: .Organic) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private(set) var handledLaunchAnalytics: Bool = false | |
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { | |
let atAppLaunch: Bool = (UIApplication.shared.applicationState != .active) | |
let request: UNNotificationRequest = response.notification.request | |
if let trigger = request.trigger, trigger is UNPushNotificationTrigger { | |
// if atAppLaunch == true, call Analytics.trackAppLaunched(source: .remoteNotification) | |
// and flag handledLaunchAnalytics as true | |
// then you can handle your remote notification here | |
} else { | |
// if atAppLaunch == true, call Analytics.trackAppLaunched(source: .localNotification) | |
// and flag handledLaunchAnalytics as true | |
// then you can handle your local notification here | |
} | |
completionHandler() | |
} |
Let’s just not forget to reset handledLaunchAnalytics when the app is going back to background.
If you know of a better way for doing this, I would be happy to hear about you!