map-o file-code-o arrow-directionplatform-webreach-project-type-boarding-passreach-project-type-couponreach-project-type-event-ticketreach-project-type-genericreach-project-type-gift-cardreach-project-type-loyalty-cardreach-project-type-member-card pictures more_vert chain

Android

This guide is a high level overview of the Urban Airship platform for Android and Amazon devices. We’ll first cover the basic details of app setup before moving on to push notifications, client-side customization, and making use of our growing suite of integration and engagement tools.

Resources

Getting Started

There are a few important steps to get out of the way when integrating Urban Airship with your app for the first time. Follow these instructions carefully to ensure that you will have a smooth development experience.

Configure a Push Provider

Before any push notifications can be sent, you must set up some form of push transport. Urban Airship supports push notifications for Android devices via Google’s GCM (Google Cloud Messaging for Android) and FCM (Firebase Cloud Messaging for Android) services and for Amazon devices via Amazon’s ADM (Amazon Device Messaging).

Because the Android and Amazon platforms are so similar, you won’t need to tailor your transport settings specifically to either host. The SDK will automatically detect the device’s operating system and use the correct transport at runtime. For more information, see the FCM setup for Android, and the ADM setup for Amazon.

SDK Installation

Example build.gradle changes:

dependencies {
  ...

  // Urban Airship SDK
  compile 'com.urbanairship.android:urbanairship-sdk:8.3.+'

  // Recommended for in-app messaging
  compile 'com.android.support:cardview-v7:25.0.1'

  // Recommended for location services
  compile 'com.google.android.gms:play-services-location:9.8.0'
}

Add the Urban Airship SDK dependency to the application’s build.gradle file.

Create Airship Config Options

Example airshipconfig.properties:

developmentAppKey = Your Development App Key
developmentAppSecret = Your Development App Secret

productionAppKey = Your Production App Key
productionAppSecret = Your Production Secret

# Toggles between the development and production app credentials
# Before submitting your application to an app store set to true
inProduction = false

# LogLevel is "VERBOSE", "DEBUG", "INFO", "WARN", "ERROR" or "ASSERT"
developmentLogLevel = DEBUG
productionLogLevel = ERROR

# FCM/GCM Sender ID
gcmSender = Your Google API Project Number

# Notification customization
notificationIcon = ic_notification
notificationAccentColor = #ff0000

Airship config options are a convenient way to pass custom settings to your app without needing to edit the source code. By default the Urban Airship SDK loads these settings from the airshipconfig.properties file located in your application’s assets directory. Use this file, among other things, to set the backend credentials for your app, and to toggle between development and production builds.

TakeOff

Basic Autopilot integration:

<meta-data android:name="com.urbanairship.autopilot"
          android:value="com.urbanairship.Autopilot"/>

The Urban Airship SDK must be initialized before any receiver, service, or activity is created. This is achieved by calling takeOff manually in the application’s onCreate method or by using Autopilot .

Autopilot will automatically call takeOff when the application initializes without the need to override any Application methods. The class can be used directly to use configuration loaded from the airshipconfig.properties file. It can also be extended to customize the airship config and to receive a callback when the Airship instance is ready.

Customizing Autopilot

Extending Autopilot example:

public class SampleAutopilot extends AutoPilot {

  @Override
  public void onAirshipReady(@NonNull UAirship airship) {
      airship.getPushManager().setUserNotificationsEnabled(true);
  }

  @Override
  public AirshipConfigOptions createAirshipConfigOptions(@NonNull Context context) {
      AirshipConfigOptions options = new AirshipConfigOptions.Builder()
          .setDevelopmentAppKey("Your Development App Key")
          .setDevelopmentAppSecret("Your Development App Secret")
          .setProductionAppKey("Your Production App Key")
          .setProductionAppSecret("Your Production App Secret")
          .setInProduction(!BuildConfig.DEBUG)
          .setGcmSender("Your Google API Project Number") // FCM/GCM sender ID
          .setNotificationIcon(R.drawable.ic_notification)
          .setNotificationAccentColor(ContextCompat(getContext(), R.color.accent))
          .build();

      return options;
  }
}

Register the extended Autopilot class:

<meta-data android:name="com.urbanairship.autopilot"
          android:value="com.example.SampleAutopilot"/>

To use Autopilot, add metadata within the application entry to the AndroidManifest.xml. The name of the metata com.urbanairship.autopilot and the value should be the fully qualified class name.

Send Your First Push Notification

Enable user notifications:

UAirship.shared().getPushManager().setUserNotificationsEnabled(true);

At this point in the guide, if you followed all the steps above you should be ready to send a test push notification to verify everything is set up properly. Before sending a push, make sure you have enabled user notifications.

Follow Send Your First Notification or our API reference for details on sending the first notification.

Android Things

Urban Airship is compatible with devices running Android Things. Urban Airship treats devices running Android Things the same as standard Android devices throughout our stack. Push messages, in-app messaging, Message Center, and analytics are all supported.

Push Notifications

Disable user notifications:

UAirship.shared().getPushManager().setUserNotificationsEnabled(true);

Android Things does not support displaying notifications, so you will want to make sure setUserNotificationsEnabled is disabled. See Listening for Push Events to learn how to receive a callback when a new push message is received.

In-App Messaging

Enable in-app messaging ASAP mode:

UAirship.shared().getInAppMessageManager().setAutoDisplayEnabled(true);

If the device has a screen and you want to use in-app messaging, make sure displayASAPEnabled is enabled to display the in-app message as it’s received.

Urban Airship Channel IDs

String channelId = UAirship.shared().getPushManager().getChannelId();
Logger.info("My Application Channel ID: " + channelId);

The Channel ID is a unique identifier that ties together an application/device pair on Android and Amazon devices. The Channel ID is used to target pushes to specific devices using the Urban Airship API. Once a Channel ID is created, it will persist the application until it is either reinstalled, or its internal data is cleared.

Don’t worry if this value initially comes back as null on your app’s first run (or after clearing the application data), as the Channel ID will be created and persisted during registration. To receive an event when the Channel ID is created, see Listening for Push Events.

Listening for Airship Events

Sample AirshipReceiver:

