Table of Contents

iOS

This is a developers’ guide for setting up an Urban Airship configuration for iOS apps. We will take you through the basic technical steps for configuring Apple and UA services, show you how to send your first basic push notification and Message Center message, and provide detailed samples and instructions for using advanced Urban Airship features.

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.

Production vs Development Apps in Urban Airship

When you create or edit an application record on our server, you must select whether your app system is “In development, connecting to test servers,” or “In production, connecting to real push servers.” Apple treats the two servers separately, so a device token for development/sandbox will not work on production/distribution.

When building your app using a development provisioning profile, set your Urban Airship application to In development, and upload the development Push SSL certificate. To push to an app built with a distribution provisioning profile (either with a release build in Xcode, ad hoc distribution, or the iTunes App Store), use an application that is In production, and upload the production Push SSL certificate.

Because Apple treats development and production/distribution as completely separate instances, we suggest making two applications in the Urban Airship web interface. That way you can continue to build and develop your application even after releasing it without interrupting your users.

Warning

Do not a) submit to the App Store or b) test notifications on an ad hoc build while your app’s code is pointing to an Urban Airship app key that is set as In Development. Development apps use different tokens that, when included in a push to a production app, will fail and in many cases cause all other pushes to fail.

Always create a Production Status Urban Airship app first and make sure your application code is pointing to the production app key. For more tips on what to check before you release your app, see this support article.

APNS Setup

While you are setting up your development and production apps, you’ll want to configure them for push services. For detailed instructions on this process, please see the APNS Setup documentation

Urban Airship SDK Setup

Download and unzip the latest version of libUAirship into the same directory as your project. You should see a new directory, named Airship, containing the latest version of the libUAirship static library and headers, as well as an AirshipKit directory, containing an Xcode project that builds the AirshipKit embedded framework.

Note

New applications with iOS 8 or above as a deployment target may opt to link against AirshipKit.framework instead of libUAirship. Because AirshipKit is an embedded framework as opposed to a static library, applications using this framework can take advantage of features such as module-style import and automatic bridging to the Swift language. Be aware, however, that embedded frameworks are not supported on iOS 7 and below. Further instructions on how to set up AirshipKit can be found in the Including the Urban Airship SDK section below.

Build Settings and Phases

Modules are enabled by default in new projects starting with Xcode 5. We recommend enabling modules and the automatic linking of frameworks. In the project’s Build Settings, search for Enable Modules and set it to YES then set Link Frameworks Automatically to YES.

Including the Urban Airship SDK

The Urban Airship static library and embedded framework have different setup procedures.

  • Embedded Framework (iOS 8+)
  • Static library (iOS 7+)

Before you begin, make sure both the AirshipKit and Airship directories are in the top level of your app’s source directory.

  1. Include AirshipKit as a project dependency:

    Drag AirshipKit.xcodeproj out of the AirshipKit folder and into your app project in Xcode (directly under the top level of the project structure). Now AirshipKit will be built at compile-time for the active architecture.

  2. Link against the embedded framework:

    To link against the embedded framework, add the AirshipKit.framework file to the Embedded Binaries section in the General tab for your target. This should also add it to the Linked Frameworks and Libraries section.

  3. Check Linked Frameworks and Libraries:

    Make sure AirshipKit.framework shows up in the Linked Frameworks and Libraries section in the General tab for your target.

  1. Search Paths:

    Ensure that your project’s Header Search Paths under Build Settings include the Airship directory (recursive).

  2. Linker flags:

    Add -ObjC -lz -lsqlite3 linker flag to Other Linker Flags to prevent “Selector Not Recognized” runtime exceptions and to include linkage to libz and libsqlite3. The linker flag -force_load <path to library>/libUAirship-<version>.a may be used in instances where using the -ObjC linker flag is undesirable.

  3. Link against the static library:

    To link against the static library, add the libUAirship.a file to the Link Binary With Libraries section in the Build Phases tab for your target.

  4. Link against required frameworks (Swift only)

    Swift apps using the static library and a bridging header should explicitly link against CoreTelephony. In the Link Binary With Libaries section mentioned above, add CoreTelephony.framework from the dropdown menu that appears when clicking the add button. Objective-C apps may skip this step.

  5. Add the Urban Airship Resources Bundle

    Locate the AirshipResources.bundle file in the Airship directory and add it to the Copy Bundle Resources section in the Build Phases tab for your target.

Enable Background Push

Enable background notifications that were introduced in iOS 7 by including the UIBackgroundModes key with the 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 Background Modes and Remote notifications under the target’s Capabilities section:

Create AirshipConfig.plist

The Urban Airship SDK uses a .plist configuration file named AirshipConfig.plist to manage your production and development application profiles.

  1. Create two applications within your Urban Airship account: One for development and one for production. For example:

    1. Name_of_your_app_dev
    2. Name_of_your_app_prod
  2. Create an AirshipConfig.plist file.

  3. Set the following values to the ones in your applications:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
      <key>detectProvisioningMode</key>
      <true/>
      <key>developmentAppKey</key>
      <string>Your Development App Key</string>
      <key>developmentAppSecret</key>
      <string>Your Development App Secret</string>
      <key>productionAppKey</key>
      <string>Your Production App Key</string>
      <key>productionAppSecret</key>
      <string>Your Production App Secret</string>
    </dict>
    </plist>
    

Import the Required Header Files

At the top of your application delegate include the umbrella AirshipKit’s umbrella header:

import AirshipKit
#import <AirshipKit/AirshipKit.h>

If your applicaiton uses the static library, you must import the individual headers:

#import "UAirship.h"
#import "UAConfig.h"
#import "UAPush.h"

Starting Urban Airship Services

