iOS Push: Advanced Features

By now you have been able to integrate the Urban Airship library into your project and send a test push notification. If not, please review iOS Push: Getting Started.

This page provides more detail on configuring your app to handle more advanced Urban Airship features such as Rich Push, Tags, Quiet Time, and Reports.

Tip

If you are not a mobile developer or if your company employs a third-party development firm to integrate Urban Airship, you must make sure that they follow these steps closely in order to ensure proper functioning of Urban Airship Analytics.

Configuration

The library provides a number of advanced configuration features that can be controlled with the UAConfig object. UAConfig objects can either be populated from your AirshipConfig.plist file, or at runtime using its exposed properties. See the UAConfig documentation for the full list of configuration options.

Auto-detect Production Mode

By default, the library will select the app key and secret based on the inProduction setting on UAConfig, however it is also able to determine this at runtime based on the current application provisioning profile. To enable this auto-detection, set detectProvisioningMode to YES. Note that because applications running in the simulator are not signed, the library will defer to the inProduction flag when not executing on a real device.

Note

This functionality is supported only in versions 3.0.3+ of our iOS library.

Reset Rich Push Users

Rich Push user info is stored in the device keychain. This allows the user info to persist through app uninstalls and device upgrades, but this can cause problems during development if you want to test a fresh install. To force a reset of the user credentials, set clearKeychain to YES in either the AirshipConfig.plist file or directly on the config object used for [UAirship takeOff:(UAConfig *)config]. This clears the keychain every time the application starts, so it should only be used in development.

Automatic Integration

The Urban Airship library will automatically integrate with your app, so you do not need to implement any of the push-related UIApplicationDelegate protocol methods or pass notifications to the library. The library is able to do this by setting itself as the app delegate, intercepting messages and forwarding them to your original app delegate. If you would like to disable this behavior and implement the delegate callbacks in your own delegate, you can set automaticSetupEnabled to NO in either your AirshipConfig.plist file or on a UAConfig object passed to [UAirship takeOff:(UAConfig *)config];

If you choose to disable the automatic app delegate setup, you will need to add the following code to your app delegate:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Your app setup and [UAirship takeOff]
    // ...

    // Register for remote notifications (required). When push is disabled,
    // UAPush will record the desired remote notification types, but not register for
    // push notifications with iOS. When push is enabled at a later time, the registration
    // will occur normally. This value defaults to badge, alert and sound, so it's only necessary to
    // set it if you want to add or remove types.
    [UAPush shared].notificationTypes = (UIRemoteNotificationTypeBadge |
                                         UIRemoteNotificationTypeSound |
                                         UIRemoteNotificationTypeAlert);
    [[UAPush shared] registerForRemoteNotifications];

}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    UA_LINFO(@"APNS device token: %@", deviceToken);

    // Updates the device token and registers the token with UA. This won't occur until
    // push is enabled if the outlined process is followed. This call is required.
    [[UAPush shared] registerDeviceToken:deviceToken];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {

    UA_LINFO(@"Received remote notification: %@", userInfo);

    // Fire the handlers for both regular and rich push
    [[UAPush shared] handleNotification:userInfo applicationState:application.applicationState];
    [UAInboxPushHandler handleNotification:userInfo];
}

Logging

Log levels can be set independently for production and development modes. Set developmentLogLevel and productionLogLevel on your UAConfig.

Actions

Urban Airship Actions provides a convenient way to automatically perform tasks by name in response to push notifications, Rich 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 library comes with pre-made actions for common tasks such as setting/modifying tags, showing a landing page, enabling deep linking and opening URLs out of the box. Actions can also be extended to enable custom application behaviors and engagement experiences.

In iOS, Actions are sent as part of the notification payload as top level key values, where the key is the name of the action and the value is the action’s argument. The argument can be any valid JSON value.

Actions are triggered with extra context in the form of a Situation. The different situations allows actions to determine if they should run or not, and possibly do different behavior depending on the situation.

Available Situations
  • UASituationManualInvocation: action was invoked manually.
  • UASituationLaunchedFromPush: action was invoked from a launched push notification.
  • UASituationForegroundPush: action was invoked from a recived push notification in the foreground.
  • UASituationBackgroundPush: action was invoked from a recived push notification in the background.
  • UASituationWebViewInvocation: action was invoked from Javascript or a URL.

Action Registry

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.

Registering an action:

[[UAActionRegistry shared] registerAction:action names:@[@"action_name", @"action_alias"]];

Looking up an action entry:

UAActionRegistryEntry *entry = [[UAActionRegistrar shared] registryEntryWithName:@"action_name"]];

Setting a predicate:

// Predicate that only allows the action to run if it was launched from a push
UAActionPredicate predicate = ^(UAActionArguments *args) {
    return (BOOL)(args.situation == UASituationLaunchedFromPush);
};

// Update the predicate
[[UAActionRegistry shared] updatePredicate:predicate forEntryWithName:@"action_name"]

Triggering Actions

Actions can be triggered manually, but its more convenient and safer to run actions through the UAActionRunner. The action runner is able to run an action by a name, or run an action directly.

Example:

UAActionArguments *args = [UAActionArguments argumentsWithValue:@"argument" withSituation:UASituationManualInvocation];

// Optional completion handler
UAActionCompletionHandler completionHandler = ^(UAActionResult *result) {
    UA_LDEBUG("Action finished!")
};

// Run an action by name
[UAActionRunner runActionWithName:@"action_name" withArguments:args withCompletionHandler:completionHandler];

// Run an action directly
[UAActionRunner runAction:action withArguments:args withCompletionHandler:completionHandler];

Landing Page Action

The landing page action allows showing a rich content page when a user clicks a notification. The landing page is shown in an overlay.

Accepted Arguments
  • URL defined as a String or URL.
Default Action Names
  • landing_page_action
  • ^p
Accepted Situations
  • UASituationForegroundPush
  • UASituationLanchedFromPush
  • UASituationBackgroundPush
  • UASituationWebViewInvocation
  • UASituationManualInvocation

When the landing page is invoked in situation UASituationBackgroundPush, it will only cache the landing page content in the background instead of displaying it.

Default Registry Predicate

Rejects UASituationForegroundPush and rejects UASituationBackgroundPush if the application has not been opened in the last week.

Example:

UAActionArguments * args = [UAActionArguments argumentsWithValue:@"http://wwww.urbanairship.com"
                                              withSituation:UASituationManualInvocation];

// Optional completion handler
UAActionCompletionHandler completionHandler = ^(UAActionResult *result) {
    UA_LDEBUG("Action finished!")
};

[UAActionRunner runActionWithName:@"landing_page_action" withArguments:args withCompletionHandler:completionHandler];

Open External URL Action

The open external URL action allows launching any URL. The action will attempt to open the url using safari.

Accepted Arguments
  • String
  • URL
Default Action Names
  • open_external_url_action
  • ^u
Accepted Situations
  • UASituationForegroundPush
  • UASituationLanchedFromPush
  • UASituationWebViewInvocation
  • UASituationManualInvocation

Default Registry Predicate

Rejects UASituationForegroundPush.

Example:

UAActionArguments * args = [UAActionArguments argumentsWithValue:@"http://wwww.urbanairship.com"
                                              withSituation:UASituationManualInvocation];

// Optional completion handler
UAActionCompletionHandler completionHandler = ^(UAActionResult *result) {
    UA_LDEBUG("Action finished!")
};

[UAActionRunner runActionWithName:@"open_external_url_action" withArguments:args withCompletionHandler:completionHandler}];

Add Tags Action

The add tags action allows adding one or more tags to the device.

Accepted Arguments
  • Single tag as a String
  • Multiple tags as an NSArray
Default Action Names
  • add_tags_action
  • ^+t
Accepted Situations
  • UASituationForegroundPush
  • UASituationLanchedFromPush
  • UASituationWebViewInvocation
  • UASituationManualInvocation

Example:

UAActionArguments * args = [UAActionArguments argumentsWithValue:@"tagOne"
                                              withSituation:UASituationManualInvocation];

// Optional completion handler
UAActionCompletionHandler completionHandler = ^(UAActionResult *result) {
    UA_LDEBUG("Action finished!")
};

[UAActionRunner runActionWithName:@"add_tags_action" withArguments:args withCompletionHandler:completionHandler}];

Remove Tags Action

The remove tags action allows removing one or more tags from the device.

Accepted Arguments
  • Single tag as a String
  • Multiple tags as an NSArray
Default Action Names
  • remove_tags_action
  • ^-t
Accepted Situations
  • UASituationForegroundPush
  • UASituationLanchedFromPush
  • UASituationWebViewInvocation
  • UASituationManualInvocation

Example:

UAActionArguments * args = [UAActionArguments argumentsWithValue:@"tagOne"
                                              withSituation:UASituationManualInvocation];

// Optional completion handler
UAActionCompletionHandler completionHandler = ^(UAActionResult *result) {
    UA_LDEBUG("Action finished!")
};