public class SampleAirshipReceiver extends AirshipReceiver {

    private static final String TAG = "SampleAirshipReceiver";

    @Override
    protected void onChannelCreated(@NonNull Context context, @NonNull String channelId) {
        Log.i(TAG, "Channel created. Channel Id:" + channelId + ".");
    }

    @Override
    protected void onChannelUpdated(@NonNull Context context, @NonNull String channelId) {
        Log.i(TAG, "Channel updated. Channel Id:" + channelId + ".");
    }

    @Override
    protected void onChannelRegistrationFailed(Context context) {
        Log.i(TAG, "Channel registration failed.");
    }

    @Override
    protected void onPushReceived(@NonNull Context context, @NonNull PushMessage message, boolean notificationPosted) {
        Log.i(TAG, "Received push message. Alert: " + message.getAlert() + ". posted notification: " + notificationPosted);
    }

    @Override
    protected void onNotificationPosted(@NonNull Context context, @NonNull NotificationInfo notificationInfo) {
        Log.i(TAG, "Notification posted. Alert: " + notificationInfo.getMessage().getAlert() + ". NotificationId: " + notificationInfo.getNotificationId());
    }

    @Override
    protected boolean onNotificationOpened(@NonNull Context context, @NonNull NotificationInfo notificationInfo) {
        Log.i(TAG, "Notification opened. Alert: " + notificationInfo.getMessage().getAlert() + ". NotificationId: " + notificationInfo.getNotificationId());

        // Return false here to allow Urban Airship to auto launch the launcher activity
        return false;
    }

    @Override
    protected boolean onNotificationOpened(@NonNull Context context, @NonNull NotificationInfo notificationInfo, @NonNull ActionButtonInfo actionButtonInfo) {
        Log.i(TAG, "Notification action button opened. Button ID: " + actionButtonInfo.getButtonId() + ". NotificationId: " + notificationInfo.getNotificationId());

        // Return false here to allow Urban Airship to auto launch the launcher
        // activity for foreground notification action buttons
        return false;
    }

    @Override
    protected void onNotificationDismissed(@NonNull Context context, @NonNull NotificationInfo notificationInfo) {
        Log.i(TAG, "Notification dismissed. Alert: " + notificationInfo.getMessage().getAlert() + ". Notification ID: " + notificationInfo.getNotificationId());
    }
}

Register the receiver in the AndroidManifest.xml:

<receiver android:name=".SampleAirshipReceiver"
          android:exported="false">

    <intent-filter>
        <action android:name="com.urbanairship.push.CHANNEL_UPDATED" />
        <action android:name="com.urbanairship.push.OPENED" />
        <action android:name="com.urbanairship.push.RECEIVED" />
        <action android:name="com.urbanairship.push.DISMISSED" />
        <category android:name="${applicationId}" />
    </intent-filter>
</receiver>

To listen for push and registration events generated by the Urban Airship SDK, extend the AirshipReceiver .

AirshipReceiver is a base class that handles parsing the raw intents for the application and provides convenient listener style callbacks. Extend the class and register the receiver in the AndroidManifest.xml.

Push Notifications

Urban Airship’s SDK provides a simple interface for managing push notifications within your Android application.

Enabling User Notifications

Enable user notifications:

UAirship.shared().getPushManager().setUserNotificationsEnabled(true);

The Urban Airship SDK makes a distinction between “user notifications”, which can be seen by the user, and other forms of push that allow you to send data to your app silently.

Enabling or disabling user notifications is a preference often best left up to the user, so by default, user notifications are disabled. However they are easily enabled with a single call to the PushManager instance.

Quiet Time

// Set the quiet time from 7:30pm - 7:30am
SimpleDateFormat formatter = new SimpleDateFormat("hh:mm", Locale.US);
Date startDate = formatter.parse("19:30");
Date endDate = formatter.parse("07:30");

UAirship.shared().getPushManager().setQuietTimeInterval(startDate,endDate);

// Enable quiet time
UAirship.shared().getPushManager().setQuietTimeEnabled(true);

Quiet time disables push notification sounds and prevents the phone from vibrating during the set time frame.

Clearing Notifications

Clear all Notifications

NotificationManagerCompat.from(context).cancelAll();

Notifications can be cleared manually by using standard Android APIs on the NotificationManager or NotificationManagerCompat classes.

Customizing Push Notifications

The DefaultNotificationFactory is the recommended factory as it provides full support for all of the Android push features.

All incoming push notifications are built using a class that extends the NotificationFactory .

The Urban Airship SDK uses the DefaultNotificationFactory . With this factory, the standard Android Notification layout will use the application’s title and icon. A default big text style will be applied for all notifications.

Common customizations:

NotificationFactory factory = UAirship.shared().getPushManager().getNotificationFactory();

// Customize the factory
factory.setTitleId(R.string.app_title);
factory.setColor(ContextCompat.getColor(context, R.color.notification_color));

Accent color, notification icons, default sound, and default title can all be modified by calling the appropriate setter on any of the NotificationFactory instances.

Custom Notification Factories

Custom Factory Example:

public class CustomNotificationFactory extends NotificationFactory {

    public CustomNotificationFactory(Context context) {
        super(context);
    }

    @Override
    public Notification createNotification(PushMessage message, int notificationId) {
        // do not display a notification if there is not an alert
        if (UAStringUtil.isEmpty(message.getAlert())) {
            return null;
        }

        // Build the notification
        NotificationCompat.Builder builder = new NotificationCompat.Builder(getContext())
                .setContentTitle("Notification title")
                .setContentText(message.getAlert())
                .setAutoCancel(true)
                .setSmallIcon(R.drawable.notification_icon);

        // Notification action buttons
        builder.extend(new ActionsNotificationExtender(getContext(), message, notificationId));

        return builder.build();
    }

    @Override
    public int getNextId(PushMessage pushMessage) {
        return NotificationIDGenerator.nextID();
    }
}

Register the factory once UAirship is ready:

@Override
public void onAirshipReady(UAirship airship) {

    // Create a customized default notification factory
    CustomDefaultNotificationFactory notificationFactory;
    notificationFactory = new CustomDefaultNotificationFactory(UAirship.getApplicationContext());

    // Set the factory on the PushManager
    airship.getPushManager().setNotificationFactory(notificationFactory);
}