The Urban Airship SDK requires only a single entry point in the app delegate, known as takeOff. Inside your application delegate’s application:didFinishLaunchingWithOptions: method, initialize a shared UAirship instance by calling UAirship takeOff. This will bootstrap the SDK and look for settings specified in the AirshipConfig.plist file you created earlier. These can also be provided by passing an instance of UAConfig at runtime by calling UAirship takeOff:. UAirship takeOff must be called on the main thread, in this method, before it returns.

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    // Populate AirshipConfig.plist with your app's info from https://go.urbanairship.com
    // or set runtime properties here.
    let config = UAConfig.defaultConfig()

    // You can also programmatically override the plist values:
    // config.developmentAppKey = "YourKey"
    // etc.

    // Call takeOff (which creates the UAirship singleton)
    UAirship.takeOff(config)
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    // Populate AirshipConfig.plist with your app's info from https://go.urbanairship.com
    // or set runtime properties here.
    UAConfig *config = [UAConfig defaultConfig];

    // You can also programmatically override the plist values:
    // config.developmentAppKey = @"YourKey";
    // etc.

    // Call takeOff (which creates the UAirship singleton)
    [UAirship takeOff:config];
}

Retrieving your Channel ID

The Channel ID is a unique identifier that ties together an application/device pair on iOS devices. The Channel ID is used to target pushes to specific devices using the Urban Airship API.

The Channel ID will be logged for all apps. You can always get the channelID with a couple of extra lines to your application:

let channelID = UAirship.push().channelId
print("My Application Channel ID: \(channelID)")
NSString *channelID = [UAirship push].channelID;
NSLog(@"My Application Channel ID: %@", channelID);

Don’t worry if this value initially comes back as null on your app’s first run. The Channel ID will be created and persisted during registration.

Enabling User Notifications

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, or in the background. Enabling or disabling user notifications is a preference often best left up to the user, so by default, user notifications are disabled. For testing purposes, enabling notification at startup requires a few extra lines of code to your app delegate.

Set the user notification types on [UAirship push]. Sounds, alerts and badges are the default types. The library will register to receive these types of notifications as soon as user push notifications are enabled.

// Set the notification types required for the app (optional). This value defaults
// to badge, alert and sound, so it's only necessary to set it if you want
// to add or remove types.
UAirship.push().userNotificationTypes = ([UIUserNotificationType.Alert |
                                          UIUserNotificationType.Badge |
                                          UIUserNotificationType.Sound])
// Set the notification types required for the app (optional). This value defaults
// to badge, alert and sound, so it's only necessary to set it if you want
// to add or remove types.
[UAirship push].userNotificationTypes = (UIUserNotificationTypeAlert |
                                         UIUserNotificationTypeBadge |
                                         UIUserNotificationTypeSound);

To enable user notifications programmatically:

// User notifications will not be enabled until userPushNotificationsEnabled is
// set true on UAPush. Once enabled, the setting will be persisted and the user
// will be prompted to allow notifications. Normally, you should wait for a more appropriate
// time to enable push to increase the likelihood that the user will accept
// notifications.
UAirship.push().userPushNotificationsEnabled = true
// User notifications will not be enabled until userPushNotificationsEnabled is
// set YES on UAPush. Once enabled, the setting will be persisted and the user
// will be prompted to allow notifications. Normally, you should wait for a more appropriate
// time to enable push to increase the likelihood that the user will accept
// notifications.
[UAirship push].userPushNotificationsEnabled = YES;

Warning

A new default behavior was introduced in SDK 6.0.0 ensuring that once user push notifications have been enabled on iOS 8+, settings may only be modified from within the iOS Settings app. Applications should link directly to the application settings.

To disable user push settings on iOS 7 or below, set userPushNotificationsEnabled to NO. If a device is running iOS 8 or higher, we recommend that the application link directly to the application’s system push settings with the UIApplicationOpenSettingsURLString URL constant.

// Open the system settings app directly to this application (on iOS 8+)
UIApplication.sharedApplication().openURL(NSURL(string: UIApplicationOpenSettingsURLString)!)
// Open the system settings app directly to this application (on iOS 8+)
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];

Send a Test Notification

Now would be a great time to send a test notification. See Send Your First Notification to get started using our dashboard interface, or our API reference for more details.

App Transport Security

If your app is targeting iOS 9 or higher, Message Center content features such as Landing Pages will only be able to load SSL-encrypted web content out of the box. This change, known as App Transport Security, will not affect content hosted on Urban Airship’s servers, which is SSL-encrypted. While we generally recommend leaving these default settings alone, if your app will need to load plain HTTP content then you can whitelist individual domains in your app’s Info.plist file. For more information, see Apple’s App Transport Security Technote.

Reference, Migration Guides, and Troubleshooting

All the public classes and methods provided by the Urban Airship SDK have corresponding Appledoc entries in our Reference documentation.

We also publish an update to the SDK migration guide SDK migration guide every time the SDK is updated, to help make the update process as painless as possible.

Lastly, if you find yourself stuck, check our Troubleshooting guide before contacting support.

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

The library can automatically determine the production mode at runtime based on the current application provisioning profile. To enable this auto-detection, set detectProvisioningMode to YES.

Note

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

Reset Message Center Users

Message Center 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. Expose a checkbox in the settings bundle set as a BOOL for the key “com.urbanairship.reset_keychain”. The next time the application starts, the user will automatically be reset once.

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 intercepting app delegate messages and forwarding them to your original app delegate, using a technique known as method swizzling.

This should be compatible with the vast majority of applications out of the box, but if you have advanced use cases for your app delegate, or if you would otherwise prefer to disable this behavior, you can set automaticSetupEnabled to NO in either your AirshipConfig.plist file or on a UAConfig object passed to [UAirship takeOff:].

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

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
    UAirship.push().appRegisteredForRemoteNotificationsWithDeviceToken(deviceToken)
}

