Iterable-iOS-SDK
is a Swift implementation of an iOS client for Iterable, for iOS versions 9.0 and higher.
Before you even start with the SDK, you will need to setup Iterable push notifications for your app.
For more information, see Getting Started Guide.
Iterable supports CocoaPods for easy installation. If you don't have it yet, please refer to this document to install Cocoapods.
To include the Iterable SDK in your project, edit the Podfile
and add the Iterable-iOS-SDK pod to your app target:
pod 'Iterable-iOS-SDK'
If you want to include Iterable Rich Notification Extension you will also need to include the Iterable-iOS-AppExtensions pod to your extension target:
pod 'Iterable-iOS-AppExtensions'
Please look at the included sample pod file HERE.
Congratulations! You have now imported Iterable SDK into your project!
Attached to the release you will find two framework bundles.
IterableSDK.framework
IterableAppExtensions.framework
-
In XCode choose the target for your app. Now add IterableSDK.framework to the embedded binaries section. If you want to use Iterable Rich Notification Extension, you will have to add IterableAppExtensions.framework to the embedded binaries section as well.
-
If you want to use Iterable Rich Notifiation Extension, you will need to add IterableAppExtension.framework to Linked Frameworks and Libraries section of your app extension target (not app target). Please note that you will have to add the IterableAppExtension.framework bundle to both the app target (step 1) and app extension target (step 2) of your project. In the app target it goes in the 'Embedded Binaries' section and in app extension target it goes in the 'Linked Frameworks and Libraries' section.
-
In build settings, set
Always Embed Swift Standard Libraries
setting to 'Yes'. This is required for Objective C projects.
Note: Sample projects are included in this repo.
You need to import IterableSDK module in order to use it. Import in the top your Swift or Obective-C files as shown below.
Swift
// In AppDelegate.swift file
// and any other file where you are using IterableSDK
import IterableSDK
Objective-C
// In AppDelegate.m file
// and any other file where you are using IterableSDK
@import IterableSDK;
In your app delegate, on application launch in application:didFinishLaunchingWithOptions:
method, initialize the Iterable SDK:
Swift
let config = IterableConfig()
config.pushIntegrationName = "<your-iterable-push-integration-name>"
IterableAPI.initialize(apiKey: "<your-api-key>", launchOptions: launchOptions, config:config)
Objective-C
IterableConfig *config = [[IterableConfig alloc] init];
config.pushIntegrationName = @"<your-iterable-push-integration-name>";
[IterableAPI initializeWithApiKey:@"<your-api-key>" launchOptions:launchOptions config:config]
See the Iterable guide on how to setup your Iterable push integration and obtain push integration name here.
Once you know the email or userId of the user, set the value.
⚠ Don't specify both email and userId in the same session, as they will be treated as different users by the SDK. Only use one type of identifier, email or userId, to identify the user. Swift
IterableAPI.email = "user@example.com"
Objective-C
IterableAPI.email = @"user@example.com";
See Apple Notification Guide regarding how to register for remote notifiations.
-
Send remote notification token to Iterable
To send push notifications to your app, you will have to first send the application's remote notification token Iterable.
In your
AppDelegate
’s application:didRegisterForRemoteNotificationsWithDeviceToken: method, send the token obtained to Iterable.Swift
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { IterableAPI.register(token: deviceToken) }
Objective-C
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { [IterableAPI registerToken:deviceToken]; }
-
Handle push notifications
When the user taps on the push notification or one of the action buttons, the system calls
UNUserNotificationCenterDelegate
's userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:. In this method, callIterableAppIntegration
with the same parameters to track push open event and perform the associated action (see below for custom action and URL delegates).Swift
public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { IterableAppIntegration.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler) }
Objective-C
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { [IterableAppIntegration userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler]; }
See example in sample app delegate here.
Congratulations! You can now send remote push notifications to your device from Iterable! Please note that you can't send push notifications until you set the userId or email. Please see sample applications to see a reference implementation.
Deep linking allows a uniform resource identifier (URI) to link to a specific location within your mobile app rather than simply launching the app.
Push notifications and action buttons may have openUrl
actions attached to them. When a URL is specified, the SDK first calls the 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 if it returns false
(the default), the SDK will open Safari with that URL. If you want to navigate to a view controller on receiving a deep link, do so in the urlDelegate
.
In the code below, DeepLinkHandler
is a custom handler which is reponsible for deep link navigation. You have to provide implementation for deep link navigation. Please see sample application for a reference implementation of DeeplinkHandler.
Swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
...
// Initialize Iterable API
let config = IterableConfig()
...
config.urlDelegate = self
IterableAPI.initialize(apiKey: apiKey, launchOptions:launchOptions, config: config)
...
}
// Iterable URL Delegate. It will be called when you receive
// an `openUrl` event from push notification.
func handle(iterableURL url: URL, inContext context: IterableActionContext) -> Bool {
return DeeplinkHandler.handle(url: url)
}
Objective-C
- (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 handleUrl:url];
}
For universal links to work with link rewriting in emails, set up an apple-app-site-association file in the Iterable project.
When an email link is clicked, your UIApplicationDelegate
's application:continueUserActivity:restorationHandler: method is called. If you already have an Iterable urlDelegate
defined (see Handling Links from Push Notifications section above), the same handler can be used for email deep links by calling handleUniversalLink:
.
Swift
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
guard let url = userActivity.webpageURL else {
return false
}
// This will track the click, retrieve the original URL and call `handleIterableURL:context:` with the original URL
return IterableAPI.handle(universalLink: url)
}
Objective-C
- (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];
}
Deferred deep linking allows a user who does not have a specific app installed to:
- Click on a deep link that would normally open content in that app.
- Install the app from the App Store.
- Open the app and immediately see the content referenced by the link.
As the name implies, the deep link is deferred until the app has been installed.
After tapping a deep link in an email from an Iterable campaign, users without the associated app will be directed to the App Store to install it. If the app uses the IterableSDK and has deferred deep linking enabled, the content associated with the deep link will load on first launch.
Set IterableConfig.checkForDeferredDeeplink = true
to enable deferred deep linking for IterableSDK.
If you are already using in-app messages with IterableSDK, please check out the migration section.
In-app messages are handled via silent push messages from the server. When your application receives a silent push, you need to call IterableSDK in your AppDelegate as in the following code:
Swift
// In AppDelegate.swift
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
IterableAppIntegration.application(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler)
}
Objective-C
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[IterableAppIntegration application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
By default, when an in-app message arrives from the server, the SDK automatically shows it if the app is in the foreground. If an in-app message is already showing when the new message arrives, the new in-app message will be shown 30 seconds after the currently displayed in-app message closes (see how to change this default value below). Once an in-app message is shown, it will be "consumed" from the server queue and removed from the local queue as well. There is no need to write any code to get this default behavior.
An incoming in-app message triggers a call to the onNew
method of IterableConfig.inAppDelegate
(an object of type IterableInAppDelegate
). To override the default behavior, set IterableConfig.inAppDelegate
to a custom class that overrides the onNew
method. onNew
should return .show
to show the incoming in-app message or .skip
to skip showing it.
Swift
class YourCustomInAppDelegate : IterableInAppDelegate {
func onNew(message: IterableInAppMessage) -> InAppShowResponse {
// perform custom processing
// ...
return .show // or .skip
}
}
// ...
let config = IterableConfig()
config.inAppDelegate = YourCustomInAppDelegate()
IterableAPI.initialize(apiKey: "YOUR API KEY", launchOptions: nil, config: config)
Objective-C
// Implement this method in your custom class that implements IterableInAppDelegate
// This will most likely be the global AppDelegate class.
- (enum InAppShowResponse)onNewMessage:(IterableInAppMessage * _Nonnull)message {
// perform custom processing
// ...
return InAppShowResponseShow; // or InAppShowResponseSkip
}
// ...
// Now set this custom class in IterableConfig
IterableConfig *config = [[IterableConfig alloc] init];
config.inAppDelegate = self; // or other class implementing the protocol
[IterableAPI initializeWithApiKey:@"YOUR API KEY" launchOptions:launchOptions config:config];
Until they are consumed by the app, all in-app messages that arrive from the server are stored in a local queue. To access that local queue, use the read-only IterableAPI.inAppManager
property (which conforms to the InAppManager
protocol). By default, all in-app messages in the local queue will be consumed and removed from this queue. To keep in-app messages around after they are shown, override the default behavior (as described above).
Swift
// Get the in-app messages list
let messages = IterableAPI.inAppManager.getMessages()
// Show an in-app message
IterableAPI.inAppManager.show(message: message)
// Show an in-app message without consuming, i.e., not removing it from the queue
IterableAPI.inAppManager.show(message: message, consume: false)
Objective-C
// Get the in-app messages list
NSArray *messages = [IterableAPI.inAppManager getMessages];
// Show an in-app message
[IterableAPI.inAppManager showMessage:message];
// Show an in-app message without consuming, i.e., not removing it from the queue
[IterableAPI.inAppManager showMessage:message consume:NO callbackBlock:nil];
Button/link clicks from in-app are handled similar to deep links from notifications and emails. Please see those sections above. If the in-app message's clicked button/link's href
contains a URL (which is usually the case), tapping that button/link will call the handle
method of IterableConfig.urlDelegate
(an object of type IterableURLDelegate
), if one is set. By default if this delegate is not set, tapping the button/link will open Safari with the href
of the clicked button/link.
Custom action is specified by passing itbl://customActionName
as the link URL (notice the itbl
scheme name). If the in-app message's href
property contains custom action name, tapping the message will call the handle
method of IterableConfig.customActionDelegate
(an object that conforms to the IterableCustomActionDelegate
protocol). If customActionDelegate
is not set, nothing will happen by default.
Take a look at this sample code that demonstrates how to implement and use the IterableURLDelegate
and IterableCustomActionDelegate
protocols.
let config = IterableConfig()
config.urlDelegate = YourCustomUrlDelegate()
config.customActionDelegate = YourCustomActionDelegate()
To customize the time delay between successive in-app messages (default value of 30 seconds), set IterableConfig.inAppDisplayInterval
to an appropriate value (in seconds).
If you are already using in-app messages, then you will have to make the following changes to your code:
spawnInAppNotification
is no longer needed and will fail to compile. In-app messages are now displayed automatically.- Stop polling for in-app messages using a timer, etc. The SDK will issue a callback using
config.inAppDelegate
as explained above. - If you want to handle all in-app messages manually, as before these changes, define an
inAppHandler
onIterableConfig
. It should returnInAppShowResponse.skip
to prevent in-app messages from showing automatically. It can callgetInAppManager().getMessages()
to get the messages andgetInAppManager().showMessage(message)
to show a specific message.
Custom events can be tracked using IterableAPI.track(event:...)
calls.
User fields can be modified using IterableAPI.updateUser
call. You also have updateEmail
and updateSubscriptions
methods.
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.
Iterable will track uninstalls with no additional work by you.
To do this, Iterable sends a silent push notification some time (currently, twelve hours) after a campaign has been sent. Based on this silent push notification, if Iterable receives feedback that the device token is no longer valid, it assigns an uninstall to the device based on the prior campaign. Similarly, if a "real" campaign uncovers an invalid device token, it will also check for a prior (within twelve hours) campaign to mark as the cause for the uninstall. If there was no recent campaign, Iterable still tracks the uninstall, but does not attribute it to a campaign.
Push notifications may contain media attachments with images, animated gifs or video, and 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.
- Include
Iterable-iOS-AppExtensions
in your podfile as explained above. - Create a new target of type notification service extension in your XCode project/solution.
- If you are calling Iterable SDK from Swift, all you need to do is inherit the
NotificationService
class (auto generated by XCode) fromITBNotificationServiceExtension
class. If you are using Objective-C, you will have to delegate to the implementation provided. See example below.
Swift
import UserNotifications
import IterableAppExtensions
class NotificationService: ITBNotificationServiceExtension {
}
Objective-C
You can not inherit in case of Objective C. You will have to delegate like below.
// File: NotificationService.m
#import "NotificationService.h"
@import IterableAppExtensions;
@interface NotificationService ()
@property (nonatomic, strong) ITBNotificationServiceExtension *baseExtension;
@end
@implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.baseExtension = [[ITBNotificationServiceExtension alloc] init];
[self.baseExtension didReceiveNotificationRequest:request withContentHandler:contentHandler];
}
- (void)serviceExtensionTimeWillExpire {
[self.baseExtension serviceExtensionTimeWillExpire];
}
@end
See our setup guide for more information.
Also see our push notification setup FAQs.
The MIT License
See LICENSE
This library is open source, and we will look at pull requests!
See CONTRIBUTING for more information.