Custom notification factories are supported, but may cause some Android Push features to no longer work. It is up the factory the features that the factory implements will be available.

Available Notification Factories

The Urban Airship SDK contains several notification factories to help simplify creating custom notifications. Any one of them can be extended.

NotificationFactory
Base factory class. Builds notifications without any default styles.
DefaultNotificationFactory
The default SDK factory. Builds notifications with a default big text style.
CustomLayoutNotificationFactory
Builds custom layout notifications.

Available Notification Extenders

The SDK also provides several notification builder extenders to help support Android Push features.

ActionsNotificationExtender
Supports Android Notification Action Button API features.
PublicNotificationExtender
Supports Public Notification API features.
StyleNotificationExtender
Supports Android style API features.
WearableNotificationExtender
Supports Android Wear API features.

Addressing Devices

To help target specific devices or users for a notification, we have Tags, Named Users and Tag Groups.

Tags

Modifying tags:

UAirship.shared().getPushManager().editTags()
    .addTag("some_tag")
    .removeTag("some_other_tag")
    .apply();

Tags allow you to attribute arbitrary metadata to a specific device. Common examples include favorites such as sports teams or news story categories.

Named Users

Setting the named user:

// Associate the channel to a Named User ID.
UAirship.shared().getNamedUser().setId("NamedUserID");

Associating the channel with a Named User ID, will implicitly disassociate the channel from the previously associated Named User ID, if it existed.

Named Users allow you to associate multiple devices to a single user or profile that may be associated with more than one device, e.g., an end-user’s Android phone and tablet. A device can have only one Named User, and a single Named User should not be associated with more than 20 devices. Named Users provide the ability to directly set tags on them (see Tag Groups).

By default, Named Users cannot be associated from the device. In this case if the devices attempts a Named User association, the association will fail and the SDK will log an error. In order to change this setting, see the Settings documentation.

Tag Groups

If setting channel tags is enabled during registration, the predefined device Tag Group cannot be modified from the device and will log an error message. Disable channel tags by setting setChannelTagRegistrationEnabled to false on the PushManager instnace if you want to modify this “default” Tag Group.

Channel Tag Group Example:

UAirship.shared().getPushManager().editTagGroups()
                .addTag("loyalty", "bronze-member")
                .removeTag("loyalty", "bronze-member")
                .setTag("games", "bingo")
                .apply();

Named User Tag Group Example:

UAirship.shared().getNamedUser().editTagGroups()
                .addTag("loyalty", "bronze-member")
                .removeTag("loyalty", "bronze-member")
                .setTag("games", "bingo")
                .apply();

Tag groups are configurable namespaces for organizing tags for the channel and Named User. Please view the Tag Groups documentation for more details. The Tag Group Walkthrough will guide you through the creation of your first Tag Group.

By default, Tag Groups cannot be modified from the device. In this case if a device attempts to modify Tag Groups, the modification will fail and the SDK will log an error. In order to change this setting, see the Settings documentation.

Custom Identifiers

Setting custom identifiers:

UAirship.shared().getAnalytics()
           .editAssociatedIdentifiers()
           .addIdentifier("key", "value")
           .apply();

Automatically track the Android Advertising ID:

UAirship.shared().getAnalytics().setAutoTrackAdvertisingIdEnabled(true);

In addition to Named Users, tags and Tag Groups, you can assign up to 20 custom identifiers to users. Identifiers that define additional ways of looking at a user— for example, Android Advertising ID, Google Analytics CID, or any other identifier you deem significant – can be added to your users.

Custom identifiers will be visible in the Connect data stream. We recommend adding any IDs that you may want to be visible in Connect, even if Connect does not yet support the relevant integration. Unlike the other identifiers (e.g., tags), you cannot use custom identifiers to target your users.

Interactive Notifications

Urban Airship provides a set of standard Interactive Notification types (See: Built-In Interactive Notification Types). It is the type that determines which buttons and corresponding labels will be available when you send a push. See the next section for where to specify that in the push payload. You control what happens when you send the push separately, by tying each button ID to a specific action.

Custom Interactive Notification Types (Notification Action Button Groups)

Example:

// Define actions for the group
NotificationActionButton hiButtonAction = new NotificationActionButton.Builder("hi")
        .setLabel(R.string.hi)
        .setIcon(R.drawable.your_icon_file)
        .setPerformsInForeground(true)
        .build();

NotificationActionButton byeButtonAction = new NotificationActionButton.Builder("bye")
        .setLabel(R.string.bye)
        .setIcon(R.drawable.your_icon_file)
        .setPerformsInForeground(true)
        .build();

// Define the group
NotificationActionButtonGroup buttonGroup = new NotificationActionButtonGroup.Builder()
        .addNotificationActionButton(hiButtonAction)
        .addNotificationActionButton(byeButtonAction)
        .build();

// Add the custom group
airship.getPushManager().addNotificationActionButtonGroup("custom group", buttonGroup);

Urban Airship reserves category IDs prefixed with “ua_”. Any custom groups with that prefix will be dropped.

If you want to define a custom Interactive Notification type, you must register a new notification action button group.

Custom NotificationActionButtonGroups are supported by registering the groups with the PushManager right after UAirship.takeOff using the PushManager.addNotificationActionButtonGroup method.

In-App Messaging

In-App Messages are banner notifications that appear inside of your app, regardless of the opt-in/opt-out status of a user.

Display

Adjusting the auto display delay:

UAirship.shared()
        .getInAppMessageManager()
        .setAutoDisplayDelay(1000L); // 1 second

By default, in-app messages will only display a single banner on app foreground after a 3-second delay. You can change this behavior to display the in-app message without delay by adjusting the auto display delay.

Display ASAP Mode

Enabling display ASAP:

UAirship.shared()
        .getInAppMessageManager()
        .setDisplayAsapEnabled(true);

Exercise caution when using display ASAP mode. The default auto display behavior for in-app messages is designed to offer a balance between immediacy and user experience, by minimizing the chance of accidentally disrupting the user’s activities in your app. Push automation may also occasionally see latencies that result in associated in-app messages being displayed in unexpected contexts.

