Iterable's iOS SDK supports features such as push notifications, in-app messages, deep links, and Mobile Inbox. This article describes how to install and configure the SDK to work with Iterable.
# In this article
To install and configure Iterable's iOS SDK, follow these steps:
- Supported iOS versions
- Encrypted data
-
Installation steps
- Step 1: Create a Notification Service Extension (if necessary)
- Step 2: Install the SDK
- Step 3: Configure the Notification Service Extension (if necessary)
- Step 4: Import IterableSDK wherever necessary
- Step 5: Create a mobile API key
- Step 6: Initialize the SDK with your API key
- Step 7: Enable push notifications
- Step 8: Enable in-app messages
- Step 9: Verify that the SDK can communicate with Iterable
- Embedded Messaging
- Upgrading the SDK
- Further reading
# Supported iOS versions
Iterable's iOS SDK supports iOS 10 and higher.
# Encrypted data
Iterable's iOS SDK encrypts some data at rest. For more information, read Upgrading to 6.4.8+.
# Installation steps
Follow these steps to install the SDK. If you're upgrading from a previous version, also see Upgrading the SDK.
# Step 1: Create a Notification Service Extension (if necessary)
For an iOS app to support push notifications that contain action buttons, images, videos or custom sounds, its Xcode project must contain a Notification Service Extension. It's helpful to set your app's Notification Service Extension target up before installing and configuring the SDK.
To add a Notification Service Extension target to your Xcode project:
Open your app's Xcode project.
Choose File > New > Target.
-
On the iOS tab, select Notification Service Extension:
Click Next.
Provide all necessary configuration information for the Notification Service Extension.
Click Finish.
Next, install the SDK using one of the methods described below. Then, configure the Notification Service Extension
# Step 2: Install the SDK
To install the SDK, use the Swift Package Manager, CocoaPods, Carthage, or install it manually.
IMPORTANT
Starting with version 6.4.0,
Iterable's iOS SDK no longer supports iOS 9. For iOS 9 support, use version
6.3.4.
# Step 2.1: Install the SDK with the Swift Package Manager
Swift Package Manager is an Xcode tool that installs project dependencies. To use it to install Iterable's iOS SDK, follow these steps:
NOTES
The Swift Package Manager can install versions 6.2.0 and higher of Iterable's iOS SDK.
In Xcode, click File > Add Packages....
-
In the window that opens, enter
https://github.com/Iterable/iterable-swift-sdkin the upper-right corner: -
Use the Dependency Rule and Add to Project options to specify which version of the SDK you'd like to add, and the project to which you'd like to add it. For example, to use the latest version of the SDK found the current major version sequence, choose Up to Next Major Version for Dependency Rule and enter
6.0.0for the lower version number.For more information about these options, see the Decide on Package Requirements section of Apple's guide, Adding Package Dependencies to Your App.
Click Add Package.
-
When prompted to choose package products:
Check IterableSDK, and choose the target associated with your app.
If you'll send push notifications with action buttons, images, videos, or custom sounds, check IterableAppExtensions. Then, choose the target associated with your app's Notification Service Extension.
Click Add Package.
The packages will be added to your app.
# Step 2.2: Install the SDK with CocoaPods
To use CocoaPods to install Iterable's iOS SDK, follow these steps:
-
If your project does not yet have a
Podfile, create one:In the terminal, navigate to the directory containing your project's .xcodeproj file.
Run this command:
pod init.
-
Edit the
Podfile:In this file, add the
Iterable-iOS-SDKpod to your project's app target.If you will send push notifications that contain action buttons, images, videos or custom sounds, add the
Iterable-iOS-AppExtensionspod to your project's Notification Service Extension.-
After these changes, your
Podfileshould look similar to this:platform :ios, '11.0' target '<YOUR_APP_TARGET>' do pod 'Iterable-iOS-SDK' end target '<YOUR_NOTIFICATION_EXTENSION_TARGET>' do pod 'Iterable-iOS-AppExtensions' end
NOTE
In versions 6.3.3 and above of Iterable's iOS SDK, it's no longer necessary to include
use_frameworks!in yourPodfile.
In the terminal, run
pod installto install the pods you configured in the previous step. If you see errors, trypod install --repo-update(docs).Your project now has an .xcworkspace file. Use this file to open your project, instead of its
.xcodeprojfile.
For more information, read the CocoaPods documentation.
# Step 2.3: Install the SDK with Carthage
To use Carthage to install Iterable's iOS SDK, follow these steps:
# Step 2.3.1: Add IterableSDK.framework
First, add IterableSDK.framework to your project:
Create a
Cartfilein the same directory as your .xcodeproj or .xcworkspace file.-
Add this line to the
Cartfile:github "Iterable/swift-sdk"
Open a terminal window. In it, navigate to the same directory as your
Cartfile.Run this command:
carthage update.From the terminal, open a Finder window:
open .. In this window, navigate to theCarthage/Build/iOSsubdirectory. Keep this window open.Open your app's Xcode project.
From the Finder window opened above, drag
IterableSDK.frameworkonto Xcode's Project Navigator (far left column). When prompted, add the framework to your app target.In Xcode's Project Navigator, select the top item, which corresponds to the project itself.
Under Targets, select your app.
Navigate to Build Phases.
Add a build phase by clicking + and selecting New Run Script Phase. A Run Script section will appear.
-
In the new Run Script section, add this command in the text area:
/usr/local/bin/carthage copy-frameworks
-
In the Input Files section, click + and add:
$(SRCROOT)/Carthage/Build/iOS/IterableSDK.framework
-
In the Output Files section, add the path to the copied framework:
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/IterableSDK.framework
# Step 2.3.2: Add IterableAppExtensions.framework
If you will send push notifications that have action buttons, images, videos or custom sounds, follow these steps, too:
Open your app's Xcode project.
From the Finder window opened in the previous section, drag
IterableAppExtensions.frameworkonto Xcode's Project Navigator (far left column). When prompted, add the framework to your Notification Service Extension target.In Xcode's Project Navigator, select the top item, which corresponds to the project itself.
Under Targets, select your Notification Service Extension.
Navigate to Build Phases.
Add a build phase by clicking + and selecting New Run Script Phase. A Run Script section will appear.
-
In the new Run Script section, in the script text area, add this command:
/usr/local/bin/carthage copy-frameworks
-
In the Input Files section, click + and add this path:
$(SRCROOT)/Carthage/Build/iOS/IterableAppExtensions.framework
-
In the Output Files section, add the path to the copied framework:
$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/IterableAppExtensions.framework
# Step 3: Configure the Notification Service Extension (if necessary)
If you added a Notification Service Extension to your project (above),
set it up to handle media attachments and action buttons. To do this, use the
ITBNotificationServiceExtension class provided by Iterable's iOS SDK:
Open the
NotificationServiceclass (auto-generated by Xcode when you added the Notification Service Extension to your project).-
For Swift-based projects:
Add an import:
import IterableAppExtensions.-
Update
NotificationServiceso that it extendsITBNotificationServiceExtension, and contains no other code:import UserNotifications import IterableAppExtensions class NotificationService: ITBNotificationServiceExtension { }
IMPORTANT
If you're using React Native, you may need to install some Objective-C compatibility headers and use different import statements. For more information, read Installing Iterable's React Native SDK — Step 3.3: Import the SDK.
-
For Objective-C projects:
Add an import:
@import IterableAppExtensions;.-
Configure the class so that it's similar to the following:
// 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
# Step 4: Import IterableSDK wherever necessary
To use Iterable's iOS SDK in your app's code, import it at the top of any Swift or Objective-C files that reference it. For example:
Swift
// In AppDelegate.swift and any other file where you're using IterableSDK import IterableSDK
Objective-C
// In AppDelegate.m and any other file where you're using IterableSDK @import IterableSDK;
IMPORTANT
If you're using React Native, you may need to install some Objective-C compatibility headers and use different import statements. For more information, read Installing Iterable's React Native SDK — Step 3.3: Import the SDK.
# Step 5: Create a mobile API key
To make calls to Iterable's's API, the SDK needs a mobile API key. To learn how to create one, read API Keys
WARNING
Never embed server-side API keys in client-side code (whether JavaScript, a mobile application or otherwise), since they can be used to access all of your project's data. For a mobile app, use a mobile API key (if possible, we recommend using JWT authentication for additional security).
If necessary, use different API keys for debug and production builds.
# Step 6: Initialize the SDK with your API key
Next, you'll need to make a few updates in your app delegate's
application(_:didFinishLaunchingWithOptions:)
method:
# Step 6.1: Call IterableAPI.initialize
Call initialize(apiKey:launchOptions:config:), passing your Iterable API key
as a parameter:
Swift
let config = IterableConfig() IterableAPI.initialize(apiKey: "<YOUR_API_KEY>", launchOptions:launchOptions, config: config)
Objective-C
IterableConfig *config = [[IterableConfig alloc] init]; [IterableAPI initializeWithApiKey:@"<YOUR_API_KEY>" config:config]
IterableConfig provides configuration and customization options for the
Iterable SDK. You'll use it later to set up push notifications and in-app
messages.
# Step 6.2: If necessary, configure the SDK to use Iterable's EDC
If your project is hosted on Iterable's European data center (EDC), configure the SDK to use Iterable's EDC-based endpoints:
Swift
let config = IterableConfig() config.dataRegion = IterableDataRegion.EU IterableAPI.initialize(apiKey: "<YOUR_API_KEY>", launchOptions: launchOptions, config: config)
Objective-C
IterableConfig *config = [[IterableConfig alloc] init]; config.dataRegion = IterableDataRegion.EU [IterableAPI initializeWithApiKey:@"<YOUR_API_KEY>" launchOptions:launchOptions config:config]
# Step 6.3: Set the allowedProtocols field
Starting with version 6.4.0
of Iterable's iOS SDK, you'll need to declare the specific URL protocols that the
SDK can expect to see on incoming links (and that it should handle as needed). This
prevents the SDK from opening links that use unexpected URL protocols.
To do this, set the allowedProtocols field (on the IterableConfig object you
pass to the SDK's initialize method) to an array that contains the protocols you'd
like the SDK to support.
For example, this code allows the SDK to handle http://, tel://, and custom://
links:
Swift
let config = IterableConfig() config.allowedProtocols = ["http", "tel", "custom"] IterableAPI.initialize(apiKey: "<YOUR_API_KEY>", launchOptions:launchOptions, config:config)
Objective-C
IterableConfig *config = [[IterableConfig alloc] init]; config.allowedProtocols = @["http", "tel", "custom"]; [IterableAPI initializeWithApiKey:@"<YOUR_API_KEY>" launchOptions:launchOptions, config:config]
IMPORTANT
Iterable's iOS SDK handles https, action, itbl, and iterable links,
regardless of the contents of this array. However, you must explicitly declare any
other types of URL protocols you'd like the SDK to handle (otherwise, the SDK
won't open them in the web browser or as deep links).
# Step 6.4: Set up a push integration
In Iterable, you'll create logical mobile apps to store information about your real mobile apps—including information about the configuration parameters Iterable needs to send push notifications to them. Iterable refers to these push notification configuration parameters as push integrations.
TIP
Older push integrations may not yet be associated in Iterable with a mobile app. However, you can assign them.
By default, the SDK expects your push integration's name to match your app's bundle ID. However, if your Iterable push integration was created before August 2019, it may have a custom name. To handle this, do one of the following things:
In Iterable, assign the existing push integration to a mobile app. If you do this, the SDK will use the push integration that matches your mobile app's bundle ID.
-
Alternatively, specify the custom push integration name when initializing the SDK:
Swift
let config = IterableConfig() config.pushIntegrationName = "<PUSH_INTEGRATION_NAME>" IterableAPI.initialize(apiKey: "<YOUR_API_KEY>", launchOptions:launchOptions, config:config)
Objective-C
IterableConfig *config = [[IterableConfig alloc] init]; config.pushIntegrationName = @"<PUSH_INTEGRATION_NAME>"; [IterableAPI initializeWithApiKey:@"<YOUR_API_KEY>" launchOptions:launchOptions, config:config]
TIP
To find the name of your push integration, navigate in Iterable to Settings > Apps and websites, open the mobile app that's associated with your actual app, look at the Details section, and find the Package Name.
# Step 6.5: Choose whether or not to use in-memory storage for in-app messages
By default, Iterable's iOS SDK stores in-app messages in an unencrypted local
file. To instead store in-app messages in memory, set useInMemoryStorageForInApps
to true:
Swift
let config = IterableConfig() config.useInMemoryStorageForInApps = true IterableAPI.initialize(apiKey: "<YOUR_API_KEY>", launchOptions:launchOptions, config:config)
Objective-C
IterableConfig *config = [[IterableConfig alloc] init]; config.useInMemoryStorageForInApps = YES; [IterableAPI initializeWithApiKey:@"<YOUR_API_KEY>" launchOptions:launchOptions, config:config];
For more information, read Upgrading to 6.4.9+.
# Step 6.6: Handle JWT-enabled API keys
If you're using a JWT-enabled API Key, you'll need custom code to manage JWT tokens for the signed-in user.
# Step 6.6.1: Register an auth handler
When initializing the SDK, provide an auth handler. The SDK uses the auth handler to:
- Fetch new JWT tokens from your server.
- Report when a non-null JWT token has been retrieved.
- Report when there have been failures fetching new JWT tokens.
The object that you pass to the SDK as an auth manager must implement the
IterableAuthDelegate protocol:
@objc public protocol IterableAuthDelegate: AnyObject { @objc func onAuthTokenRequested(completion: @escaping AuthTokenRetrievalHandler) @objc func onAuthFailure(_ authFailure: AuthFailure) }
For example, you might use your AppDelegate as your IterableAuthDelgate:
extension AppDelegate: IterableAuthDelegate { // ... func onAuthTokenRequested(completion: @escaping AuthTokenRetrievalHandler) { // Fetch a JWT token for the signed-in user, from your server, and // return it to the SDK. completion("<JWT_TOKEN_FOR_THE_CURRENT_USER>") } func onAuthFailure(_ authFailure: AuthFailure) { // Inspect the authFailure enum case and take any necessary action. For // example, you can pause auth retries (see section 5.5.3, below). } // ... } // Then, when initializing the SDK... let config = IterableConfig() config.authDelegate = self IterableAPI.initialize(apiKey: "<YOUR_API_KEY>", launchOptions:launchOptions, config:config)
IMPORTANT
You'll need to keep a strong reference to your IterableAuthDelegate instance.
IterableConfig only holds a weak reference to it.
onAuthTokenRequested
The SDK calls onAuthTokenRequested when it needs a new JWT token for the
signed-in user. This method should fetch a new JWT token from your server and
return it to the SDK as a string.
This method is called when:
- You identify a user by calling
setEmailorsetUserId. - You update a user's email address by calling
updateEmail. - The current JWT token has expired, or is about to expire.
- The SDK receives a JWT-related
401response from Iterable's API.
onAuthFailure
The SDK calls onAuthFailure after it fails to fetch a new JWT token for the
signed-in user. The AuthFailure object passed to this method describes the
reason for the failure, along with other information.
This method is called when:
-
onAuthTokenRequestedreturnsnull. -
onAuthTokenRequestedthrows an exception. - The SDK receives a JWT-related
401response from Iterable's API. - The token returned by
onAuthTokenRequestedis invalid.
In onAuthFailure, to determine the reason for the failure, inspect the
AuthFailure object, which has these properties:
-
userKey- A string that identifies the user byuserIdoremail. -
failedAuthToken- The JWT token that caused the failure. -
failedRequestTime- The timestamp of the failed request, if applicable. -
failureReason- AnAuthFailureReasonenum case that indicates the reason for the failure.
AuthFailureReason can be:
-
authTokenExpirationInvalid– An auth token's expiration must be less than one year from its issued-at time. -
authTokenExpired– The token has expired. -
authTokenFormatInvalid– Token has an invalid format (failed a regular expression check). -
authTokenGenerationError–onAuthTokenRequestedthrew an exception. -
authTokenGenericError– Any other error not captured by another constant. -
authTokenInvalidated– Iterable has invalidated this token and it cannot be used. -
authTokenNull–onAuthTokenRequestedreturned a null JWT token. -
authTokenPayloadInvalid– Iterable could not decode the token's payload (iat,exp,email, oruserId). -
authTokenSignatureInvalid– Iterable could not validate the token's authenticity. -
authTokenUserKeyInvalid– The token doesn't include anemailor auserId. Or, one of these values is included, but it references a user that isn't in the Iterable project. -
authTokenMissing– The request to Iterable's API did not include a JWT authorization header.
TIP
You can also provide a JWT token for the current user by passing it directly to
setEmail or setUserId.
# Step 6.6.2: Set an expiring token refresh period
To specify how long before the expiration of the user's current JWT token
the SDK should call your auth token refresh handler,
to fetch a new token, set expiringAuthTokenRefreshPeriod on IterableConfig:
let config = IterableConfig() // ... other configuration options ... config.expiringAuthTokenRefreshPeriod = 45.0 IterableAPI.initialize(apiKey: "<YOUR_API_KEY>", launchOptions:launchOptions, config:config)
# Step 6.6.3: Set an auth retry policy
To control how the SDK handles consecutive JWT token refresh attempts, specify an auth retry policy. An auth retry policy allows you to control:
- The number of consecutive times the SDK should attempt to refresh a user's JWT token, in between successful API calls, before giving up.
- The interval between those attempts.
- A backoff strategy.
// When creating a RetryPolicy object, specify a maximum number of retries, an // interval between retries, and a backoff strategy: .linear or .exponential. // The SDK's default RetryPolicy has a maximum of 10 retries, an interval of 6 // seconds, and a linear backoff strategy. let config = IterableConfig() // ... other configuration options ... config.retryPolicy = RetryPolicy(maxRetry: 10, retryInterval: 5, retryBackoff: .linear) IterableAPI.initialize(apiKey: "<YOUR_API_KEY>", config: config)
After the SDK reaches the maximum number of consecutive JWT-related request
failures, as configured by your RetryPolicy, it stops attempting to refresh
the JWT token.
Auto-retry for offline processing (6.7.0+)
In addition to the RetryPolicy above (which controls JWT refresh scheduling),
the SDK supports automatic retry for offline-queued tasks that fail due to JWT
expiration. When this feature is enabled, the offline task runner pauses
authenticated tasks on a 401 error, refreshes the JWT, and retries
automatically. Unauthenticated API calls continue processing while
authentication is paused. This feature requires no code changes.
This feature is not enabled by default. To turn it on for your project, ask your Iterable customer success manager to enable it for your account.
# Step 6.6.4: Pause JWT token refresh
You can manually pause JWT token refresh attempts. To do this, call:
IterableAPI.pauseAuthRetries(true) // or false
When JWT refresh attempts have been paused, they'll only resume after:
- You provide a new JWT token to the SDK, by calling
setAuthToken. - You identify the user by setting
setEmailorsetUserId. - You update the user's email by calling
updateEmail. - The app restarts.
- You manually pause and unpause JWT token refresh attempts, by calling:
// If you didn't manually pause JWT refresh attempts in the first place, // first pause the retries, and then unpause them. IterableAPI.pauseAuthRetries(true) IterableAPI.pauseAuthRetries(false)
# Step 7: Enable push notifications
IMPORTANT
Iterable sends push notifications to iOS apps for two reasons:
- When you send push notification campaigns
- Silently, to tell the app to download new in-app messages
Because Iterable uses silent push notifications to help deliver in-app messages, configure your app to support push notifications even if you do not plan to send push notification campaigns.
To enable push notifications, follow the steps described below.
# Step 7.1: Set up iOS push notifications in Iterable
Follow the instructions in Iterable's Setting up iOS Push Notifications guide. This document describes how to configure your iOS app's App ID to use push notifications, and how to set up a mobile app (and associated push integration) in Iterable's web app.
# Step 7.2: Add the Push Notifications capability to your app
Follow Apple's instructions to add the Push Notifications capability to your app.
If you'll be sending Time Sensitive push notifications (introduced in iOS 15), also add the Time Sensitive Notifications capability. For more information about Time Sensitive notifications, check out this WWDC 2021 talk.
# Step 7.3: Enable the Remote Notifications background mode
Follow Apple's instructions to enable the Remote Notifications background mode in your app.
# Step 7.4: Fetch a device token from Apple and register it with Iterable
For Iterable to send push notifications to an iOS device, it must know the unique token assigned to that device by Apple.
By default, Iterable's SDK automatically fetches this token from Apple when the
application's code sets IterableAPI.email or IterableAPI.userId (which also
disables the device token for the previous email or userId, preventing Iterable
from sending push notifications to that user on that device). To fetch the token,
the SDK calls registerForRemoteNotifications()
on UIApplication.
NOTES
If you set IterableConfig.autoPushRegistration to false, the SDK does not
automatically register for a device token. In this case:
- Call
registerForRemoteNotifications()to register for a token when necessary. - To manually disable push notifications for the current user, call
IterableAPI.disableDeviceForCurrentUser().
After fetching a device token, iOS passes it to the application(_:didRegisterForRemoteNotificationsWithDeviceToken:)
method on the app delegate. Configure this method to register the token with
Iterable's SDK, which saves it the user's Iterable profile:
Swift
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { IterableAPI.register(token: deviceToken) }
Objective-C
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { [IterableAPI registerToken:deviceToken]; }
# Step 7.5: Handle incoming push notifications and enable push notification tracking
To handle incoming push notifications, and to allow Iterable to track events when a user interacts with push notifications, follow these steps:
-
For some object in your app, conform to the
UNUserNotificationCenterDelegateprotocol (apps commonly use the app delegate for this purpose). Import theUserNotificationsframework, indicate that the class conforms to the protocol, and implement these methods:-
userNotificationCenter(_:willPresent:withCompletionHandler:)This method can be used to allow your app to display incoming push notifications when it is in the foreground.
-
userNotificationCenter(_:didReceive:withCompletionHandler:)iOS calls this method when a user interacts with a push notification. From here, Iterable's SDK can create events associated with these interactions.
-
Set this object as the delegate for the current
UNUserNotificationCenter.
For example, Iterable's Swift and Objective-C sample projects have app delegate code similar to the following:
Swift
class AppDelegate: UIResponder, UIApplicationDelegate { func application(_: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // ... UNUserNotificationCenter.current().delegate = self // ... } // ... } extension AppDelegate: UNUserNotificationCenterDelegate { public func userNotificationCenter(_: UNUserNotificationCenter, willPresent _: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { completionHandler([.badge, .banner, .list, .sound]) } public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { IterableAppIntegration.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler) } }
Objective-C
@implementation AppDelegate // In its .h file, the AppDelegate class declares that it conforms to UNUserNotificationCenterDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // ... UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; center.delegate = self; // ... } ##pragma mark - UNUserNotificationCenterDelegate - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler { completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionBanner | UNNotificationPresentationOptionList | UNNotificationPresentationOptionSound); } - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { [IterableAppIntegration userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler]; } @end
NOTES
To learn more about push notifications on iOS, read Apple's documentation about the UserNotifications framework.
# Step 7.6: (Optional) Request authorization to display push notifications
IMPORTANT
Complete the steps in this section if you plan to use Iterable to send push notification campaigns to your app. Otherwise, they are unnecessary.
iOS apps must have explicit user permission to display push notification alerts, play push notification sounds or update icon badges based on push notifications.
To request this permission, display a prompt by calling the requestAuthorization(options:completionHandler:)
method on UNUserNotificationCenter.
This is usually done from somewhere in the app delegate. For example:
Swift
UNUserNotificationCenter.current().requestAuthorization(options:[.alert, .badge, .sound]) { (success, error) in if success == true { // ... } }
Objective-C
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) { if (granted) { dispatch_async(dispatch_get_main_queue(), ^{ // ... }); } }];
TIP
To learn more about asking for permission to display notifications, read Apple's Asking Permission to Use Notifications guide.
# Step 8: Enable in-app messages
To enable in-app messages, follow these steps:
-
Iterable uses silent push notifications to notify an app about new in-app messages awaiting delivery. Because of this, enable push notifications even if you don't plan to send push notification campaigns.
-
Let Iterable's SDK know when the app receives a push notification. This way, it knows to go fetch waiting in-app messages.
To do this, implement the app delegate's
application(_:didReceiveRemoteNotification:fetchCompletionHandler:)method. In it, call the identically named method onIterableAppIntegration. For example: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]; }
TIP
You can also use this method to handle silent push notifications, inspecting their payload and kicking off any necessary actions.
# Step 9: Verify that the SDK can communicate with Iterable
To test that your app can communicate with Iterable:
-
In your app's code, after initializing the SDK with your API key, set
IterableAPI.emailto a specific email address:Swift
let config = IterableConfig() IterableAPI.initialize(apiKey: "<YOUR_API_KEY>", launchOptions:launchOptions, config:config) IterableAPI.email = "user@example.com"
Objective-C
IterableConfig *config = [[IterableConfig alloc] init]; [IterableAPI initializeWithApiKey:@"<YOUR_API_KEY>" launchOptions:launchOptions, config:config] IterableAPI.email = @"user@example.com";
-
Run the app on a physical device (not the simulator).
Registering for a push notification token from Apple can only be done on a physical device.
-
Check to make sure the new user is visible in Iterable:
Open the Iterable project associated with the API key used in your app's code.
Navigate to Audience > Contact Lookup.
Enter the email address used above and click Search Users.
The user's profile should appear.
If you're having trouble, make sure that you have:
# Embedded Messaging
To learn how to use Iterable's iOS SDK with Embedded Messaging, read Embedded Messages with Iterable's iOS SDK.
# Upgrading the SDK
This section describes how to upgrade from earlier versions of Iterable's iOS SDK.
# Upgrading to 6.7.0+
Version 6.7.0
of Iterable's iOS SDK removes the deprecated trackEmbeddedDismiss and
trackEmbeddedImpression methods and their underlying API endpoints. If your app
references them, before upgrading, remove any calls to them and then follow the steps
in Embedded Messages with Iterable's iOS SDK
to use EmbeddedSessionManager.shared to track sessions and impressions. These steps are
required to track embedded message sessions and impressions once you've removed the
deprecated methods.
This update also provides a way to enable automatic retry for JWT 401 failures that occur during offline event processing. The setting is disabled by default, so contact your Iterable customer success manager to enable it for your project. No code changes are required. For more information, see auto-retry note in Step 6.6.3: Set an auth retry policy.
# Upgrading to 6.6.6+
Version 6.6.6
makes IterableAPI.isIterableDeepLink(_:) public so apps can call it directly before
handling a URL. It also includes fixes for Carthage, shared keychain access groups,
and full-screen in-app message display.
No code changes are required for this update.
# Upgrading to 6.6.5+
If your app uses Embedded Messaging, upgrade to Version 6.6.5 if you want to manage embedded message sync successes or failures in your
own code using the optional sync callbacks that are now available through
IterableEmbeddedUpdateDelegate. With this release, you can also sync messages
for specific placements instead of all placements at once using the new
placementIds parameter for IterableEmbeddedManager.syncMessages.
In addition, this release improves retry behavior for concurrent API requests that fail with JWT-related 401 errors.
No code changes are required for this update.
# Upgrading to 6.6.0+
To enable Unknown User Activation, upgrade to Version 6.6.0 of Iterable's iOS SDK and set enableUnknownUserActivation to true on IterableConfig
before initializing the SDK. These code changes are only required if you want to use Unknown User
Activation; otherwise, no changes are required.
let config = IterableConfig() config.enableUnknownUserActivation = true IterableAPI.initialize(apiKey: "<YOUR_API_KEY>", launchOptions: launchOptions, config: config)
IMPORTANT
As of 6.7.1,
enableUnknownUserActivation defaults to false. In versions 6.6.0 through
6.7.0 it defaulted to true, so if your app relied on this setting, set it to true
explicitly when you upgrade.
For more information, read Unknown User Activation: Developer Docs.
# Upgrading to 6.5.13+
Version 6.5.13 of
Iterable's iOS SDK requires allowedProtocols be set as part of URL validation
when handling deep links.
# Upgrading to 6.5.5+
Version 6.5.5 of Iterable's iOS SDK provides more insight into JWT refresh failures, so you can take appropriate action in your application code.
-
When a JWT refresh fails (for any of various reasons), the SDK calls
onAuthFailure(_ authFailure: AuthFailure)on theIterableAuthDelegateinstance you provided to the SDK at initialization. TheAuthFailureobject provides more information about the failure.Note that
onAuthFailure(_ authFailure: AuthFailure)replacesonTokenRegistrationFailed(_ reason: String?). If you've implementedonTokenRegistrationFailed, you'll need to update your application code. -
To set a retry policy for JWT refreshes, you can set the
retryPolicyproperty onIterableConfigto aRetryPolicyobject. Use this object to specify:- The maximum number of consecutive JWT-related request failures the SDK should allow before giving up, Defaults to 10.
- The interval between each JWT refresh attempt. Defaults to 6 seconds.
- A backoff strategy: linear or exponential. Defaults to linear.
You manually pause JWT refresh attempts by calling
IterableAPI.pauseAuthRetries(true)
For more information, see Step 6.6.1: Register an auth handler.
# Upgrading to 6.4.9+
Version 6.4.9 of Iterable's iOS SDK makes it possible to store in-app messages in memory, rather than in an unencrypted local file. However, an unencrypted local file is still the default option.
To store in-app messages in memory, set useInMemoryStorageForInApps to true:
Swift
let config = IterableConfig() config.useInMemoryStorageForInApps = true IterableAPI.initialize(apiKey: "<YOUR_API_KEY>", launchOptions:launchOptions, config:config)
Objective-C
IterableConfig *config = [[IterableConfig alloc] init]; config.useInMemoryStorageForInApps = YES; [IterableAPI initializeWithApiKey:@"<YOUR_API_KEY>" launchOptions:launchOptions, config:config];
When users upgrade to a version of your iOS app that uses this version of the SDK (or higher), and you've enabled this option, the local file used for in-app message storage (if it already exists) is deleted. However, no data is lost.
# Upgrading to 6.4.8+
Starting with version 6.4.8, Iterable's iOS SDK, as a privacy enhancement, encrypts the following data when storing it at rest:
-
email— The user's email address. -
userId— The user's ID. -
authToken— The JWT used to authenticate the user with Iterable's API. -
lastPushPayload— The JSON payload that came along with the last push notification received by the app.
(Note that Iterable's iOS SDK does not store in-app messages at rest—before or after this update.)
NOTE
Iterable's iOS SDK does, in fact, store in-app messages in an unencrypted local file. However, version 6.4.9 provides an option to store them in memory, instead.
When a user upgrades to a version of your app that uses this version of the SDK (or higher), these fields are encrypted. No data that's already stored is lost.
For more information about the encryption described above, examine the SDK source code:
# Upgrading to 6.4.0+
Starting with version 6.4.0
of Iterable's iOS SDK, you'll need to declare the URL protocols that the SDK
should expect to see on incoming links (and then handle as needed). For more
information, read Set the allowedProtocols field.
# Upgrading from a version prior to 6.1.0
Versions 6.1.0+ of the SDK require Xcode 10.2 or higher.
-
In-app messages
-
spawnInAppNotificationThe
spawnInAppNotificationmethod is no longer needed, and will fail to compile. The SDK now displays in-app messages automatically. There is no need to poll the server for new messages. -
Handling manually
To manually control when in-app messages display, set
IterableConfig.inAppDelegate(anIterableInAppDelegateobject). From itsonNewmethod, return.skip.To get the queue of available in-app messages, call
IterableApi.inAppManager.getMessages(). Then, callIterableApi.inAppManager.show(message)to show a specific message. -
Custom actions
The SDK now reserves the
iterable://URL scheme for Iterable-defined actions handled by the SDK, and theaction://URL scheme for custom actions handled by the mobile application's custom action handler.If you are currently using the
itbl://URL scheme for custom actions, the SDK will still pass these actions to the custom action handler. However, support for this URL scheme will eventually be removed (timeline TBD), so it is best to move to theaction://URL scheme as you can.
-
-
Consolidated deep link URL handling
By default, the SDK handles deep links using the URL delegate assigned to
IterableConfig. -
Checking if a URL is an Iterable deep link
To check if a URL is an Iterable deep link before handling it, use the
isIterableDeepLinkmethod:if IterableAPI.isIterableDeepLink(urlString) { // URL is an Iterable deep link }
This method returns
trueif the URL matches the Iterable deep link pattern (URLs containing/a/in the path). For more information, read iOS Universal Links.
# Further reading
- Identifying the User
- Updating User Profiles
- Tracking Events with Iterable's Mobile SDKs
- Setting up iOS Push Notifications
- Advanced iOS Push Notifications
- In-App Messages on iOS
- Setting up Mobile Inbox on iOS
- Customizing Mobile Inbox on iOS
- iOS Universal Links
- Deep Links in Push Notifications
- Sample apps that use Iterable's iOS SDK
- Configuring Deep Links for Email or SMS
- JWT-Enabled API Keys