IterableSDK 5.0.3

IterableSDK 5.0.3

TestsTested
LangLanguage Obj-CObjective C
License MIT
ReleasedLast Release Jul 2020

Maintained by Ilya Brin, DavidTruong, Victor Babenko, Jay Kim, Akshay Ayyanchira.



  • By
  • Ilya Brin

CocoaPods License Docs Build Status

Iterable iOS SDK

iterable-ios-sdk is an Objective-C implementation of an iOS client for Iterable, for iOS versions 7.0 and higher.

Setting up a push integration in Iterable

Before you even start with the SDK, you will need to

  1. Set your application up to receive push notifications, and
  2. Set up a push integration in Iterable. This allows Iterable to communicate on your behalf with Apple's Push Notification Service

If you haven't yet done so, you will need to enable push notifications for your application. This can be done by toggling Push Notifications under your target's Capabilities in Xcode. You can also do it directly in the app center on Apple's member center; go to Identifiers -> App IDs -> select your app. You should see Push Notifications under Application Services. Hit Edit and enable Push Notifications.

You will also need to generate an SSL certificate and private key for use with the push service. See the links at the end of this section for more information on how to do that.

Once you have your APNS certificates set up, go to Integrations -> Mobile Push in Iterable. When creating an integration, you will need to pick a name and a platform. The name is entirely up to you; it will be the appName when you use registerToken in our SDK. The platform can be APNS or APNS_SANDBOX; these correspond to the production and sandbox platforms. Your application will generate a different token depending on whether it is built using a development certificate or a distribution provisioning profile.

Creating an integration in Iterable

For more information, see

Congratulations, you've configured your mobile application to receive push notifications! Now, let's set up the Iterable SDK...

Automatic Installation (via CocoaPods)

Iterable supports CocoaPods for easy installation. If you don't have it yet, you can install it with Ruby by running:

$ sudo gem install cocoapods 

To include the Iterable SDK in your project, you need to add it to your Podfile. If you don't have a Podfile yet, you can create one by running:

$ pod init

To add the Iterable pod to your target, edit the Podfile and include this line under the target:

pod 'IterableSDK'

Now, you need to tell Cocoapods to install the dependencies:

$ pod install

Congratulations! You have now imported the Iterable SDK into your project!

If your project is built with Swift, you will need a bridging header. See here for more information on how to create one.

Manual Installation

In the Artifacts directory, you can find the compiled static library and headers. To include it in your project...

  1. Add the headers to your header search paths. Build Settings -> Search Paths -> Header Search Paths. Enter the location where you put the SDK's headers. You should enable recursive (and it'll add ** to the end of the path).
  2. Link your project against Iterable's SDK. There are two ways to do this.
  3. Go to Build Phases -> Link Binary With Libraries and select libIterable-iOS-SDK.a, OR
  4. Go to Build Settings -> Search Paths -> Library Search Paths, and enter the location where libIterable-iOS-SDK.a resides. Next, tell your project that it should look for Iterable-iOS-SDK during the linking phase by going to Build Settings -> Linking -> Other Linker Flags, and add -lIterable-iOS-SDK
  5. Go to Build Settings -> Linking -> Other Linker Flags, and add -ObjC. It is required for the NSData+Conversion.h category to be picked up properly during linking. For more information, see this.

Using the SDK

  1. On application launch (application:didFinishLaunchingWithOptions:), initialize the Iterable SDK:
IterableConfig *config = [[IterableConfig alloc] init];
config.pushIntegrationName = "myPushIntegration";
[IterableAPI initializeWithApiKey:@"<your-api-key>" launchOptions:launchOptions config:config];
  • The apiKey should correspond to the API key of your project in Iterable. If you'd like, you can specify a different apiKey depending on whether you're building in DEBUG or PRODUCTION, and point the SDK to the relevant Iterable project.
  • Ideally, you will call this from inside application:didFinishLaunchingWithOptions: and pass in launchOptions. This will let the SDK automatically track a push open for you if the application was launched from a remote Iterable push notification.
  • This method creates a singleton IterableAPI for your use. You can retrieve it later with [IterableAPI sharedInstance]. If retrieving it later, be sure that you have either instantiated it earlier, or check for a non-nil return value.
  1. Once you know the email (Preferred) or userId of the user, call setEmail: or setUserId:
  • EMAIL: [[IterableAPI sharedInstance] setEmail:@"[email protected]"];
  • USERID: [[IterableAPI sharedInstance] setUserId:@"userId"];
    • If you are setting a userId, an existing user must already exist for that userId
    • It is preferred that you use Email since that doesn't require an additional lookup by userId call on the backend.
  1. Register for remote notifications
    Since iOS 10, the preferred way is to use UserNotifications framework. See Asking Permission to Use Notifications and Registering Your App with APNs from Apple's documentation.

    1. Request authorization to display notifications via UNUserNotificationCenter's requestAuthorizationWithOptions:completionHandler:. The first time you call this method, iOS will prompt the user to allow the specified interactions. The OS will asynchronously let you know the user's choices via the provided callback block.
      For iOS < 10, call UIApplication's registerUserNotificationSettings:
    2. Call UIApplication's registerForRemoteNotifications method to register your app for remote notifications.
    3. Use your app delegate’s application:didRegisterForRemoteNotificationsWithDeviceToken: method to receive the device token needed to deliver remote notifications. Use the application:didFailToRegisterForRemoteNotificationsWithError: method to process errors.

    Device registration will fail if user email or userId is not set. If you're calling setEmail: or setUserId: after the app is launched (i.e. when the user logs in), make sure you call registerForRemoteNotifications again to register the device with the logged in user.

  2. Send the token to Iterable
    Use the SDK's - (void)registerToken:(NSData *)token to send the token to Iterable
    This will register the token with the integration passed in pushIntegrationName. If you also pass sandboxPushIntegrationName, Iterable SDK will try to determine the APNS environment from the provisioning profile and register the device with the correct integration (APNS or APNS_SANDBOX).
    Device tokens can change, so your app needs to reregister every time it is launched and pass the received token back to your server. Don't cache your token on the device; send it every time you receive one. This is the practice recommended by Apple; see the documentation here. Specifically,

    Device tokens can change, so your app needs to reregister every time it is launched and pass the received token back to your server. If you fail to update the device token, remote notifications might not make their way to the user’s device. Device tokens always change when the user restores backup data to a new device or computer or reinstalls the operating system. When migrating data to a new device or computer, the user must launch your app once before remote notifications can be delivered to that device.

    Never cache a device token; always get the token from the system whenever you need it. If your app previously registered for remote notifications, calling the registerForRemoteNotifications method again does not incur any additional overhead, and iOS returns the existing device token to your app delegate immediately. In addition, iOS calls your delegate method any time the device token changes, not just in response to your app registering or re-registering.

  3. Handling push interactions When the user taps on the notification or one of the action buttons, the system calls UNUserNotificationCenterDelegate's userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:. Pass this call to IterableAppIntegration to track push open event and perform the associated action (see below for custom action and URL delegates).

Putting it all together:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // other setup tasks here....
    
    // Initialize Iterable SDK
    IterableConfig *config = [[IterableConfig alloc] init];
    config.pushIntegrationName = "myPushIntegration_Prod";
    config.sandboxPushIntegrationName = "myPushIntegration_Dev";
    [IterableAPI initializeWithApiKey:@"YOUR API KEY" launchOptions:launchOptions config:config];
 
    if (@available(iOS 10, *)) {
    	UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        center.delegate = self;
        [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error){
             if(!error){
                 [[UIApplication sharedApplication] registerForRemoteNotifications];
             }
         }];  
    } else {
	    UIUserNotificationType types = UIUserNotificationTypeBadge |
	                 UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
	    UIUserNotificationSettings *mySettings =
	                [UIUserNotificationSettings settingsForTypes:types categories:nil];
	    [[UIApplication sharedApplication] registerUserNotificationSettings:mySettings];
    	[[UIApplication sharedApplication] registerForRemoteNotifications];
    }
 
    // Register for remote notifications.
}
 
// Handle remote notification registration.
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)token {
    [[IterableAPI sharedInstance] registerToken:token];
}
 
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"Error in registration for remote notifications. Error: %@", error);
}

// This is necessary for push notifications to work while the app is in foreground
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
    completionHandler(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound);
}

// Pass the notification response (tap on the notification or one of the buttons) to the Iterable SDK so it can track the push open event and perform the associated action
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{
    [IterableAppIntegration userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler];
}

// This method will be called when the notification is opened on iOS < 10
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
	[IterableAppIntegration application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}

Congratulations! You can now send remote push notifications to your device from Iterable!

Iterable Notifications

All notifications from Iterable will come with a field called itbl in the payload. This field will contain a dictionary of data for Iterable's use. You can access it directly, but you should avoid doing so, as those fields might change. As of now, the fields include

  • campaignId - the campaign id (in Iterable). Not relevant for proof and test pushes.
  • templateId - the template id (in Iterable). Not relevant for test pushes.
  • messageId - the message id (in Iterable).
  • isGhostPush - whether this is a ghost push. See section below on uninstall tracking.

Uninstall Tracking

Iterable will track uninstalls with no additional work by you.

This is implemented by sending a second push notification some time (currently, twelve hours) after the original campaign. If we receive feedback that the device's token is no longer valid, we assign an uninstall to the device, attributing it to the most recent campaign within twelve hours. An "real" campaign send (as opposed to the later "ghost" send) can also trigger recording an uninstall. In this case, if there was no previous campaign within the attribution period, an uninstall will still be tracked, but it will not be attributed to any campaign.