Enabling display ASAP will attempt to display the in-app message on arrival. If the app is currently in the background, the in-app message will be displayed on the next foreground after the auto display delay. If a message is already displaying when a new in-app message is received, the new message will be displayed after the auto display delay when the currently displayed message dismisses.

Manual Display

Disabling automatic display:

UAirship.shared()
        .getInAppMessageManager()
        .setAutoDisplayEnabled(false);

Manually displaying in-app messages:

UAirship.shared()
        .getInAppMessageManager()
        .showPendingMessage(activity);

Auto displaying in-app messages can be disabled, to either stop in-app messages or to manually handle when in-app messages should be displayed.

Exclude activity from displaying in-app messages:

<meta-data
      android:name="com.urbanairship.push.iam.EXCLUDE_FROM_AUTO_SHOW"
      android:value="true" />

Activities can be excluded from auto-displaying an in-app message. This is useful for preventing in-app message displays on screens where it would be detrimental for the user experience, such as splash screens, settings screens, or landing pages.

Custom Style

Example:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
   <!--Set the custom banner style-->
   <item name="inAppMessageBannerStyle">@style/AppBannerStyle</item>
</style>

<!-- Custom in-app message style -->
<style name="AppBannerStyle" parent="InAppMessage.Banner">
   <item name="cardElevation">20dp</item>
   <item name="bannerFontPath">"fonts/MyFont.ttf"</item>
   <item name="bannerPrimaryColor">#ff990f</item>
   <item name="bannerSecondaryColor">#334455</item>
   <item name="bannerNoDismissButton">false</item>
   <item name="bannerDismissButtonDrawable">@drawable/ic_close_white_18dp</item>
   <item name="bannerTextAppearance">@style/AppBannerTextAppearance</item>
   <item name="bannerActionButtonTextAppearance">@style/AppBannerActionButtonTextAppearance</item>
</style>

<!-- Custom in-app message text style -->
<style name="AppBannerTextAppearance" parent="InAppMessage.Banner.TextAppearance">
   <item name="android:textSize">30sp</item>
   <item name="android:textStyle">italic</item>
   <item name="urbanAirshipFontPath">"fonts/CustomBannerTextFont.ttf"</item>
</style>

<!-- Custom in-app message action button text style -->
<style name="AppBannerActionButtonTextAppearance" parent="InAppMessage.Banner.TextAppearance">
   <item name="android:textSize">18sp</item>
</style>

Sending in-app message color overrides is supported through the Message Composer and push API. Advanced styling is also supported by providing a custom banner view style in the applications theme with the attribute inAppMessageBannerStyle.

The banner view can be customized with the following attributes:

bannerFontPath
A path to custom font in the assets directory
bannerPrimaryColor
The default banner primary color
bannerSecondaryColor
The default banner secondary color
bannerDismissButtonDrawable
Custom drawable for the banner’s dismiss button
bannerNoDismissButton
Removes the banner dismiss button (still dismissible by swiping)
bannerTextAppearance
Text appearance style for the message’s text
bannerActionButtonTextAppearance
Text appearance style for the message’s text
urbanAirshipFontPath
Text appearance attribute that defines a path to custom font in the assets directory

If the CardView v7 support library is included, the banner view will be an extension of a CardView, so any of the card attributes also apply.

Message Center

Displaying the Message Center

Displaying the Message Center:

UAirship.shared().getInbox().startInboxActivity();

Message Center Display intent filter:

<intent-filter>
    <action android:name="com.urbanairship.VIEW_RICH_PUSH_INBOX" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

> Displaying a specific message:

<div class="highlight"><pre><code class="language-java" data-lang="java"><span></span><span class="n">UAirship</span><span class="o">.</span><span class="na">shared</span><span class="o">().</span><span class="na">getInbox</span><span class="o">().</span><span class="na">startMessageActivity</span><span class="o">(</span><span class="n">messageId</span><span class="o">);</span>
</code></pre></div>


<!-- Route message displays through a Message Center -->
<intent-filter>
    <action android:name="com.urbanairship.VIEW_RICH_PUSH_INBOX" />
    <data android:scheme="message"/>
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

Message display intent filter:

<intent-filter>
    <action android:name="com.urbanairship.VIEW_RICH_PUSH_MESSAGE" />
    <data android:scheme="message"/>
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

Parsing message from intents:

RichPushMessage message = null;