func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
    UAirship.push().appRegisteredUserNotificationSettings()
}

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
    UAirship.push().appReceivedRemoteNotification(userInfo, applicationState: application.applicationState)
}

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
    UAirship.push().appReceivedRemoteNotification(userInfo,
        applicationState:application.applicationState,
        fetchCompletionHandler:completionHandler)
}

func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
    UAirship.push().appReceivedActionWithIdentifier(identifier!,
        notification: userInfo,
        applicationState: application.applicationState,
        completionHandler: completionHandler)
}

func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [NSObject : AnyObject], withResponseInfo responseInfo: [NSObject : AnyObject], completionHandler: () -> Void) {

    UAirship.push().appReceivedActionWithIdentifier(identifier!,
        notification: userInfo,
        responseInfo: responseInfo,
        applicationState: application.applicationState,
        completionHandler: completionHandler)
}
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    [[UAirship push] appRegisteredForRemoteNotificationsWithDeviceToken:deviceToken];
}

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
    [[UAirship push] appRegisteredUserNotificationSettings];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    [[UAirship push] appReceivedRemoteNotification:userInfo
                                  applicationState:application.applicationState];
}

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    [[UAirship push] appReceivedRemoteNotification:userInfo
                                  applicationState:application.applicationState
                            fetchCompletionHandler:completionHandler];
}

- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())handler {
    [[UAirship push] appReceivedActionWithIdentifier:identifier
                                        notification:userInfo
                                    applicationState:application.applicationState
                                   completionHandler:handler];
}

- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())handler {
    [[UAirship push] appReceivedActionWithIdentifier:identifier
                                        notification:userInfo
                                        responseInfo:responseInfo
                                    applicationState:application.applicationState
                                   completionHandler:handler];
}

Logging

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

Addressing Devices

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

Tags

Tags are an easy way to group channels. Many tags can be applied to one or more devices. Then, a message sent to a tag will be sent out to all devices 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.

Example:

Replace existing tags or set a new group of tags

UAirship.push().tags = ["one", "two", "three"]
UAirship.push().updateRegistration()
[UAirship push].tags = @[@"one", @"two", @"three"];
[[UAirship push] updateRegistration];

Add a single tag to the current device tag list and update the server immediately

UAirship.push().addTag("a_tag")
UAirship.push().updateRegistration()
[[UAirship push] addTag:@"a_tag"];
[[UAirship push] updateRegistration];

Remove a single tag from the current device tag list and update the server immediately

UAirship.push().removeTag("a_tag")
UAirship.push().updateRegistration()
[[UAirship push] removeTag:@"a_tag"];
[[UAirship push] updateRegistration];

Named Users

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 iPhone and iPad. 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 can only be associated server-side. A 403 Forbidden response is returned if Named User association is attempted when client-side association is disabled. In order to associate a Named User through the application, you must change the application’s Named User security setting to allow Named Users to be set from devices. Please visit the Settings documentation to enable this option.

Once the application has a channel ID, you can associate the channel to a Named User ID:

UAirship.push().namedUser.identiifier = "NamedUserID"
[UAirship push].namedUser.identifier = @"NamedUserID";

To disassociate a channel from a Named User ID, set its ID to nil:

UAirship.push().namedUser.identiifier = nil
[UAirship push].namedUser.identifier = nil;

Note

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

Tag Groups

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 can only be modified from the server. A 403 Forbidden response is returned if Tag Groups modification is attempted when client-side Tag Groups is disabled. In order to modify Tag Groups through the application, you must change the application’s Tag Group security settings to allow these tags to be set from devices. Please visit the Settings documentation to enable this option.

Channel Tag Groups

Once you have created a Tag Group, you can add or remove tags for the Tag Group on the channel. In this example, we have created a Tag Group loyalty.

Add tags to a Tag Group on the channel:

// Add tags to a Tag Group.
let tagsToAdd = ["silver-member", "gold-member"]
UAirship.push().addTags(tagsToAdd, group:"loyalty")

// Update the registration
UAirship.push().updateRegistration()
// Add tags to a Tag Group.
NSArray *tagsToAdd = @[@"silver-member", @"gold-member"];
[[UAirship push] addTags:tagsToAdd group:@"loyalty"];

// Update the registration.
[[UAirship push] updateRegistration];

Remove tags from a Tag Group on the channel:

// Remove tags from a Tag Group.
let tagsToRemove = ["bronze-member", "club-member"]
UAirship.push().removeTags(tagsToAdd, group:"loyalty")

// Update the registration
UAirship.push().updateRegistration()
// Remove tags from a Tag Group.
NSArray *tagsToRemove = @[@"bronze-member", @"club-member"];
[[UAirship push] removeTags:tagsToRemove group:@"loyalty"];

// Update the registration.
[[UAirship push] updateRegistration];

Note

If setting channel tags is enabled on the device, the predefined device Tag Group cannot be modified from the device and will log an error message. Disable channel tags by setting channelTagRegistrationEnabled to NO on UAPush if you want to modify this “default” Tag Group.

Named User Tag Groups

Named users provide the ability to directly set tags on them. Once you have created a Tag Group and associated a channel with the Named User, you can add or remove tags for the Tag Group on that Named User. In this example, we have created a Tag Group loyalty.

Add tags to a Tag Group on a Named User:

// Add tags to a Tag Group.
let tagsToAdd = ["silver-member", "gold-member"]
UAirship.push().namedUser.addTags(tagsToAdd, group:"loyalty")

// Apply the change.
UAirship.push().namedUser.updateTags()
// Add tags to a Tag Group.
NSArray *tagsToAdd = @[@"silver-member", @"gold-member"];
[[UAirship push].namedUser addTags:tagsToAdd group:@"loyalty"];

// Apply the change.
[[UAirship push].namedUser updateTags];

Remove tags from a Tag Group on a Named User:

// Add tags to a Tag Group.
let tagsToRemove = ["silver-member", "gold-member"]
UAirship.push().namedUser.removeTags(tagsToAdd, group:"loyalty")

// Apply the change.
UAirship.push().namedUser.updateTags()
// Remove tags from a Tag Group.
NSArray *tagsToRemove = @[@"silver-member", @"gold-member"];
[[UAirship push].namedUser removeTags:tagsToRemove group:@"loyalty"];

// Apply the change.
[[UAirship push].namedUser updateTags];

Custom Identifiers

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, iOS Vendor ID, iOS 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.

Note

Previous identifiers will be replaced by the new identifiers each time associateIdentifiers is called. It is a set operation.

Add a custom identifier:

// Get the current identifiers
let identifiers = UAirship.shared().analytics.currentAssociatedDeviceIdentifiers()

// Add a custom identifier
identifiers.setIdentifier("customIdentifier", forKey:"customkey")

// Associate the identifiers
UAirship.shared().analytics.associateDeviceIdentifiers(identifiers)
// Get the current identifiers
UAAssociatedIdentifiers *identifiers = [[UAirship shared].analytics currentAssociatedDeviceIdentifiers];

// Add a custom identifier
[identifiers setIdentifier:@"customIdentifier" forKey:@"customKey"];

// Associate the identifiers
[[UAirship shared].analytics associateDeviceIdentifiers:identifiers];

Add the iOS Advertising ID:

// Get the current identifiers
let identifiers = UAirship.shared().analytics.currentAssociatedDeviceIdentifiers()

// Set the advertising ID info
identifiers.advertisingID = ASIdentifierManager.sharedManager().advertisingIdentifier.UUIDString;
identifiers.advertisingTrackingEnabled = ASIdentifierManager.sharedManager().advertisingTrackingEnabled;
identifiers.vendorID = UIDevice.currentDevice().identifierForVendor?.UUIDString

// Associate the identifiers
UAirship.shared().analytics.associateDeviceIdentifiers(identifiers)
// Get the current identifiers
UAAssociatedIdentifiers *identifiers = [[UAirship shared].analytics currentAssociatedDeviceIdentifiers];

// Set the advertising ID info
identifiers.advertisingID = [[ASIdentifierManager sharedManager].advertisingIdentifier] UUIDString];
identifiers.advertisingTrackingEnabled = [ASIdentifierManager sharedManager].advertisingTrackingEnabled;
identifiers.vendorID = [[UIDevice currentDevice].identifierForVendor UUIDString];

// Associate the identifiers
[[UAirship shared].analytics associateDeviceIdentifiers:identifiers];

Push

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

Badges

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

UIApplication.sharedApplication().applicationIconBadgeNumber = 0;
[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:

UAirship.push().updateRegistration()
[[UAirship push] updateRegistration];

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

// Set to bade to 1
UAirship.push().setBadgeNumber(1)

// Reset the badge
UAirship.push().resetBadge()
// Set to bade to 1
[[UAirship push] setBadgeNumber:1];

// Reset the badge
[[UAirship push] resetBadge];

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 [UAPush 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:

UAirship.push().autobadgeEnabled = true

// Reset the badge
UAirship.push().resetBadge()
[UAirship push].autobadgeEnabled = YES;

// Reset the badge
[[UAirship push] resetBadge];

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

Quiet Time

// Set the quiet time from 7:30pm - 7:30am
UAirship.push().setQuietTimeStartHour(19, startMinute: 30, endHour: 7, endMinute: 30)

// Enable quiet time
UAirship.push().quietTimeEnabled = true

// Update registration
UAirship.push().updateRegistration()
// Set the quiet time from 7:30pm - 7:30am
[[UAirship push] setQuietTimeStartHour:19 startMinute:30 endHour:7 endMinute:30];

// Enable quiet time
[UAirship push].quietTimeEnabled = YES;

// Update registration
[[UAirship push] updateRegistration];

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:

UAirship.push().pushNotificationDelegate = customPushDelegate
[UAirship push].pushNotificationDelegate = customPushDelegate;

Background Push

The library provides support for background notifications that were introduced in iOS 7. Background pushes are push notifications that can launch or resume the app in the background and fetch new content. It is highly recommended that developers enable this background mode in their applications.

To support this mode, first you must include the UIBackgroundModes key with the 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 Background Modes and Remote notifications under the target’s Capabilities section:

Then, create a custom UAPushNotificationDelegate that implements receivedBackgroundNotification:fetchCompletionHandler:, which will perform your task when a background push is received.

Example:

func receivedForegroundNotification(notification: [NSObject : AnyObject], fetchCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)) {
  // App received a foreground notification

  // Call the completion handler
  completionHandler(UIBackgroundFetchResult.NoData)
}

func launchedFromNotification(notification: [NSObject : AnyObject], fetchCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)) {
    // App was launched from a notification

    // Call the completion handler
    completionHandler(UIBackgroundFetchResult.NoData)
}

func launchedFromNotification(notification: [NSObject : AnyObject], actionIdentifier identifier: String, completionHandler: () -> Void) {
    // App was launched from a notification action button

    // Call the completion handler
    completionHandler()
}


func receivedBackgroundNotification(notification: [NSObject : AnyObject], actionIdentifier identifier: String, completionHandler: () -> Void) {
    // App was launched in the background from a notificaiton action button

    // Call the completion handler
    completionHandler()
}

func receivedBackgroundNotification(notification: [NSObject : AnyObject], fetchCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)) {
    // App received a background notification

    // Call the completion handler
    completionHandler(UIBackgroundFetchResult.NoData)
}
- (void)receivedForegroundNotification:(NSDictionary *)notification fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    // App received a foreground notification

    // Call the completion handler
    completionHandler(UIBackgroundFetchResultNoData);
}

