Leanplum's user guides and developer documentation.

Leanplum Documentation

Leanplum's user guides, SDK setup, API docs, and more resources are here to help you get the most out of A/B testing, Campaigns, Messaging, and Analytics.

Custom push notification swizzling for iOS

about a year ago by Mayank Sanganeria

By default, Leanplum's iOS SDK uses method swizzling to collect push tokens. If your iOS app has multiple different SDKs installed that attempt to swizzle the push methods, it can cause problems where some push notification methods are not called.

To avoid issues collecting push tokens, you can disable automatic method swizzling for push notification methods and call the Leanplum push notification methods manually.

Set up push token collection manually

Here are the steps to call the push methods without swizzling:

  1. Disable swizzling by putting a boolean flag for LeanplumSwizzlingEnabled in your app Info.plist to NO.
  2. Make sure the following methods are present in your AppDelegate.m file. Make sure to call the corresponding method on the Leanplum object.
// At minimum:
+ (void)application:(UIApplication *) didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)token;
+ (void)application:(UIApplication *) didFailToRegisterForRemoteNotificationsWithError:(NSError *)error;
+ (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;

// Optional:
+ (void)application:(UIApplication *) didRegisterUserNotificationSettings:(UIUserNotificationSettings*) notificationSettings;
+ (void)application:(UIApplication *) didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler API_AVAILABLE(ios(10.0));
+ (void)application:(UIApplication *) didReceiveLocalNotification:(UILocalNotification *)localNotification;
// At minimum:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error)

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)


// Optional:
func application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings)
func application(_ application: UIApplication, 
didReceiveRemoteNotification userInfo: [AnyHashable : Any])
func application(_ application: UIApplication, 
               didReceive notification: UILocalNotification)

Here’s a sample implementation:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    // Needs to be called if swizzling is disabled in Info.plist otherwise it won’t affect SDK if swizzling is enabled.
  
      void (^leanplumCompletionHandler)(LeanplumUIBackgroundFetchResult) =  ^(LeanplumUIBackgroundFetchResult result) {
        UIBackgroundFetchResult r = result;
        completionHandler(r);
    };
  
    [Leanplum didReceiveRemoteNotification:userInfo 
fetchCompletionHandler:leanplumCompletionHandler];
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    // Needs to be called if swizzling is disabled in Info.plist otherwise it won’t affect SDK if swizzling is enabled.
    [Leanplum didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
    // Needs to be called if swizzling is disabled in Info.plist otherwise it won’t affect SDK if swizzling is enabled.
    [Leanplum didFailToRegisterForRemoteNotificationsWithError:error];
}
// Implement didReceiveRemoteNotification with completion handler.
// Implementing (didReceiveRemoteNotification userInfo: [AnyHashable : Any]) could lead to action not working when the app is not already running
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
  
    let leanplumCompletionHandler: LeanplumFetchCompletionBlock = { (lpBlock:LeanplumUIBackgroundFetchResult) in
     let result:UIBackgroundFetchResult = UIBackgroundFetchResult.init(rawValue: lpBlock) ?? .noData
                                                   
     completionHandler(result)
    }
  
    Leanplum.didReceiveRemoteNotification(userInfo, fetchCompletionHandler: leanplumCompletionHandler)
}

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    // Needs to be called if swizzling is disabled in Info.plist otherwise it won’t affect SDK if swizzling is enabled.
    Leanplum.didRegisterForRemoteNotifications(withDeviceToken: deviceToken)
}

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    // Needs to be called if swizzling is disabled in Info.plist otherwise it won’t affect SDK if swizzling is enabled.
    Leanplum.didFailToRegisterForRemoteNotificationsWithError(error)
}

If you are using UNUserNotificationCenter, you need to call the Leanplum didReceive method, so the notification is handled:

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler
{
    [Leanplum didReceiveNotificationResponse:response withCompletionHandler:completionHandler];
}
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
   Leanplum.didReceive(response, withCompletionHandler: completionHandler)
}