These "ghost" notifications will not automatically create a notification on the device. In fact, your application won't even be notified at all, unless you've enabled background mode. If you'd like your application to receive and act on these "ghost" pushes, you can enable background mode (this won't make the notifications show up; it'll just let your app handle them). To do this, go to your target in Xcode, then go to Capabilities -> Background Modes and enable Background fetch and Remote notifications.

After enabling background mode, you will need to implement a different method instead of application:didReceiveRemoteNotification:; this method is application:didReceiveRemoteNotification:fetchCompletionHandler:. This method, unlike application:didReceiveRemoteNotification:, will be called regardless of whether your application is running in the foreground or background. Once you are done, don't forget to call the completion handler with a UIBackgroundFetchResult. For more information on background mode notifications, see the Discussion under the documentation for the method.

Disabling push notifications to a device

When a user logs out, you typically want to disable push notifications to that user/device. This can be accomplished by calling disableDeviceForCurrentUser. Please note that it will only attempt to disable the device if you have previously called registerToken.

In order to re-enable push notifcations to that device, simply call registerToken as usual when the user logs back in.

InApp Notifications

To display the user's InApp notifications call spawnInAppNotification with a defined ITEActionBlock callback handler. When a user clicks a button on the notification, the defined handler is called and passed the action name defined in the InApp template.

InApp opens and button clicks are automatically tracked when the notification is called via spawnInAppNotification. Using spawnInAppNotification the notification is consumed and removed from the user's in-app messages queue. If you want to retain the messages on the queue, look at using getInAppMessages directly. If you use getInAppMessages you will need to manage the in-app opens manually in the callback handler.

Tracking and Updating User Fields

Custom events can be tracked using the track function and user fields can be modified using the updateUser function.

Deep Linking

Handling links from push notifications

Push notifications and action buttons may have openUrl actions attached to them. When a URL is specified, the SDK first calls urlDelegate specified in your IterableConfig object. You can use this delegate to handle openUrl actions the same way as you handle normal deep links. If the delegate is not set or returns NO, the SDK will open Safari with that URL.

// AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ...
    // Initialize Iterable SDK
    IterableConfig *config = [[IterableConfig alloc] init];
    ...
    config.urlDelegate = self;
    [IterableAPI initializeWithApiKey:@"YOUR API KEY" launchOptions:launchOptions config:config];
    ...
}

- (BOOL)handleIterableURL:(NSURL *)url context:(IterableActionContext *)context {
    // Assuming you have a DeeplinkHandler class that handles all deep link URLs and navigates to the right place in the app
    return [[DeeplinkHandler sharedInstance] handleUrl:url];
}

Handling email links

For Universal Links to work with link rewriting in emails, you need to set up apple-app-site-association file in the Iterable project. More instructions here: Setting up iOS Universal Links

If you already have a urlDelegate (see Handling links from push notifications section above), the same handler can be used for email deep links by calling handleUniversalLink: in your UIApplicationDelegate's application:continueUserActivity:restorationHandler::

- (BOOL)application:(UIApplication *)application
 		continueUserActivity(NSUserActivity *)userActivity 
 		restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler {
    // This will track the click, retrieve the original URL and call `handleIterableURL:context:` with the original URL
    return [IterableAPI handleUniversalLink:userActivity.webpageURL];
}

Alternatively, call getAndTrackDeeplink along with a callback to handle the original deeplink url. You can use this method for any incoming URLs, as it will execute the callback without changing the URL for non-Iterable URLs.

Swift:

func application(_ application: UIApplication, continue userActivity: NSUserActivity,
                  restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
    
    IterableAPI.getAndTrackDeeplink(userActivity.webpageURL!, callbackBlock: {
        (originalURL) in
            //Handle Original URL deeplink here
    });
    return true
}

Objective-C:

- (BOOL)application:(UIApplication *)application
 		continueUserActivity(NSUserActivity *)userActivity 
 		restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler {
    
    [IterableAPI getAndTrackDeeplink:iterableLink callbackBlock:^(NSString* originalURL) {
        //Handle Original URL deeplink here
    }];
    
    return true;
}

Rich Push Notifications

Push notifications may contain media attachments with images, animated gifs or video, and with an upcoming update, there will be a way to create action buttons. For this to work within your app, you need to create a Notification Service Extension. More instructions here: Rich Push Notifications in iOS 10 and Android - Media Attachments.
Iterable SDK provides an implementation that handles media attachments and action buttons, so you'll only need to inherit from it:

Podfile
// If the target name for the notification extension is 'MyAppNotificationExtension'
target 'MyAppNotificationExtension' do
    pod 'IterableAppExtensions'
end
NotificationService.h
#import <UserNotifications/UserNotifications.h>
#import <IterableAppExtensions/IterableExtensions.h>

@interface NotificationService : ITBNotificationServiceExtension

@end

Additional Information

See our setup guide for more information.

Also see our push notification setup FAQs.

License

The MIT License

See LICENSE

Want to Contribute?

This library is open source, and we will look at pull requests!

See CONTRIBUTING for more information.