if (RichPushInbox.VIEW_INBOX_INTENT_ACTION.equals(intent.getAction()) {
    if (getIntent().getData().getScheme().equalsIgnoreCase(RichPushInbox.MESSAGE_DATA_SCHEME)) {
        String messageId = getIntent().getData().getSchemeSpecificPart();
        message = UAirship.shared().getInbox().getMessage(messageId);
    }
}

The Message Center can be displayed anytime by calling RichPushInbox.startInboxActivity() . A specific message can be displayed by calling RichPushInbox.startMessageActivity :

RichPushInbox.startInboxActivity() will either launch the MessageCenterActivity or it can be customized by the application by adding the appropriate intent filters to an activity in the AndroidManifest.xml.

Styling the Message Center

Example:

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
   <!-- Set the custom Message Center style -->
   <item name="messageCenterStyle">@style/AppTheme.MessageCenter</item>
</style>

 <style name="AppTheme.MessageCenter" parent="MessageCenter">
     <item name="messageCenterDividerColor">#44000000</item>
     <item name="messageCenterItemIconEnabled">true</item>
     <item name="messageCenterItemTitleTextAppearance">@style/AppTheme.MessageCenter.TitleTextAppearance</item>
     <item name="messageCenterItemDateTextAppearance">@style/AppTheme.MessageCenter.DateTextAppearance</item>
 </style>

 <!-- Custom message title text style -->
 <style name="AppTheme.MessageCenter.TitleTextAppearance" parent="MessageCenter.Item.Title.TextAppearance">
     <item name="android:textSize">30sp</item>
     <item name="android:textStyle">italic</item>
     <item name="android:textColor">@android:color/black</item>
     <item name="urbanAirshipFontPath">"fonts/CustomFont.ttf"</item>
 </style>

 <!-- Custom message date text style -->
 <style name="AppTheme.MessageCenter.DateTextAppearance" parent="MessageCenter.Item.Date.TextAppearance">
     <item name="android:textSize">16sp</item>
     <item name="urbanAirshipFontPath">"fonts/CustomFont.ttf"</item>
 </style>

The Message Center can be styled by providing a custom style in the application’s theme with the attribute messageCenterStyle. The Message Center can be customized with the following attributes:

messageCenterItemBackground
A drawable for the message item’s background.
messageCenterItemTitleTextAppearance
Text appearance style for the message’s title
messageCenterItemDateTextAppearance
Text appearance style for the message’s date
messageCenterItemIconEnabled
Flag to enable message list icons instead of a checkbox
messageCenterItemIconPlaceholder
The default placeholder when using message list icons
messageNotSelectedTextAppearance
Text appearance style for the no message selected text when displaying the Message Center in a tablet view.
messageNotSelectedText
The string to use for the no message selected text when displaying the Message Center in a tablet view.
messageCenterEmptyMessageTextAppearance
Text appearance style for the empty message list text.
messageCenterEmptyMessageText
The string to use for the empty message list text.
messageCenterDividerColor
The message list divider color.
urbanAirshipFontPath
Text appearance attribute that defines a path to custom font in the assets directory

Message Center Filtering

Filtering messages:

RichPushInbox.Predicate pred = new RichPushInbox.Predicate() {
    @Override
    public boolean apply(RichPushMessage message) {
        return message.getTitle().contains("Cool");
    }
};

UAirship.shared().getMessageCenter().setPredicate(pred);

Sometimes it can be useful to filter the contents of the message center according to some predetermined pattern. To facilitate this, use the shared MessageCenter instance to set a predicate. Once set, only messages that match the predicate will be displayed.

Embedding the Message Center

Embedding the MessageCenterFragment in a layout xml:

<fragment
    android:name="com.urbanairship.messagecenter.MessageCenterFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Embedding the MessageCenterFragment using a fragment transaction:

MessageCenterFragment fragment = new MessageCenterFragment();
getSupportFragmentManager().beginTransaction()
                                   .replace(R.id.content_frame, fragment, "message_center")
                                   .commit();

The Message Center can be embedded in any FragmentActivity using MessageCenterFragment .

Actions

Urban Airship Actions provides a convenient way to automatically perform tasks by name in response to push notifications, Message Center App Page interactions and JavaScript.

An action is an abstraction over a unary function, which takes an argument and performs a defined task, producing an optional result. Actions may restrict or vary the work they perform depending on the arguments they receive, which may include type introspection and runtime context.

The Urban Airship SDK comes with pre-made actions for common tasks such as setting/modifying tags, showing a landing page, enabling deep linking, scheduling or canceling action schedules, and deep linking. Actions can also be extended to enable custom application behaviors and engagement experiences.

Actions are sent with a push by supplying a JSON payload as a push extra with the key com.urbanairship.actions. The JSON payload is a map of the action names to action values. The values can be any valid JSON value.

Action Situations

Actions are triggered with additional context in the form of a Situation, which corresponds to the way the action was triggered. The different situations allow actions to determine whether they should run, or potentially perform different behaviors depending on this context.

Action.SITUATION_MANUAL_INVOCATION
Action is invoked manually.
Action.SITUATION_PUSH_RECEIVED
Action is triggered when a push is received.
Action.SITUATION_PUSH_OPENED
Action is triggered when a notification is opened.
Action.SITUATION_WEB_VIEW_INVOCATION
Action is triggered from a web view.
Action.SITUATION_FOREGROUND_NOTIFICATION_ACTION_BUTTON
Action is triggered from a foreground notification action button.
Action.SITUATION_BACKGROUND_NOTIFICATION_ACTION_BUTTON
Action is triggered from a background notification action button.
Action.SITUATION_AUTOMATION
Action is triggered from automation.

Action Registry

Registering an action:

Action customAction = new CustomAction();
UAirship.shared()
         .getActionRegistry()
         .registerAction(customAction, "my_action_name");

Looking up an entry:

ActionRegistry.Entry entry = UAirship.shared()
                                      .getActionRegistry()
                                      .getEntry("my_action_name");

Setting a predicate:

// Predicate that will reject PUSH_RECEIVED causing the action to never run during that situation.
Predicate<ActionArguments> rejectPushReceivedPredicate = new Predicate<ActionArguments>() {
    @Override
    public boolean apply(ActionArguments arguments) {
        return !(Situation.PUSH_RECEIVED.equals(arguments.getSituation()));
    }
};

entry.setPredicate(rejectPushReceivedPredicate);

The action registry is the central place to register actions by name. Each entry in the registry contains an action, the names that the action is registered under, a predicate that allows filtering when an action can run, and allows specifying alternative actions for different situations.

Triggering Actions

Example:

// Running an action directly through the ActionRunRequest
ActionRunRequest.createRequest("actionName")
                .setSituation(Situation.MANUAL_INVOCATION)
                .setValue("actionValue")
                .run();

// Running an action by registered name
ActionRunRequest.createRequest("my_action_name")
                .setValue("actionValue")
                .run();

// An optional callback when finished
ActionRunRequest.createRequest("my_action_name")
                .setValue("actionValue")
                .run(new ActionCompletionCallback() {
                    public void onFinish(ActionArguments arguments, ActionResult result) {
                        Logger.info("Action finished!  Result: " + result);
                    }
                });

// Block until the action finishes
ActionResult result = ActionRunRequest.createRequest("my_action_name")
                                      .runSync();

Actions can be programmatically through a ActionRunRequest , by defining actions in a push notification, from JavaScript using a Custom HTML Templates, or from an automation schedule.

The ActionRunRequest class provides a fluent API for running actions. The action run request takes in a value, situation, and metadata and constructs the ActionArguments and passes it to the action to run. ActionArguments value can only contain an ActionValue instance. ActionValue is a class that limits the type of values to those that can be JSON serializable and contains getter methods that automatically does type checking to parse value back into its original form.Each action is run on its own thread when triggered asynchronously. Synchronous runs will block and should never be called on the UI thread.

Available Actions

LandingPageAction
The landing page action allows showing a rich content page in an overlay.
OpenExternalUrlAction
The open external URL action allows launching any URL. The action will construct an intent with a given URI and try to start an activity with it for viewing.
DeepLinkAction
The deep link action works exactly as the Open External URL Action. It constructs an intent with a given URI and tries to launch an activity. The deep linking strategy assumes the application is set up to handle URIs. See Android Deep Linking guide for more details on providing deep linking.
ShareAction
The share action constructs an intent to share the text to the application. The Android chooser activity will be started to pick the application used to share the text.
AddTagsAction
The add tags action allows adding one or more tags to the device. Note: this action is a no-op if channelTagRegistrationEnabled to false on PushManager .
RemoveTagsAction
The remove tags action allows removing one or more tags from the device.
AddCustomEventAction
The custom event action creates and adds a custom event. See Custom Events documentation for more details on Custom Events.
ClipboardAction
The clipboard action copies text to the system clipboard.
OpenRichPushInboxAction
The open rich push inbox action will try to start an activity to view either the Rich Push Inbox or a Rich Push Message if a message ID is supplied as the arguments value and the message is present in the inbox.
OverlayRichPushMessageAction
The overlay rich push action will display a Rich Push Message in the landing page activity.
WalletAction
The wallet action allows opening Android Pay deep links.
ScheduleAction
The schedule action schedules an automation action.
CancelSchedulesAction
The cancel schedules action cancels automation actions.
FetchDeviceInfoAction
The fetch device info action gets an updated snapshot of the devices information from the JS bridge.

Custom Actions

Custom Action:

public class CustomAction extends Action {

    @Override
    public boolean acceptsArguments(ActionArguments arguments) {
        if (!super.acceptsArguments(arguments)) {
            return false;
        }

        // Do any argument inspections. The action will stop
        // execution if this method returns false.

        return true;
    }

    @Override
    public ActionResult perform(ActionArguments arguments) {
        Logger.info("Action is performing!");

        return ActionResult.newEmptyResult();
    }
}

Register the action after takeOff:

@Override
public void onAirshipReady(UAirship airship) {
      airship.getActionRegistry()
             .registerAction(new CustomAction(), "my_custom_action");
}

Actions that are either long lived should request a wake lock before performing. This is especially important for actions that are performing in Situation.PUSH_RECEIVED, when a push is delivered when the device is not active.

The action framework supports any custom actions. Create an action by extending the base action class, then register the action to the registry after [TakeOff]#takeoff

n-device automation allows the Urban Airship SDK to execute actions when certain conditions are met upon the creation of an analytics event. These conditions are defined as triggers and range from app foreground to screen events. Actions can be scheduled either through an action or using the APIs exposed by the SDK.

Using the Automation Actions

Example schedule payload that will display a landing page after a user has either visited a given page ten times or, as reported through a custom event, purchased items beyond a threshold of $30.

{
   "schedule_actions" :{
      "actions":{
         "landing_page_action":"https://www.urbanairship.com"
      },
      "limit": 1,
      "start": "2015-04-01T12:00:00",
      "end": "2017-05-01T12:00:00",
      "group": "campaign 1",
      "triggers": [
         {
            "type": "screen",
            "goal": 10,
            "predicate": {
               "value": {
                  "equals": "purchase_page"
               }
            }
         },
         {
            "type": "custom_event_count",
            "goal": 1.0,
            "predicate": {
               "and" : [
               {
                  "key": "event_name",
                  "value": {
                     "equals": "purchase"
                  }
               },
               {
                  "key": "price",
                  "scope": ["properties"],
                  "value": {
                     "at_least": "30.0"
                  }
               }]
            }
         }
      ]
   }
}

The “schedule_actions” action enables scheduling through the Push API as an “app defined” action, through the Urban Airship JavaScript bridge, or directly in the SDK by manually running the action. There are several components to this schedule payload.

Schedule Payload

group
Optional, group identifier. Useful for canceling and retrieving schedules for a specific campaign.
start
Optional, start time as an ISO 8601 timestamp. The time before the schedule starts listening for events.
end
Optional, end time as ISO 8601 timestamp. Once the schedule end time is reached, it will automatically be canceled.
triggers
Required, an array of triggers. Triggers cause the actions payload to execute.
limit
Optional, integer defaulting to 1. Number of times to trigger the actions payload before canceling the schedule.
actions
Required, map of actions payloads. Run when one or more of the triggers meets its goal.

Trigger Payload

type
Required, the event type. Must be one of the valid types below. Each trigger type defines how the goal is incremented and the predicate argument.
goal
Required, the trigger’s goal. When the trigger’s goal is met, it will trigger the schedule’s actions to be executed.
predicate
Optional, predicate to filter out events.

Trigger Types

custom_event_value
Custom event’s value will be applied to the trigger’s goal. Predicate is applied to the event.
custom_event_count
Custom events will be counted towards the trigger’s goal. Predicate is applied to the event.
foreground
App foreground counts will be counted towards the trigger’s goal. Predicate is ignored.
background
App background counts will be counted towards the trigger’s goal. The predicate is ignored.
region_enter
Region enter events will be counted towards the trigger’s goal. Predicate is applied to the event.
region_exit
Region exit events will be counted towards the trigger’s goal. Predicate is applied to the event.
screen
Screen tracking. Predicate is applied against the screen’s name.

Trigger Predicates

Predicate syntax:

<predicate>        := <json_matcher> | <not> | <and> | <or>
<not>              := { "not": { <predicate> } }
<and>              := { "and": [<predicate>, <predicate>, …] }
<or>               := { "or": [<predicate>, <predicate>, …] }
<json_matcher>     := { <selector>, "value": { <value_matcher> }} | { "value": {<value_matcher>}}
<selector>         := <scope>, "key": string | "key": string | <scope>
<scope>            := "scope": string | "scope": [string, string, …]
<value_matcher>    := <numeric_matcher> | <string_matcher> | <presence_matcher>
<numeric_matcher>  := "equals": number | "at_least": number | "at_most": number | "at_least": number, "at_most": number
<string_matcher>   := "equals": string
<presence_matcher> := "is_present": boolean

The predicate is the core logic within the trigger, presenting a set of structured conditions that are applied to the trigger event. It follows the same patterns as in Custom Event Selectors and may be a value matcher or logical expression.

Cancelling Actions

Example cancel action payload:

// Cancel all scheduled actions
"cancel_scheduled_actions": "all"

// Cancel specific groups and/or ids
"cancel_scheduled_actions": {
   "ids": ["id 1", "id 2"],
   "groups": ["campaign 1", "campaign 2"]
}

Just like scheduling actions, canceling scheduled actions can be done with the “cancel_scheduled_actions” action.

all
Optional. Value for canceling all schedules.
group
Optional. Either a single group or an array of groups
ids
Optional. Either a single ID or an array of IDs

Using the Automation API

Scheduling actions example:

Trigger customEventTrigger = Triggers.newCustomEventTriggerBuilder()
                                     .setCountGoal(2)
                                     .setEventName("name")
                                     .build();

Trigger foregroundEventTrigger = Triggers.newForegroundTriggerBuilder()
                                         .setGoal(3)
                                         .build();

ActionScheduleInfo actionSchedule = ActionScheduleInfo.newBuilder()
                                                      .addTrigger(customEventTrigger)
                                                      .addTrigger(foregroundEventTrigger)
                                                      .addAction("sample_action", JsonValue.wrap("sample_action_value"))
                                                      .setGroup("group_name")
                                                      .setLimit(4)
                                                      .setStart(System.currentTimeMillis())
                                                      .setEnd(System.currentTimeMillis() + TimeUnit.MILLISECONDS.convert(1, TimeUnit.DAYS))
                                                      .build();

// Schedule the schedule info
UAirship.shared().getAutomation().scheduleAsync(actionSchedule, new PendingResult.ResultCallback<ActionSchedule>() {
    @Override
    public void onResult(@Nullable ActionSchedule result) {
        // Handle result
    }
});

It should be noted that the automation module cannot be accessed off of the main process. If any method is called, the method will no-op and execute the callback, if provided.

The API provided in Automation allows for synchronous and asynchronous access to the automation storage. To schedule an action schedule, first create an ActionScheduleInfo object.

When an ActionScheduleInfo instance is scheduled, the module will return an ActionSchedule instance with a unique ID generated for the schedule. When scheduling asynchronously, a callback may be provided to handle this response. If present, the callback will be posted to the calling thread’s looper. The main thread’s looper will otherwise be used.

Retrieving Scheduled Actions

Retrieving schedules:

UAirship.shared().getAutomation().getScheduleAsync("id", new PendingResult.ResultCallback<ActionSchedule>() {
    @Override
    public void onResult(@Nullable ActionSchedule result) {
        // Handle result
    }
});

UAirship.shared().getAutomation().getSchedulesAsync("group", new PendingResult.ResultCallback<List<ActionSchedule>>() {
    @Override
    public void onResult(@Nullable List<ActionSchedule> result) {
        // Handle result
    }
});

The API provides methods for retrieving a single schedule, group of schedules, or all schedules. If retrieving asynchronously, a callback may be provided.

Cancelling Scheduled Actions

// Synchronous canceling
UAirship.shared().getAutomation().cancel("id");

UAirship.shared().getAutomation().cancelGroup("group");

// Asynchronous canceling
UAirship.shared().getAutomation().cancelAsync("id");

UAirship.shared().getAutomation().cancelGroupAsync("group");

Lastly, a series of methods are provided for canceling a single schedule, a group or list of schedules, or all schedules.

Analytics Reporting

This document is a quick guide to integrating Reports support with your Android application using the Urban Airship client library. We will briefly cover the event upload model the client library implements.

Analytics Events and Uploading

Our client library stores events in a local database and uploads them periodically in a background thread. We’ve taken great care to make sure that the database won’t grow beyond a small fixed size, so extended periods of lost connectivity are nothing to worry about. The event upload thread is woken up when new events are triggered and goes to sleep when there are no more events to process, so the impact on battery life is negligible.

Custom Events

Recording custom events:

CustomEvent.Builder builder = new CustomEvent.Builder("event_name")
      .setEventValue(123.12);

// Record the event
UAirship.shared().getAnalytics().addEvent(builder.create());

Custom events let you track user activities and key conversions in your application, and tie them back to corresponding push messaging campaigns. Custom events requires analytics to be enabled. If disabled, any event that is added to analytics will be ignored. For a more detailed explanation on custom events and possible use cases, see the Custom Events topic guide.

Convenient templates are provided to create custom events for common account, media or retail related events. For more details see the Android Event Templates topic guide.

Screen Tracking

Track a screen:

UAirship.shared().getAnalytics().trackScreen("MainActivity");

Tracking all activities as screens:

this.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {
    @Override
    public void onActivityStarted(Activity activity) {
        UAirship.shared().getAnalytics().trackScreen(activity.getClass().getSimpleName());
    }
});

