The Iterable Android SDK is a Java implementation of an Android client for Iterable, supporting Android API versions 15 and higher.
Before you even start with the SDK, you will need to:
- Set your application up to receive push notifications
- Set up a push integration in Iterable. This allows Iterable to communicate on your behalf with Firebase Cloud Messaging.
For more details, read Iterable's Setting up Android Push Notifications guide.
Congratulations, you've configured your Iterable project to send push notifications to your app! Now, let's set up the Iterable SDK.
âš IMPORTANT Beta versions of this SDK are subject to Iterable's Beta Mobile SDK Terms of Service.
The current beta version of the SDK is 3.2.0-beta1. Beta releases are not published to Maven; instead, use Jitpack:
-
Add the JitPack repository to your build file. Add it in your root build.gradle at the end of repositories:
allprojects { repositories { ... maven { url 'https://jitpack.io' } } } -
Add Iterable SDK dependencies:
implementation 'com.github.Iterable.iterable-android-sdk:iterableapi:3.2.0-beta1' implementation 'com.github.Iterable.iterable-android-sdk:iterableapi-ui:3.2.0-beta1'
The SDK adds a FirebaseMessagingService to the app manifest automatically, so you don't have to do any extra setup to handle incoming push messages.
If your application implements its own FirebaseMessagingService, make sure you forward onMessageReceived and onNewToken calls to IterableFirebaseMessagingService.handleMessageReceived and IterableFirebaseMessagingService.handleTokenRefresh, respectively:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
IterableFirebaseMessagingService.handleMessageReceived(this, remoteMessage);
}
@Override
public void onNewToken(String s) {
IterableFirebaseMessagingService.handleTokenRefresh();
}
}Note that FirebaseInstanceIdService is deprecated and replaced with onNewToken in recent versions of Firebase.
-
In-app messages:
spawnInAppNotification-
spawnInAppNotificationis no longer needed and will fail to compile. The SDK now displays in-app messages automatically. For more information, see In-app messages. -
There is no need to poll the server for new messages.
-
-
In-app messages: handling manually
-
To control when in-app messages display (rather than displaying them automatically), set
IterableConfig.inAppHandler(anIterableInAppHandlerobject). From itsonNewInAppmethod, returnInAppResponse.SKIP. -
To get the queue of available in-app messages, call
IterableApi.getInstance().getInAppManager().getMessages(). Then, callIterableApi.getInstance().getInAppManager().showMessage(message)to show a specific message. -
For more details, see In-app messages.
-
-
In-app messages: custom actions
-
This version of the SDK 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. For more details, see Handling in-app message buttons and links. -
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 templates to theaction://URL scheme as it's possible to do so.
-
-
Consolidated deep link URL handling
- By default, the SDK handles deep links with the the URL handler
assigned to
IterableConfig. Follow the instructions in Deep linking to migrate any existing URL handling code to this new API.
- By default, the SDK handles deep links with the the URL handler
assigned to
-
In the
onCreatemethod of theApplication, initialize the Iterable SDK:IterableConfig config = new IterableConfig.Builder() .setPushIntegrationName("myPushIntegration") .build(); IterableApi.initialize(context, "<your-api-key>", config);
- The
apiKeyshould correspond to the API key of your project in Iterable. If you'd like, you can specify a differentapiKeydepending on whether you're building inDEBUGorPRODUCTION, and point the SDK to the relevant Iterable project.
âš Don't call
IterableApi.initializefromActivity#onCreate; it is necessary for Iterable SDK to be initialized when the application is starting, to make sure everything is set up regardless of whether the app is launched to open an activity or is woken up in background as a result of an incoming push message. - The
-
Once you know the email (Preferred) or userId of the user, call
setEmailorsetUserId- EMAIL:
IterableApi.getInstance().setEmail("email@example.com"); - USERID:
IterableApi.getInstance().setUserId("userId");
âš 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.
- EMAIL:
-
Register for remote notifications
Iterable SDK automatically registers the push token with Iterable whenever
setEmailorsetUserIdis called.âš This default behavior is the preferred way of handling token registrations.
If you want to trigger token registration manually, first disable automatic registration by calling
setAutoPushRegistration(false)onIterableConfig.Builderwhen initializing the SDK.Than call
registerForPushwhenever you want to register the token:IterableApi.getInstance().registerForPush();This will take care of retrieving the token and registering it with Iterable.
âš Device registration will fail if user email or userId is not set. If you're calling
setEmailorsetUserIdafter the app is launched (i.e. when the user logs in), make sure you callregisterForPush()again to register the device with the logged in user.
Congratulations! You can now send remote push notifications to your device from Iterable!
When a user logs out, you typically want to disable push notifications to that user/device. This can be accomplished by calling disablePush(). Please note that it will only attempt to disable the device if you have previously called registerForPush().
In order to re-enable push notifcations to that device, simply call registerForPush() as usual when the user logs back in.
Notifications are rendered with the app launcher icon by default. To specify a custom icon for notifications, add this line to AndroidManifest.xml:
<meta-data android:name="iterable_notification_icon" android:resource="@drawable/ic_notification_icon"/>where ic_notification_icon is the name of the notification icon.
Add this line to AndroidManifest.xml to specify the notification color:
<meta-data android:name="iterable_notification_color" android:value="#FFFFFF"/>where #FFFFFF can be replaced with a hex representation of a color of your choice. In stock Android, the notification icon and action buttons will be tinted with this color.
You can also use a color resource:
<meta-data android:name="iterable_notification_color" android:resource="@color/notification_color"/>Since Android 8.0, Android requires apps to specify a channel for every notification. Iterable uses one channel for all notification; to customize the name of this channel, add this to AndroidManifest.xml:
<meta-data android:name="iterable_notification_channel_name" android:value="Notifications"/>You can also use a string resource to localize the channel name:
<meta-data android:name="iterable_notification_channel_name" android:resource="@string/notification_channel_name"/>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 onNewInApp method of IterableConfig.inAppHandler (an object of type IterableInAppHandler). To override the default behavior, set inAppHandler in IterableConfig to a custom class that overrides the onNewInApp method. onNewInApp should return InAppResponse.SHOW to show the incoming in-app message or InAppResponse.SKIP to skip showing it.
class MyInAppHandler implements IterableInAppHandler {
@Override
public InAppResponse onNewInApp(IterableInAppMessage message) {
if (/* add conditions here */) {
return InAppResponse.SHOW;
} else {
return InAppResponse.SKIP;
}
}
}
// ...
IterableConfig config = new IterableConfig.Builder()
.setPushIntegrationName("myPushIntegration")
.setInAppHandler(new MyInAppHandler())
.build();
IterableApi.initialize(context, "<your-api-key>", config);The SDK keeps the local in-app message queue in sync by checking the server queue every time the app goes into foreground, and via silent push messages that arrive from Iterable servers to notify the app whenever a new in-app message is added to the queue.
To access the in-app message queue, call IterableApi.getInstance().getInAppManager().getMessages(). To show a message, call IterableApi.getInstance().getInAppManager().showMessage(message).
// Get the in-app messages list
IterableInAppManager inAppManager = IterableApi.getInstance().getInAppManager();
List<IterableInAppMessage> messages = inAppManager.getMessages();
// Show an in-app message
inAppManager.showMessage(message);
// Show an in-app message without consuming (not removing it from the queue)
inAppManager.showMessage(message, false, null);The SDK handles in-app message buttons and links as follows:
-
If the URL of the button or link uses the
action://URL scheme, the SDK passes the action toIterableConfig.customActionHandler.handleIterableCustomAction(). IfcustomActionHandler(anIterableCustomActionHandlerobject) has not been set, the action will not be handled.- For the time being, the SDK will treat
itbl://URLs the same way asaction://URLs. However, this behavior will eventually be deprecated (timeline TBD), so it's best to migrate to theaction://URL scheme as it's possible to do so.
- For the time being, the SDK will treat
-
The
iterable://URL scheme is reserved for action names predefined by the SDK. If the URL of the button or link uses aniterable://URL known to the SDK, it will be handled automatically and will not be passed to the custom action handler.- The SDK does not yet recognize any
iterable://actions, but may do so in the future.
- The SDK does not yet recognize any
-
The SDK passes all other URLs to
IterableConfig.urlHandler.handleIterableURL(). IfurlHandler(anIterableUrlHandlerobject) has not been set, or if it returnsfalsefor the provided URL, the URL will be opened by the system (using a web browser or other application, as applicable).
To customize the time delay between successive in-app messages, set inAppDisplayInterval on IterableConfig to an appropriate value in seconds. The default value is 30 seconds.
Apps using version 3.2.0 and later of this SDK can save in-app messages to an inbox. This inbox displays a list of saved in-app messages and allows users to read and interact with them at their convenience. The SDK provides a default user interface for the inbox, and it can be customized to match your brand's styles.
To configure an in-app message to use the inbox, marketers should:
- Enable the Show in Inbox toggle in the in-app message's template
- Choose whether or not to Deliver Silently to Inbox (so that the message does not display prominently when the device receives it, but can be viewed later by the user)
Add a new dependency, iterableapi-ui, to your build.gradle file:
compile 'com.iterable:iterableapi-ui:3.2.0-beta1'To open Inbox as a separate activity, launch IterableInboxActivity. The SDK also provides IterableInboxFragment if you need to embed the Inbox UI within an existing activity.
You can embed IterableInboxFragment either via a layout .xml file, or by calling IterableInboxFragment.newInstance() and inserting it into your activity.
It's also possible to show the inbox when a user taps a button (or completes some other action). To do this, respond to the user's action by starting IterableInboxActivity. For example:
// Add this in your button handler
startActivity(this, IterableInboxActivity.class);The SDK provides various ways to customize the inbox's interface to match your brand's styles. For simpler customization needs, specify a custom XML layout ID by calling setItemLayoutId on the IterableInboxFragment. For more advanced scenarios, define classes that inherit from IterableInboxFragment and InboxRecyclerViewAdapter and override existing methods as necessary.
IterableInboxFragment and IterableInboxActivity can display inbox messages in two ways:
POPUP- (default): Displays the inbox message as a dialog on top of the Inbox UI.ACTIVITY- Displays the inbox message in a new activity.
To completely change the look of an inbox, copy the contents of fragment_inbox_item.xml from iterableapi-ui into a new layout XML in your project and modify it. Then call setItemLayoutId on the IterableInboxFragment in onCreate of the parent activity to specify the custom layout XML for Inbox cells.
An inbox lists saved in-app messages. Because of this, Iterable events that apply to in-app messages also apply to inbox messages. These events are described below:
This event is triggered when an in-app message is sent to a user.
Important event properties:
eventType-inAppSendcreatedAt- when the in-app message was sentcampaignId- the in-app message campaign ID
This event is triggered when an in-app message is received by a user's device.
Important event properties:
eventType-inAppDeliverycreatedAt- when the in-app message was received by the devicecampaignId- the in-app message campaign ID
This event tracks the number of unique times a message appeared in the inbox during a single inbox session (period when the user had the inbox open). The total represents the count of unique times the message displayed on-screen in the inbox during an inbox session (not the number of times the user actually opened that message).
Important event properties:
eventType-inboxMessageImpressioncreatedAt- when the event was createdcampaignId- the in-app message campaign IDimpressionCount- how many times the message was visible in the inbox during the inbox sessiontotalDuration- the total duration of time (in seconds) the message was visible in the inbox
This event is triggered when the user taps a message in the inbox to view its contents.
Important event properties:
eventType-inAppOpencreatedAt- when the in-app message was openedcampaignId- the in-app message campaign ID
This event is triggered when the user taps on a link or button in an in-app message.
Important event properties:
eventType-inAppClickcreatedAt- when the button in the in-app message was tappedcampaignId- the in-app message campaign IDclickedUrl- the URL associated with the tapped link/button
This event is triggered when the user closes an inbox message by tapping a close button or a back button. Close buttons/links should have URL iterable://dismiss. Tapping a close button/link also creates an inAppClick event.
Important event properties:
eventType-inAppClosecreatedAt- when the in-app message was closedcampaignId- the in-app message campaign IDcloseAction- the type of item the user tapped:link(for buttons/links),backfor a back button, orother
This event is triggered when the user deletes an inbox message by swiping left on it and tapping the Delete button, or when the user taps a delete button/link in the in-app message, which should have a URL of iterable://delete. Tapping a delete button/link also creates an inAppClick event and an inAppClose event.
Important event properties:
eventType-inAppDeletecreatedAt- when the in-app message was deletedcampaignId- the in-app campaign IDdeleteAction- how the message was deleted (inbox-swipeif the user swiped left in the inbox and tapped Delete, ordelete-buttonif the user tapped a button/link with URLiterable://delete).
This event captures information about an inbox session, which starts when a user opens the inbox and ends when they navigate away (or close/minimize the app). Viewing a message in the inbox does not end the session.
Important event properties
eventType-inboxSessioncampaignId- the in-app campaign idinboxSessionStart- when the session startedinboxSessionEnd- when the session endeduniqueImpressionCount- no of unique messages visible in the Inbox message list to the user during the inbox sessionstartTotalMessageCount- the number of messages in the inbox at the session's startendTotalMessageCount- the number of messages in the inbox at the session's end (messages can be added or removed during a session)
Push notifications and action buttons may have openUrl actions attached to them. When a URL is specified, the SDK first calls the urlHandler specified in your IterableConfig object. You can use this class to handle openUrl actions the same way as you handle normal deep links. If the handler is not set or returns NO, the SDK will open a browser with that URL.
// MyApplication.java
@Override
public void onCreate() {
super.onCreate();
...
IterableConfig config = new IterableConfig.Builder()
.setPushIntegrationName("myPushIntegration")
.setUrlHandler(this)
.build();
IterableApi.initialize(context, "YOUR API KEY", config);
}
@Override
public boolean handleIterableURL(Uri uri, IterableActionContext actionContext) {
// Assuming you have a DeeplinkHandler class that handles all deep link URLs and navigates to the right place in the app
return DeeplinkHandler.handle(this, uri);
}For App Links to work with link rewriting in emails, you need to set up an assetlinks.json file in the Iterable project. For more information, read Setting up Android App Links.
If you already have a urlHandler (see Handling links from push notifications), the same handler can be used for email deep links by calling handleAppLink in the activity that handles all app links in your app:
// MainActivity.java
@Override
public void onCreate() {
super.onCreate();
...
handleIntent(getIntent());
}
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (intent != null) {
handleIntent(intent);
}
}
private void handleIntent(Intent intent) {
if (Intent.ACTION_VIEW.equals(intent.getAction()) && intent.getData() != null) {
IterableApi.handleAppLink(intent.getDataString());
// Overwrite the intent to make sure we don't open the deep link
// again when the user opens our app later from the task manager
setIntent(new Intent(Intent.ACTION_MAIN));
}
}Alternatively, call getAndTrackDeeplink along with a callback to handle the original deep link URL. You can use this method for any incoming URLs, as it will execute the callback without changing the URL for non-Iterable URLs.
IterableApi.getAndTrackDeeplink(uri, new IterableHelper.IterableActionHandler() {
@Override
public void execute(String result) {
Log.d("HandleDeeplink", "Redirected to: "+ result);
// Handle the original deep link URL here
}
});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 Play Store to install it. If the app uses the Iterable SDK and has deferred deep linking enabled, the content associated with the deep link will load on first launch.
Set checkForDeferredDeeplink to true on IterableConfig when initializing the SDK to enable deferred deep linking for Iterable SDK. Make sure a urlHandler is also set up to handle deep links to open the right content within your app on first launch (see above for details).
The recommended migration path is to upgrade the existing Google Cloud project to Firebase, update the server token in the existing GCM push integration in Iterable with the new Firebase token, and update the Android app to support Firebase. If you keep using the same project for FCM and the same integration name, the old tokens will still be valid and won't require re-registration of existing devices.
If you're using a different project for FCM and have existing devices on a GCM project with a different sender ID, updating the app will generate new tokens for users, but the old tokens will still be valid. When migrating from one sender ID to another, specify legacyGCMSenderId in IterableConfig when initializing the SDK. This will disable old tokens to make sure users won't receive duplicate notifications.
For more information, take a look at:
- Iterable's Android SDK Release Notes
- Iterable's Setting up Android Push Notifications guide
- Iterable's 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.