[UAActionRunner runActionWithName:@"remove_tags_action" withArguments:args withCompletionHandler:completionHandler}];

Custom Actions

The action framework supports any custom actions. Create an action by extending the base action class or defining an action using blocks. After takeoff, register the action. The action can be triggered the same way as built-in actions.

Note

All actions are run on the main queue. If its possible for an action to block the main queue, it should perfrom its work on a background queue and call the UAActionCompletionHandler when finished.

Example:

UAAction *customAction = [UAAction actionWithBlock: ^(UAActionArguments *args, UAActionCompletionHandler handler) {
    UA_LDEBUG("Action is performing with UAActionArguments: %@", args);
    handler([UAActionResult emptyResult);
}];

Register the action after takeoff:

[UAirship takeOff];
[[UAActionRegistry shared] registerAction:customAction name:@"custom_action"];

Rich Push

Rich Push is a service that stores and manages rich message content for your users. The message content is served directly to the user’s device and viewed via a persistent in-app inbox that we provide as a drop-in user interface.

Rich Push messages can contain any type of HTML content such as videos, polls, coupons, or any other interactive feature you choose. Rich Push messages are not subject to the same payload restrictions as push notifications because they are not delivered via APNS or GCM. However, it is simple (and recommended) to accompany a new Rich Push message with a push notification as the alert mechanism.

Since you have already integrated the client library, there are just a few additional steps required to set up the Inbox message view.

Set Up The Inbox View

If you have not already initialized a shared UAirship instance and registered for remote notifications, please refer to the Objective C Implementation section of the iOS: Getting Started section.

Note

Sample UI classes are included in the library distribution. However, you must add the UI folder to your project.

The UA iOS Sample App is available for download on our Developer Resources page.

Initialize the Inbox UI
Inside your application delegate’s application:didFinishLaunchingWithOptions method, init the UAInbox UI and start if the app launched from a push notification:
//Init the UI
[UAInbox useCustomUI:[UAInboxUI class]];//sample UI implementation
[UAInbox shared].pushHandler.delegate = [UAInboxUI shared];

// If the application gets an UAInbox message id on launch open it up immediately.
// Only works for the default inbox
[UAInboxUI shared].inboxParentController = _viewController;
Display Rich Push Inbox
Displaying the Rich Push Inbox within the application is as simple as making one call and passing in the view controller from which you wish to launch the Inbox UI:
[UAInbox displayInboxInViewController:parentViewController animated:YES];
Show Notifications While App is Running
In order to to this, add the following to your app delegate:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    [UAInboxPushHandler handleNotification:userInfo];
}

Send a Test Rich Push

Now you should be ready to send a test Rich Push message. The easiest way to do this is by using the Rich Push Composer in the Urban Airship web application. Please refer to Rich Push Composer in our User Guide for step-by-step instructions.

Badge Updates

The value of the badge can be set in a number of ways. Most often, the number corresponds with some notion of unread or unviewed content, e.g., email messages or friend requests. The most common way to update the badge is directly through APNS, either by passing along the badge integer in the payload of a push notification, or by telling the app to adjust the value using our autobadge feature.

For Rich Push applications, you may want the badge value to represent the actual state of unread messages in the Rich Push Inbox. If so, then you need to set this behavior in the application delegate. Here is an example of how to set the current badge to the current unread message count when the application moves to inactive state:

- (void)applicationWillResignActive:(UIApplication *)application {
    UAInbox *inbox = [UAInbox shared];
    if (inbox.messageList.unreadCount >= 0) {
        [[UIApplication sharedApplication] setApplicationIconBadgeNumber:inbox.messageList.unreadCount];
    }
}

The above sample code is available in the UA sample app as well.

If you use this method then you should never include badge values in the payload of push notifications, because Rich Push will override them.

Localization

The Rich Push sample has built-in localization support and provides English resources. All Urban Airship localization strings for Rich Push are contained in their own bundle:

UAInboxLocalization.bundle

To add a new translation just copy one of the existing lproj directories into the bundle and update all of the items in Localizable.strings

Push

Urban Airship’s push library provides a simple interface for managing push notifications within your iOS application. Import UAPush.h to begin using these features:

#import "UAPush.h"

Push Settings

The push settings interface provides controls for toggling push notification and managing quiet time. Drop this interface directly into your application to give your users control over these settings.

The following is an example of how you can launch the settings from a button press in your view controller:

- (IBAction)buttonPressed:(id)sender {
    if (sender == settingsButton) {
        [UAPush openApnsSettings:parentViewController animated:YES];
    }
}

Badges

You can set (or reset) the badge number within your application by setting applicationIconBadgeNumber:

[UIApplication sharedApplication].applicationIconBadgeNumber = 0;

If you are using autobadge, in addition to setting the local badge number as shown above, you will need to make a device registration call to reset the server side counter:

The application’s icon badge can be manipulated with convenience methods provided by UAPush:

[[UAPush shared] setBadgeNumber:1];//set to 1
[[UAPush shared] resetBadge];//zero badge

A typical application will reset the badge any time a user starts the app or resumes it from the background. This can be done by making resetBadge calls from application:didFinishLaunchingWithOptions: and applicationDidBecomeActive. You may also wish to reset the badge after receiving a push when the application is running by calling reset from application:didReceiveRemoteNotification.

If your application uses Urban Airship’s autobadge feature, enable client-side autobadge tracking in application:didFinishLaunchingWithOptions: before changing the badge value:

[[UAPush shared] setAutobadgeEnabled:YES];
[[UAPush shared] resetBadge];//zero badge

This will ensure that the client will always sync badge changes with the server so that subsequent autobadge notifications will increment properly.

Set quiet time

NSDate *fromDate;//set with the hour and minute quiet time begins
NSDate *toDate;//set with the hour and minute quiet time ends

[[UAPush shared] setQuietTimeFrom:fromDate to:toDate withTimeZone:[NSTimeZone localTimeZone]];

// Update the values on UA servers
[[UAPush shared] updateRegistration];

Launch Push Settings

Displaying the settings view is as simple as making a single call and passing in the view controller from which you wish to launch the Push Settings UI.

[UAPush openApnsSettings:_parentViewController animated:YES];

Handling notifications

iOS handles push notifications received outside the application, but if a notification is received while the app is running, it is up to the application developer to handle it.

The sample UI includes an implementation of UAPushNotificationDelegate that handles alerts, sounds, and badges. However, if you wish to customize this behavior, you can provide your own implementation:

[UAPush shared].pushNotificationDelegate = customPushDelegate;

Aliases

Aliases 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 iPad.

Set an Alias on App Start

To set an alias for a device token (Please note that the alias field can contain up to 128 bytes/128ascii characters, which can vary by language used):

- (void)application:(UIApplication *)application
        didFinishLaunchingWithOptions:(NSDictionary *)userInfo {

    // ... your app init code

    [UAirship takeOff];

    // Sets the alias. It will be sent to the server on registration.
    NSString *yourAlias = @"Your Alias";
    [UAPush shared].alias = yourAlias;

}

For setting a new alias, set the alias and update the device registration with UA.

NSString *alias = @"new_alias_string";
[UAPush shared].alias = alias;

[[UAPush shared] updateRegistration];
Remove Alias

To remove an alias, set the value of the alias to nil and update the device registration with UA.

[UAPush shared].alias = nil;
[[UAPush shared] updateRegistration];

Set Tags

Tags are an easy way to group device tokens. Unlike aliases, of which you can only have one (though a single alias can apply to many device tokens), many tags can be applied to one or more device tokens. Then, a message sent to a tag will be sent out to all device tokens that are associated with that tag.

Tags are a good way to group device tokens by country, language, time zone or device type. These tags can be automatically generated using UATagUtils. It is good practice to minimize API calls when setting multiple tags. It’s more efficient to set them in groups.

Replace existing tags or set a new group of tags
NSArray *niftyTags = [@"one", @"two", @"three"];

[[UAPush shared] setTags:niftyTags];
[[UAPush shared] updateRegistration];
Add a single tag to the current device tag list and update the server immediately
NSString *tagToAdd = @"a_tag";

[[UAPush shared] addTagToCurrentDevice:tagToAdd];
[[UAPush shared] updateRegistration];
Remove a single tag from the current device tag list and update the server immediately
NSString *tagToDelete = @"a_tag";

[[UAPush shared] removeTagFromCurrentDevice:tagToDelete];
[[UAPush shared] updateRegistration];
Set the current list of tags using UATagUtils
#import "UATagUtils.h"

...

// Set some commonly used tags
NSArray *tags = [UATagUtils createTags:
                    (UATagTypeTimeZoneAbbreviation
                     | UATagTypeLanguage
                     | UATagTypeCountry
                     | UATagTypeDeviceType)];