- (void)launchedFromNotification:(NSDictionary *)notification fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
    // App was launched from a notification

    // Call the completion handler
    completionHandler(UIBackgroundFetchResultNoData);
}

- (void)launchedFromNotification:(NSDictionary *)notification actionIdentifier:(NSString *)identifier completionHandler:(void (^)())completionHandler {
    // App was launched from a notification action button

    // Call the completion handler
    completionHandler()
}

- (void)receivedBackgroundNotification:(NSDictionary *)notification actionIdentifier:(NSString *)identifier completionHandler:(void (^)())completionHandler {
    // App was launched in the background from a notificaiton action button

    // Call the completion handler
    completionHandler()
}

- (void)receivedBackgroundNotification:(NSDictionary *)notification fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    // App received a background notification

    // Call the completion handler
    completionHandler(UIBackgroundFetchResultNoData);
}

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.

Finally, set the custom UAPushNotificationDelegate after takeOff.

UAirship.push().pushNotificationDelegate = customPushDelegate
[UAirship push].pushNotificationDelegate = customPushDelegate;

If background pushes are not working after following the above steps, see iOS Background Push Troubleshooting.

Interactive Notifications

Built-In Interactive Notification Types

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 (Categories)

In order to define a custom Interactive Notification type, you must register a new category.

Note

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

Custom UIUserNotificationCategories are supported by setting the set of categories on [UAirship push].userNotificationCategories.

Categories can be set after takeOff. After takeOff completes (i.e., application:didFinishLaunchingWithOptions: has returned), any modifications to the user notification categories will require an update to the registration settings by calling [UAirship push] updateRegistration].

Note

[UAirship push] updateRegistration] supplants [UAirship push] updateAPNSRegistration] and handles registration for both APNS and Channels.

Example:

// Define an action for the category
let categoryAction = UIMutableUserNotificationAction()
categoryAction.destructive = false
categoryAction.activationMode = UIUserNotificationActivationMode.Foreground;
categoryAction.authenticationRequired = true
categoryAction.title = "Action!"
categoryAction.identifier = "category_action"

// Define the category
let category = UIMutableUserNotificationCategory()
category.setActions([categoryAction], forContext: UIUserNotificationActionContext.Minimal)
category.setActions([categoryAction], forContext: UIUserNotificationActionContext.Default)
category.identifier = "custom_category"

// Set the custom categories
UAirship.push().userNotificationCategories = Set([category])

// Update registration
UAirship.push().updateRegistration()
// Define an action for the category
UIMutableUserNotificationAction *categoryAction = [[UIMutableUserNotificationAction alloc] init];
categoryAction.destructive = NO;
categoryAction.activationMode = UIUserNotificationActivationModeForeground;
categoryAction.authenticationRequired = YES;
categoryAction.title = @"Action!";
categoryAction.identifier = @"category_action";

// Define the category
UIMutableUserNotificationCategory *category = [[UIMutableUserNotificationCategory alloc] init];
[category setActions:@[categoryAction] forContext:UIUserNotificationActionContextMinimal];
[category setActions:@[categoryAction] forContext:UIUserNotificationActionContextDefault];
category.identifier = @"custom_category";

// Set the custom categories
[UAirship push].userNotificationCategories = [NSSet setWithArray:@[category]];

// Update registration
[[UAirship push] updateRegistration];

User Notification Action Callbacks

Custom-defined Interactive Notification types can either make use of Urban Airship’s pre-defined actions, or you can write new custom action code.

If you want to bypass Urban Airship’s actions, you can can receive callbacks through either the UIApplicationDelegate or UAPushNotificationDelegate.

UIApplicationDelegate:

func application(application: UIApplication, handleActionWithIdentifier identifier: String?,forRemoteNotification userInfo: [NSObject : AnyObject], completionHandler: () -> Void)
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier
                                                      forRemoteNotification:(NSDictionary *)userInfo
                                                          completionHandler:(void(^)())completionHandler;

UAPushNotificationDelegate:

/**
 * Called when the app is started from a user notification action button with foreground activation mode.
 *
 * @param notification The notification dictionary.
 * @param identifier The user notification action identifier.
 * @param completionHandler Should be called as soon as possible.
 */
func launchedFromNotification(notification: [NSObject : AnyObject], actionIdentifier identifier: String, completionHandler: () -> Void)

/**
 * Called when the app is started from a user notification action button with background activation mode.
 *
 * @param notification The notification dictionary.
 * @param identifier The user notification action identifier.
 * @param completionHandler Should be called as soon as possible.
 */
func receivedBackgroundNotification(notification: [NSObject : AnyObject], actionIdentifier identifier: String, completionHandler: () -> Void)
/**
 * Called when the app is started from a user notification action button with foreground activation mode.
 *
 * @param notification The notification dictionary.
 * @param identifier The user notification action identifier.
 * @param completionHandler Should be called as soon as possible.
 */
- (void)launchedFromNotification:(NSDictionary *)notification actionIdentifier:(NSString *)identifier completionHandler:(void (^)())completionHandler;


/**
 * Called when the app is started from a user notification action button with background activation mode.
 *
 * @param notification The notification dictionary.
 * @param identifier The user notification action identifier.
 * @param completionHandler Should be called as soon as possible.
 */
- (void)receivedBackgroundNotification:(NSDictionary *)notification actionIdentifier:(NSString *)identifier completionHandler:(void (^)())completionHandler;

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 library comes with pre-made actions for common tasks such as setting/modifying tags, showing a landing page, enabling deep linking, displaying the inbox or inbox message 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

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:

UAirship.shared().actionRegistry().registerAction(action, names:["action_name", "action_alias"])
[UAirship shared].actionRegistry registerAction:action names:@[@"action_name", @"action_alias"];

Looking up an action entry:

let entry = UAirship.shared().actionRegistry().registryEntryWithName("action_name")
UAActionRegistryEntry *entry = [[UAirship shared].actionRegistry registryEntryWithName:@"action_name"];

