“Swizzling” is a technique that Marketing Cloud Personalization can use to automatically listen for info it needs to support Personalization features you’ve enabled. Swizzling eliminates the need for you to manually forward info to Personalization via API calls.
What Personalization Swizzles
Open URL for Testing
See handleOpenURL: for details. Your app must still declare one of the iOS open-URL delegate methods to allow Personalization to ‘listen’ as well.
For more information, see setAPNSToken:. Your app must still declare the delegate method to allow Personalization to “listen” as well.
Firebase token
For more information, see setFirebaseToken:. Your app must still declare the delegate method to allow Personalization to “listen” as well.
Notification received
For more information, see handleNotification:actionIdentifier:. Your app must still declare one of the iOS notification-received methods to allow Personalization to “listen” as well.
viewDidAppear: and viewWillDisappear:. To manage the lifecycle of the associated [UIViewController(Evergage) evergageScreen], stopping view time tracking and releasing resources as appropriate.
This swizzling currently cannot be disabled.
iOS unfortunately does not enforce classes to call [super viewDidAppear:] and [super viewWillDisappear:], despite documentation stating “you must call super at some point in your implementation”. Be sure your classes comply.
Important
Swizzle Safety
Personalization takes care to swizzle safely:
Personalization will only extend found methods - If your app isn’t declaring some method to discover information, Personalization won’t add a listener for you. While this approach may require slightly more app code, it makes clear what Personalization can listen to, and avoids potential issues where adding a new method could change behavior (for example, adding a higher-priority callback resulting in some other callback not getting called at all).
Swizzle exactly once, using dispatch_once
For static classes, swizzle in a category’s +load method
For dynamic delegate classes discovered at runtime:
If the delegate already exists, Personalization dispatch_once swizzles the delegate class
Otherwise, Personalization dispatch_once swizzles setDelegate:. When Personalization sees the first non-nil delegate, it dispatch_once swizzles the delegate class
Personalization only ever swizzles the first non-nil delegate. This measure We noticed some other 3rd party libraries replacing a delegate with a proxy to the original delegate, and swizzling both classes led to double-processing.
Swizzle Code
Below you can see a simplified version of how Personalization swizzles a method. Personalization also takes precautions to try or catch NSExceptions, etc.
1@implementation SomeClass (Evergage)2+ (void)load {3 static dispatch_once_t onceToken;4 dispatch_once(&onceToken, ^{5 __block IMP originalIMP = [EVGSwizzler replaceMethod:@selector(someMethod:) inClass:[self class] withBlock:^(id _self, id someParam) {6 // Call original implementation:7 ((void(*)(id,SEL,id))originalIMP)(_self, @selector(someMethod:), someParam);89 // ... Personalization processing ...10 }];11 });12}13@end1415@implementation EVGSwizzler16+ (nullable IMP)replaceMethod:(nonnull SEL)selector inClass:(nonnull Class)cls withBlock:(nonnull id)block {17 // Finds method on this class or superclass18 Method originalMethod = class_getInstanceMethod(cls, selector);19 if (!originalMethod) {20 // No orignal method found, abort21 return nil;22 }2324 IMP originalIMP = method_getImplementation(originalMethod);25 if (!originalIMP) {26 // No original implementation found, abort27 return nil;28 }2930 // Replaces the implementation with the block, which calls the returned original implementation31 IMP newIMP = imp_implementationWithBlock(block);32 class_replaceMethod(cls, selector, newIMP, method_getTypeEncoding(originalMethod));33 return originalIMP;34}35@end
Other Methods
swizzlingEnabled
If swizzling is enabled for the Personalization iOS SDK.
1+ (BOOL)swizzlingEnabled
Availability
1.3.0
Discussion
Defaults to YES (enabled). To disable, add EvergageSwizzlingEnabled to the app’s Info.plist file with a boolean value of NO. See Evergage(Swizzling) for more details, including additional code you must write to forward information to Personalization.
URLs for Testing
You do not normally need to call this method, but simply ensure your UIApplicationDelegate defines an open-URL method, and add your app’s Personalization URL scheme.
handleOpenURL:
1- (BOOL)handleOpenURL:(nonnull NSURL *)url
Parameters
Parameters
Description
url
The URL that the app is opening via application:openURL:options: (iOS9+), application:openURL:sourceApplicatoin:annotation:, or application:handleOpenURL:.
Return Value
YES, if the URL was Personalization specific
Availability
1.2.0 (moved from Evergage.h)
Discussion
By default, Personalization will swizzle any of these open-URL methods you define:
application:openURL:options:
application:openURL:sourceApplication:annotation:
application:handleOpenURL:
However, if you disable swizzling in the Info.plist (see swizzlingEnabled), then you will need to manually call this method from your open-URL method.
This method enables Personalization to handle Personalization-related URLs. Used so test campaigns can easily and codelessly be managed by opening URLs in Safari on the device.
Your app must also add support for this Personalization URL scheme. For more information, see the Testing Guide.
For the URL formats below:
<URLScheme> is the Personalization-generated URL scheme for the app, which is located in the Personalization UI. To retrieve the URL scheme, select Dataset, then Settings > Sources > Apps > (this app) > URL Scheme: (format “evgxxxxx”).
<ExpID> is the ID of a specific campaign experience, which can be found in the Personalization UI. To retrieve the ExpID, select the Dataset, then Campaigns > Campaign Summary of the campaign the experience is in.
These URLs do not aggregate or combine. The most recent one determines the behavior.
Testing lasts for 30 minutes, or until the app is terminated or another test URL is entered.
There are three test URL formats:
Test All Campaigns:
1<URLScheme>://test/all
In addition to default behavior of showing mobile campaigns in the Published state, also show mobile campaigns that are in the Test state. All campaign rules will still be active.
Test a Specific Experience:
1<URLScheme>://test/<ExpId>
In addition to default behavior of showing mobile campaigns in the Published state, also show the particular experience of a mobile campaign, regardless of that campaign’s state and rules that normally determine when its shown.
Stop Testing:
1<URLScheme>://test/none
Return to the default behavior of showing mobile campaigns in the Published state only.
Typically, you don’t need to directly invoke this method. If your app uses Apple Push Notification Service (APNS), simply ensure the following:
Confirm that your app’s UIApplicationDelegate defines the method application:didRegisterForRemoteNotificationsWithDeviceToken:.
Your app calls registerForRemoteNotifications on UIApplication regularly on/after launch, as applicable (such as after the user has completed the notification onboarding process and opted in). Doing so ensures periodic calls to the mentioned delegate method, thereby providing the ability to react off of permission changes, etc.
For iOS versions 10 and above, use the UNUserNotificationCenter to request user permission for displaying notifications.
1- (void)setAPNSToken:(nonnull NSData *)token
Parameters
Parameters
Description
token
The APNS token as received from iOS.
Availability
1.3.0
Discussion
By default, Personalization will swizzle the method application:didRegisterForRemoteNotificationsWithDeviceToken:, if defined. However, if you disable swizzling in the Info.plist, you will need to call this method directly to provide the APNS token.
This method notifies Personalization when the app’s APNS token changes, in order to support Personalization push notification campaigns.
Personalization will only send push notifications to the most recent user. For more information, see [Evergage userId].
Personalization automatically tracks clicks and opens for typical push notifications. However, when you need to call a method to track a click, use [EVGContext trackClickthrough:actionIdentifier:].
The setAPNSToken: method can automatically determine if the token is for APNS production vs APNS sandbox.
The setFirebaseToken: method notifies Personalization when your app’s Firebase Messaging token changes, to support Personalization push notification campaigns using Firebase Cloud Messaging.
You do not normally need to call this method. If your app uses Firebase Messaging, simply ensure your FIRMessagingDelegate defines the method messaging:didReceiveRegistrationToken:.
Personalization also supports APNS with or without Firebase, and requires an APNS token even when using Firebase. For more information, see setAPNSToken:.
By default, Personalization will swizzle your FIRMessagingDelegate’s messaging:didReceiveRegistrationToken: method, if defined. However, if you disable swizzling in the Info.plist, you will need to manually call this method.
Personalization will only send push notifications to the most recent user. For more information, see [Evergage userId].
Personalization automatically tracks clicks and opens for typical push notifications. However, when you need to call a method to track a click, use [EVGContext trackClickthrough:actionIdentifier:].
You do not normally need to call this method. If your app uses push notifications, simply ensure you receive them by defining a notification-received method.
However, if you disable swizzling in the Info.plist (see swizzlingEnabled), then you will need to manually call this method from your notification-received method.
This method notifies Personalization when the app receives/processes a notification, so Personalization can update campaign attribution statistics.