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
- Set your application up to receive push notifications, and
- 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.
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 withSwift
, you will need abridging 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...
- 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). - Link your project against Iterable's SDK. There are two ways to do this.
- Go to
Build Phases
->Link Binary With Libraries
and selectlibIterable-iOS-SDK.a
, OR - Go to
Build Settings
->Search Paths
->Library Search Paths
, and enter the location wherelibIterable-iOS-SDK.a
resides. Next, tell your project that it should look forIterable-iOS-SDK
during the linking phase by going toBuild Settings
->Linking
->Other Linker Flags
, and add-lIterable-iOS-SDK
- Go to
Build Settings
->Linking
->Other Linker Flags
, and add-ObjC
. It is required for theNSData+Conversion.h
category to be picked up properly during linking. For more information, see this.
Using the SDK
- 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 differentapiKey
depending on whether you're building inDEBUG
orPRODUCTION
, and point the SDK to the relevant Iterable project. - Ideally, you will call this from inside
application:didFinishLaunchingWithOptions:
and pass inlaunchOptions
. 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.
- Once you know the email (Preferred) or userId of the user, call
setEmail:
orsetUserId:
- 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.
-
Register for remote notifications
Since iOS 10, the preferred way is to useUserNotifications
framework. See Asking Permission to Use Notifications and Registering Your App with APNs from Apple's documentation.- 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, callUIApplication
's registerUserNotificationSettings: - Call
UIApplication
's registerForRemoteNotifications method to register your app for remote notifications. - 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 callingsetEmail:
orsetUserId:
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. - Request authorization to display notifications via
-
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 inpushIntegrationName
. If you also passsandboxPushIntegrationName
, 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. -
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 toIterableAppIntegration
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.