Setting a predicate:

// Predicate that only allows the action to run if it was launched from a push
func predicate(args: UAActionArguments) -> Bool {
    return args.situation == UASituation.LaunchedFromPush
}

// Update the predicate
UAirship.shared().actionRegistry.updatePredicate(predicate, forEntryWithName: "action_name")
// 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
[[UAirship shared].actionRegistry updatePredicate:predicate forEntryWithName:@"action_name"];

Triggering Actions

Actions can be triggered automatically through push via our REST API or Message Composer platform. They can also be triggered automatically from a web view displaying message center content. This interaction between web content and the Actions Framework is described in more detail in Custom HTML Templates.

It’s possible to trigger actions manually as well, but it’s 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.

// Run an action by name
UAActionRunner.runActionWithName("action_name", value: "action_value", situation: UASituation.ManualInvocation) { (result: UAActionResult) in
    print("Action finsihed!")
}

// Run an action directly
UAActionRunner.runAction(action, value: "action_value", situation: UASituation.ManualInvocation) { (result: UAActionResult) in
    print("Action finsihed!")
}
// Optional completion handler
UAActionCompletionHandler completionHandler = ^(UAActionResult *result) {
    NSLog("Action finished!");
};

// Run an action by name
[UAActionRunner runActionWithName:@"action_name"
                            value:@"actionValue"
                        situation:UASituationManualInvocation
                completionHandler:completionHandler];

// Run an action directly
[UAActionRunner runAction:action
                    value:@"actionValue"
                situation:UASituationManualInvocation
        completionHandler:completionHandler];

Available Actions

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 perform its work on a background queue and call the UAActionCompletionHandler when finished.

Example:

let customAction = UAAction(block: { (args: UAActionArguments, handler: UAActionCompletionHandler) -> Void in
    print("Action is performing with UAActionArguments: \(args)")

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

    handler([UAActionResult emptyResult]);
}];

Register the action after takeoff:

UAirship.shared().actionRegistry.registerAction(customAction, name:"custom_action")
[[UAirship shared].actionRegistry registerAction:customAction name:@"custom_action"];

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, verify you followed the steps in Automatic Integration for proper integration.

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

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.

Example:

let event = UACustomEvent(name: "event_name", value: 123.12)

// Record the event
UAirship.shared().analytics.addEvent(event)
UACustomEvent *event = [UACustomEvent eventWithName:@"event_name" value:@123.12];

// Record the event
[[UAirship shared].analytics addEvent:event];

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.

You can disable analytics at runtime, which will delete any locally stored events and prevent any events from uploading.

UAirship.shared().analytics.enabled = false
[UAirship shared].analytics.enabled = NO;

Warning

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

Message Center

Displaying the Message Center

The default message center can be displayed at any time by calling display on UADefaultMessageCenter instance.

UAirship.defaultMessageCenter().display()
[[UAirship defaultMessageCenter] display];

Styling the Message Center

The default message center’s look can be customized by creating a UADefaultMessageCenterStyle instance, setting its style properties, and then setting the style property of the Message Center instance to the customized style instance:

let style = UADefaultMessageCenterStyle()

// Customize the style object
style.navigationBarColor = UIColor(red: 0.988, green: 0.694, blue: 0.106, alpha: 1)
style.titleColor = UIColor(red: 0.039, green: 0.341, blue: 0.490, alpha: 1)
style.tintColor = UIColor(red: 0.039, green: 0.341, blue: 0.490, alpha: 1)

style.titleFont = UIFont(name: "Roboto-Regular", size: 17.0)
style.cellTitleFont = UIFont(name: "Roboto-Bold", size: 14.0)
style.cellDateFont = UIFont(name: "Roboto-Light", size: 12.0)

// Set the style
UAirship.defaultMessageCenter().style = style
UADefaultMessageCenterStyle *style = [UADefaultMessageCenterStyle style];

// Customize the style object
style.navigationBarColor = [UIColor colorWithRed:0.988 green:0.694 blue:0.106 alpha:1];
style.titleColor = [UIColor colorWithRed:0.039 green:0.341 blue:0.490 alpha:1];
style.tintColor = [UIColor colorWithRed:0.039 green:0.341 blue:0.490 alpha:1];

style.titleFont = [UIFont fontWithName:@"Roboto-Regular" size:17.0];
style.cellTitleFont = [UIFont fontWithName:@"Roboto-Bold" size:13.0];
style.cellDateFont = [UIFont fontWithName:@"Roboto-Light" size:12.0];

// Set the style
[UAirship defaultMessageCenter].style = style;

This can also be done without writing code by creating a plist file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>titleFont</key>
        <dict>
                <key>fontName</key>
                <string>Roboto-Regular</string>
                <key>fontSize</key>
                <string>17</string>
        </dict>
        <key>titleColor</key>
        <string>#00698f</string>
        <key>tintColor</key>
        <string>#00698f</string>
        <key>navigationBarColor</key>
        <string>#eaaa00</string>
        <key>iconsEnabled</key>
        <false/>
        <key>cellTitleFont</key>
        <dict>
                <key>fontName</key>
                <string>Roboto-Bold</string>
                <key>fontSize</key>
                <string>13</string>
        </dict>
        <key>cellDateFont</key>
        <dict>
                <key>fontName</key>
                <string>Roboto-Light</string>
                <key>fontSize</key>
                <string>17</string>
        </dict>
</dict>
</plist>

To initialize a message center style from the plist, use the [UADefaultMessageCenter styleWithContentsOfFile] method:

let style = UADefaultMessageCenterStyle(contentsOfFile:plistFileName)
UADefaultMessageCenterStyle *style = [UAMessageCenterStyle styleWithContentsOfFile:plistFileName];