The Urban Airship SDK gives you the ability to track what screen a user views within the application, as well as how long the user stayed on that screen and the user’s previous screen. These events then come through Urban Airship Connect and allow you to see the path that a user takes through an application, or to trigger actions based on a user visiting a particular area of the application.

When a new screen is tracked or when the application backgrounds, a screen tracking event will be generated. Normally, Analytics.trackScreen should be called in either Activity.onStart or Fragment.onStart, depending on how the application is built.

For applications where you only want to track activities, you can automate screen tracking with an activity life cycle listener.

Disabling Analytics

Disable analytics at runtime:

UAirship.shared().getAnalytics().setEnabled(false);

Features that depend on analytics being enabled may not work properly if it’s disabled (reports, location segmentation, region triggers, push to local time).

If you do not wish to include analytics and reporting in your application, you can disable analytics in the Airship Config under the analyticsEnabled flag.

When analytics is disabled at runtime it will delete any locally stored events and prevent any events from uploading.

Android Preferences Screen

You can easily add Urban Airship preferences to the Android settings screen. The SDK provides the following preferences:

PushEnablePreference
Enables/disables user notifications.
SoundEnablePreference
Enables/disables notification sounds.
VibrateEnablePreference
Enables/disables notification vibration.
QuietTimeEnablePreference
Enables/disables quiet time.
QuietTimeEndPreference
Sets the quiet time end.
QuietTimeStartPreference
Sets the quiet time start.
AnalyticsEnablePreference
Enables/disables analytic events.
ChannelIdPreference
Displays the channel ID.
UserIdPreference
Displays the user ID.
LocationUpdatesEnabledPreference
Enables/disables location updates.
LocationBackgroundUpdatesAllowedPreference
Enables/disables location updates from continuing in the background.