[[UAPush shared].tags = [NSArray arrayWithArray:tags];//update locally
[[UAPush shared] updateRegistration];//update server

Background Push

Note

Background push getting you down? See iOS Background Push Troubleshooting.

The library provides support for background notifications that were introduced in iOS 7. To support this mode, you must include the UIBackgroundModes key with “remote-notification” value in your app’s Info.plist file. When viewing the plist in Xcode, UIBackgroundModes is displayed as “Required background modes” and “remote-notification” is displayed as “App downloads content in response to push notifications”.

You can also enable “remote-notifications” under the target’s capabilities section:

../_images/ios-background-push-capabilities.png

Unless you are utilizing the automatic integration feature of the UAirship library, you must also implement the application application:didReceiveRemoteNotification:fetchCompletionHandler:.

Example:

-(void)application:(UIApplication *)application
     didReceiveRemoteNotification:(NSDictionary *)userInfo
           fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

    // Notify UAInbox to fetch any new messages if the notification
    // contains a rich application page id.
    if (application.applicationState != UIApplicationStateBackground) {
        UA_LINFO(@"Received remote notification: %@", userInfo);
        [UAInboxPushHandler handleNotification:userInfo];
    }

    // Notify UAPush that a push came in with the completion handler
    [[UAPush shared] handleNotification:userInfo
                     applicationState:application.applicationState
               fetchCompletionHandler:completionHandler];
}

Note

If your application delegate implements application:didReceiveRemoteNotification:fetchCompletionHandler: on platforms that support background push, then your application delegate will no longer receive calls to application:didReceiveRemoteNotification:. It is still necessary to implement the non-completion handler version of the app delegate and UAPushNotificationDelegate if you are supporting older versions of iOS.

If you want to do tasks when a background push is received, create a custom UAPushNotificationDelegate that implements receivedBackgroundNotification:fetchCompletionHandler:.

Example:

- (void)receivedForegroundNotification:(NSDictionary *)notification
                fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

    UA_LDEBUG(@"Received a notification while the app was already in the foreground");

    // Do something with your customData JSON, then entire notification is also available

    // Be sure to call the completion handler with a UIBackgroundFetchResult
    completionHandler(UIBackgroundFetchResultNoData);
}

- (void)launchedFromNotification:(NSDictionary *)notification
          fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{

    UA_LDEBUG(@"The application was launched or resumed from a notification");

    // Do something when launched via a notification

    // Be sure to call the completion handler with a UIBackgroundFetchResult
    completionHandler(UIBackgroundFetchResultNoData);
}

- (void)receivedBackgroundNotification:(NSDictionary *)notification
                fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {

    // Do something with the notification in the background

    // Be sure to call the completion handler with a UIBackgroundFetchResult
    completionHandler(UIBackgroundFetchResultNoData);
}

Set the custom UAPushNotificationDelegate after takeOff.

Example:

[UAPush shared].pushNotificationDelegate = customPushDelegate;

Reports

Our iOS client library ships with analytics support out of the box, and by default, there are no explicit preferences you need to set in order to enable reporting. The integration is handled automatically unless you set automaticSetupEnabled to NO. If so, you will need to add additional code to handle conversions on app foregrounds as some instrumentation is required in order to record app foregrounds, backgrounds and incoming notifications.

Key Integration Calls

The following is an overview of the key integration points for data collection for apps that have disabled automatic setup.

Time in App, Opens and Opt-In Reports

To ensure proper recording for time in app, simply make sure you are calling takeOff when the app starts. The library will handle foreground and background events automatically.

On launch, call takeOff:

// Create Airship singleton that's used to talk to Urban Airship servers.
[UAirship takeOff];
Push Conversions

To record conversions and influence, you need to record incoming notifications. This is handled automatically unless you have set automaticSetupEnabled to NO. If so, you will need to add additional code to handle conversions on app foregrounds.

If you are using the UAPush library, use the standard push handler to record conversions:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    [[UAPush shared] handleNotification:userInfo applicationState:application.applicationState];
}

If you are using Rich Push, add a call to the standard inbox push handler as well:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    [[UAPush shared] handleNotification:userInfo applicationState:application.applicationState];
    [UAInboxPushHandler handleNotification:userInfo];
}
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.
Disabling Analytics
If you do not wish to include analytics and reporting in your application, in your AirshipConfig.plist file, simply set the analyticsEnabled to NO.

Apple, StoreKit and iPhone are trademarks of Apple, Inc. Maponics Neighborhood Boundaries © Maponics 2012. DMA® is a registered service mark of The Nielsen Company. Used under License.