Aside from setting the style directly, as shown above, you can also apply this style to the default message center directly in your AirshipConfig.plist by setting the messageCenterStyleConfig key with the name of your plist file:

<key>messageCenterStyleConfig</key>
<string>Your Message Center Style Config File</string>

Message Center Filtering

Sometimes it can be useful to filter the contents of the message center according to some predetermined pattern. To facilitate this, use the [UADefaultMessageCenter filter] property to set a predicate. Once set, only messages that match the predicate will be displayed. As a simple example, the filter shown below keeps only messages whose titles contain the string “Cool”.

UAirship.defaultMessageCenter().filter = NSPredicate { (evaluatedObject, _) in
    let message = evaluatedObject as! UAInboxMessage
    return message.title.containsString("Cool")
};
[UAirship defaultMessageCenter].filter = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
    UAInboxMessage *message = (UAInboxMessage *)evaluatedObject;
    return [message.title containsString:@"Cool"];
}];

Overriding the default Message Center

For custom Message Center implementations, initialize the UAInboxDelegate with the custom Message Center implementation’s view controller. This is necessary to ensure that the default modal Message Center is not displayed on top of the custom Message Center when a message is received.

self.inboxDelegate = CustomInboxDelegate()
UAirship.inbox().delegate = self.inboxDelegate
self.inboxDelegate = [[CustomInboxDelegate alloc] init];
[UAirship inbox].delegate = self.inboxDelegate;

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 applications implementing the Message Center, you may want the badge value to represent the actual state of unread messages in the Message Center. 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:

func applicationWillResignActive(application: UIApplication) {
    if (UAirship.inbox().messageList.unreadCount >= 0) {
        application.applicationIconBadgeNumber = UAirship.inbox().messageList.unreadCount
    }
}
- (void)applicationWillResignActive:(UIApplication *)application {
    if ([UAirship inbox].messageList.unreadCount >= 0) {
        application.applicationIconBadgeNumber = [UAirship inbox].messageList.unreadCount;
    }
}

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

In-App Messaging

In-app messages are banner notifications that appear inside of your app. Aside from giving you the power to engage with users as they browse your app, they also allow you to reach opted out users in iOS 8 and above, a segment of the app audience that has previously been difficult to target.

Requirements

In-app messaging requires iOS 7+ and for Background Push to be enabled in your app’s capabilities.

A Note on Background Notifications

Without the remote notifications background mode, apps are limited to receiving silent pushes in the foreground only. On iOS 8, background notifications can be received even if the user has opted out or was never prompted. For the widest possible reach, you should encourage your users to upgrade to iOS 8.

Display

By default, in-app messages will only display a single banner on app foreground after a three-second delay. You can change this by setting the displayDelay property on [UAirship inAppMessaging]:

Adjusting the auto-display delay to five seconds:

UAirship.inAppMessaging().displayDelay = 5
[UAirship inAppMessaging].displayDelay = 5;

Display ASAP Mode

Enabling display ASAP mode will cause the SDK 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 once the currently displayed message is dismissed, after the autodisplay delay.

Enabling display ASAP:

UAirship.inAppMessaging().displayASAPEnabled = true
[UAirship inAppMessaging].displayASAPEnabled = YES;

Note

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.

Manual Display

The automatic display of in-app messages can be disabled, either to block message display in response to user preferences or to manually control when and where messages should be displayed:

UAirship.inAppMessaging().isAutoDisplayEnabled = false
[UAirship inAppMessaging].isAutoDisplayEnabled = NO;

In the latter case, message display can be triggered manually so that the most recent pending message is displayed at a time more appropriate for the app:

UAirship.inAppMessaging().displayPendingMessage()
[[UAirship inAppMessaging] displayPendingMessage];

Styling and Custom UI

Sending in-app message color overrides is supported through the composer and push API. Additional advanced styling can also be achieved by setting optional properties on the UAInAppMessaging class:

public var font: UIFont
public var defaultPrimaryColor: UIColor
public var defaultSecondaryColor: UIColor
@property(nonatomic, strong) UIFont *font;
@property(nonatomic, strong) UIColor *defaultPrimaryColor;
@property(nonatomic, strong) UIColor *defaultSecondaryColor;

More comprehensive custom UI is possible by setting an optional UAInAppMessageControllerDelegate on the UAInAppMessaging object, which is used to configure details such as custom message views and animation hooks:

UAirship.inAppMessaging().messageControllerDelegate = myMessageControllerDelegate
[UAirship inAppMessaging].messageControllerDelegate = myMessageControllerDelegate;

Required methods for the UAInAppMessageControllerDelegate protocol provide the SDK custom view and control classes at display time, configured using the data contained in the associated UAInAppMessageControllerDelegate object:

public func viewForMessage(message: UAInAppMessage, parentView: UIView) -> UIView
public func messageView(messageView: UIView, buttonAtIndex index: UInt) -> UIControl
- (UIView *)viewForMessage:(UAInAppMessage *)message parentView:(UIView *)parentView;
- (UIControl *)messageView:(UIView *)messageView buttonAtIndex:(NSUInteger)index;

Optional methods allow for additional customization handling touch state (such as inverting colors when the message view is tapped) and the animation of messaging display and dismissal:

optional public func messageView(messageView: UIView, didChangeTouchState touchDown: Bool)
optional public func messageView(messageView: UIView, animateInWithParentView parentView: UIView, completionHandler: () -> Void)
optional public func messageView(messageView: UIView, animateOutWithParentView parentView: UIView, completionHandler: () -> Void)
- (void)messageView:(UIView *)messageView didChangeTouchState:(BOOL)touchDown;
- (void)messageView:(UIView *)messageView animateInWithParentView:(UIView *)parentView completionHandler:(void (^)(void))completionHandler;
- (void)messageView:(UIView *)messageView animateOutWithParentView:(UIView *)parentView completionHandler:(void (^)(void))completionHandler;