Location Targeting

The location component of the Urban Airship library is designed to be extremely flexible. You can use it to do all of your location tracking or if you want you can just use it when you’re in need of a single location update and if neither one of those fits your needs, you can do your own location tracking and let us upload them to your dashboard for you. So, let’s get started integrating location into your application so you can start making extremely relevant, targeted pushes to your users.

Setup

AndroidManifest.xml:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

In order to start using location in your app, you’ll need to add a location permission to your AndroidManifest.xml.

If approximate locations aren’t good enough, request android.permission.ACCESS_FINE_LOCATION instead to access the GPS.

Apps targeting Android Marshmallow (API 23) and later will prompt users to grant permissions at runtime, instead of install time. Since users can revoke permissions at any time from the app Settings screen, your app needs to check that it has the permissions it needs every time it runs. See Permissions for more details.

Using Urban Airship Location

Urban Airship Location exposes a very simple, high-level API for requesting location.

The Urban Airship SDK is compatible with Google Play Services’ Fused Location Provider. Fused Location will automatically be used if Google Play Services is available on the device, is up to date, and the application was built with the Google Play Services dependency. Otherwise the standard Android location will be used, such as for Amazon devices. Google Play Services setup instructions can be found here.

Continuous Location Updates

Enabling location updates:

// Enable location updates
UAirship.shared().getLocationManager().setLocationUpdatesEnabled(true);