Interactive Notification Compatibility Classes

In order to support interactive notification buttons on in-app messages for iOS 7, we’ve added a set of compatibility classes that mirror the functionality of apple’s user notification category and action model objects:

Use these classes instead of the corresponding UIUserNotificationCategory and UIUserNotificationAction classes if you wish to add custom interactive push buttons to in-app messages in iOS 7.

Location Targeting

The significant change service is the preferred method for acquiring data for long periods of time. If the accuracy of the significant change service is not high enough for your app’s needs, a combination of [UALocationService reportCurrentLocation] and the automaticLocationOnForegroundEnabled service can be used to add more accurate GPS data points on app foreground events. Running the standard location service for prolonged periods of time has a serious impact on battery life, and should be used wisely. On an iPhone 4S, using the full power GPS depleted 20% of the battery in 26 minutes when combined with nominal web surfing.

Authorization

Before you can access the user’s location, the user must authorize your application via a location authorization prompt. For the authorization prompt to display properly, you must add the NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription keys to your application’s info.plist. To maintain iOS7 compatibility, the NSLocationUsageDescription must also be present:

Once the necessary description keys are in place, the location authorization prompt can request to allow location services only when the application is in use by setting requestAlwaysAuthorization to NO. By default, the location authorization prompt requests continuous background monitoring authorization and requestAlwaysAuthorization is set to YES:

UAirship.shared().locationService.requestAlwaysAuthorization = true
[UAirship shared].locationService.requestAlwaysAuthorization = YES;

Check for user authorization with:

UALocationService.locationServicesEnabled()
UALocationService.locationServiceAuthorized()
UALocationService.airshipLocationServiceEnabled()
[UALocationService locationServicesEnabled];
[UALocationService locationServiceAuthorized];
[UALocationService airshipLocationServiceEnabled];

Location Updates

After the user has given authorization, and you have enabled UA location services via [UALocationService setAirshipLocationServiceEnabled:], you can query the user’s location with the following:

Any time a location is needed:

UAirship.shared().locationService.reportCurrentLocation()
[[UAirship shared].locationService reportCurrentLocation];

Starting the service:

UAirship.shared().locationService.startReportingSignificantLocationChanges()
[[UAirship shared].locationService startReportingSignificantLocationChanges];

Stopping the Service:

UAirship.shared().locationService.stopReportingSignificantLocationChanges()
[[UAirship shared].locationService stopReportingSignificantLocationChanges];

Background Location Updates

Urban Airship location services stop detecting and uploading location data when the app is sent to the background unless background location is explicitly allowed for that app. Once the background location service is allowed, location data can be detected and uploaded during the next app open when a normal Analytics event occurs.

Enable background location:

UAirship.shared().locationService.backgroundLocationServiceEnabled = true
[UAirship shared].locationService.backgroundLocationServiceEnabled = YES;

Any running service will be shut down completely when an app is cleared by swiping up on that app from the Recent Apps screen whether or not backgroundLocationServiceEnabled is enabled.

Any running service that has not enabled backgroundLocationServiceEnabled will be shut down on app background (UIApplicationDidEnterBackgroundNotification) and will be automatically restarted on app foreground (UIApplicationWillEnterForegroundNotification) . Be aware of this when using the UALocationService callbacks to update UI elements with location data.

An exception to this is the single location service. The single location service, once started, will continue running as a background task until a location is retrieved or the default timeout of 30 seconds has passed. Please refer to both the Urban Airship documentation and the Apple documentation for more information:

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, follow these steps:

  1. Copy the UrbanAirship.strings file and translate it into another language:

    "ua_notification_button_yes" = "Yes";
    "ua_notification_button_no" = "No";
    "ua_notification_button_shop_now" = "Shop Now";
    "ua_notification_button_buy_now" = "Buy Now";
    "ua_notification_button_follow" = "Follow";
    "ua_notification_button_unfollow" = "Unfollow";
    "ua_notification_button_opt_in" = "Opt-in";
    "ua_notification_button_opt_out" = "Opt-out";
    "ua_notification_button_remind" = "Remind Me Later";
    "ua_notification_button_share" = "Share";
    "ua_notification_button_accept" = "Accept";
    "ua_notification_button_decline" = "Decline";
    "ua_notification_button_download" = "Download";
    "ua_notification_button_more_like" = "More Like This";
    "ua_notification_button_less_like" = "Less Like This";
    "ua_notification_button_like" = "Like";
    "ua_notification_button_dislike" = "Dislike";
    "ua_notification_button_copy" = "Copy";
    "ua_notification_button_save" = "Save";
    "ua_notification_button_add_to_calendar" = "Add to Calendar";
    "ua_notification_button_add" = "Add";
    "ua_notification_button_tell_me_more" = "Tell Me More";
    "ua_notification_button_send_info" = "Send Info";
    "ua_notification_button_rate_now" = "Rate Now";
    "ua_notification_button_search" = "Search";
    "ua_notification_button_book_now" = "Book Now";
    "ua_share_dialog_title" = "Share";
    "ua_channel_notification_ticker" = "Urban Airship Channel";
    "ua_channel_copy_toast" = "Channel copied to clipboard!";
    "ua_message_center_title" = "Message Center";
    "ua_empty_message_list" = "No messages";
    "ua_message_not_selected" = "No messages selected";
    "ua_mc_failed_to_load" = "Unable to load message. Please try again later.";
    "ua_retry_button" = "Retry";
    "ua_ok" = "OK";
    "ua_cancel" = "Cancel";
    "ua_select_none" = "Select None";
    "ua_select_all" = "Select All";
    "ua_connection_error" = "Connection Error";
    "ua_mark_read" = "Mark Read";
    "ua_delete" = "Delete";
    
  2. Add the new localization to the application in the project’s info section.