// Allow location updates to continue in the background
UAirship.shared().getLocationManager().setBackgroundLocationAllowed(true);

Listening for location updates:

// Create a listener
LocationListener listener = new LocationListener() {
    @Override
    public void onLocationChanged(Location location) {
        Log.i("Location", "New user location " + location);
    }
});

// Add the listener to UALocationManager
UAirship.shared().getLocationManager().addLocationListener(listener);

// Remove the listener when finished
UAirship.shared().getLocationManager().removeLocationListener(listener);

Location updates are enabled or disabled by UALocationManager.setLocationUpdatesEnabled . Continuing updates in the background is controlled by UALocationManager.setBackgroundLocationAllowed . Listening for background locations now requires both location updates enabled and background location allowed.

Location updates can be listened for by instantiating or extending the LocationListener class:

Location Request Options

LocationRequestOptions options = new LocationRequestOptions.Builder()
        .setPriority(LocationRequestOptions.PRIORITY_BALANCED_POWER_ACCURACY)
        .setMinDistance(800)
        .setMinTime(5, TimeUnit.MINUTES)
        .create();

// Set the default continuous location request options
UAirship.shared().getLocationManager().setLocationRequestOptions(options);

Location request options are modeled after the Fused Location Provider by specifying high level needs instead of low level criteria. The location request options will automatically be converted to either criteria when using the standard Android Location APIs or to a LocationRequest when using Fused Location Provider.

The location request options for location updates will automatically default to LocationRequestOptions.PRIORITY_BALANCED_POWER_ACCURACY for request priority, 800 meters for minimum distance update interval and 5 minutes for minimum time update interval.

Single Location Requests

Example:

LocationCallback locationCallback = new LocationCallback() {
    @Override
    public void onResult(Location location) {
        if (location != null) {
            Log.i("Location", "Single location request: " + location);
        } else {
            Log.i("Location", "Single request failed!");
        }
    }
};

Cancelable locationRequest = UAirship.shared()
                                     .getLocationManager()
                                     .requestSingleLocation(locationCallback);

// Optionally you can cancel the request and the callback will not be called
locationRequest.cancel();

Single location requests can be made in addition to continuous location updates or by themselves to have more control over when location requests are made.

When a single location request is made, a PendingResult is returned. The PendingResult can be used to cancel the request or set a callback when the result is ready.

Recording Location

UAirship.shared().getAnalytics().recordLocation(location);

Any location update from Urban Airship’s location module will automatically be recorded as a location event.

If you’re using your own location tracking, you can still upload those events to Urban Airship so you can view them on your dashboard. Track the location by calling recordLocation on Analytics . The location will be automatically batched and uploaded so you can view it on your dashboard.

Android Pay

Create a pass request:

Field field = new Field.Builder()
        .setName("text")
        .setValue("text value")
        .setLabel("text label")
        .build();

PassRequest passRequest = PassRequest.newBuilder()
        .setApiKey("Urban Airship API key")
        .setTemplateId("template ID")
        .addField(field)
        .setTag("tag")
        .build();

Execute the pass request to fetch a pass object:

passRequest.execute(new Callback() {
                @Override
                public void onResult(Pass pass) {
                  // Handle the pass
                }

                @Override
                public void onError(int errorCode) {
                    if (errorCode >= 500) {
                        // retry
                    }
                }
            });

Pass requests can be canceled at any time:

passRequest.cancel();

Prompt the user to add the pass:

pass.requestToSavePass(getApplicationContext());

The Urban Airship SDK provides tools to create Wallet passes and deep link them to Android Pay.

SDK Localization

The Urban Airship SDK provides localization for interactive notification buttons and the Message Center for the following languages: English, Chinese (Traditional), Chinese (Simplified), German, Hungarian, Slovak, Russian, Portuguese (Portugal), Portuguese (Brazil), French, Danish, Turkish, Norwegian, Romanian, Polish, Finnish, Dutch, Hindi, Spanish (Latin American), Spanish (Spain), Hebrew, Czech, Italian, Vietnamese, Thai, Japanese, Arabic, Korean, Malay, Indonesian, and Swedish.

To add translations for another language, copy the english strings.xml to the appropriate language resource folder. Translate it to the new language and the new language resource will be merged automatically. For more information, please see the Android documentation on resource merging and localization.