In-App Automation

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

 Note

This guide applies to in-app messages sent via In-App Automation.

In-app messaging can improve your engagement strategy by providing messages that can be customized to be visually consistent with the the rest of your app. Most customization can be accomplished through the dashboard composer, however more advanced customization can be obtained by modifying the Airship SDK. This guide outlines how to customize iOS in-app messages.

Feature enablement

The in-app messaging manager can be enabled or disabled. When the manager is disabled it prevents any in-app messages from displaying and any events from counting towards a trigger's goal.

Disabling the manager:

[[UAirship inAppMessageManager] setEnabled:false];
UAirship.inAppMessageManager().isEnabled = false

Pausing message display

Pausing is similar to disabling the manager, but messages can continue to be triggered and queued up for display. This is useful for preventing in-app message displays on screens where it would be detrimental to the user experience, such as splash screens, settings screens, or landing pages.

Pausing the manager:

[[UAirship inAppMessageManager] setPaused:true];
UAirship.inAppMessageManager().isPaused = true

Display interval

The display interval controls the amount of time to wait before the manager is able to display the next triggered in-app message. The default value is set to 30 seconds but can be adjusted to any amount of time in seconds.

Setting the display interval to 10 seconds:

[UAirship inAppMessageManager].displayInterval = 10;
UAirship.inAppMessageManager().displayInterval = 10

Implementing the UAInAppMessagingDelegate protocol

Example delegate:

- (UAInAppMessage *)extendMessage:(UAInAppMessage *)message {
    // Can be used to modify the message before it is displayed
    return message;
}

-(void)messageWillBeDisplayed:(UAInAppMessage \*)message scheduleID:(NSString \*)scheduleID {
  // Message displayed
}

-(void)messageFinishedDisplaying:(UAInAppMessage \*)message scheduleID:(NSString \*)scheduleID resolution:(UAInAppMessageResolution \*)resolution {
  // Message finished
}
func extend(_ message: UAInAppMessage) -> UAInAppMessage {
    // Can be used to modify the message before it is displayed
    return message
}

func messageWillBeDisplayed(_ message: UAInAppMessage, scheduleID: String) {
  // Message displayed
}

func messageFinishedDisplaying(_ message: UAInAppMessage, scheduleID: String, resolution: UAInAppMessageResolution) {
    // Message finished
}

Setting the delegate

[UAirship inAppMessageManager].delegate = automationDelegate;
UAirship.inAppMessageManager().delegate = automationDelegate

The UAInAppMessagingDelegate can be implemented to receive callback when a message is displayed, finished displaying, and to modify the message before being displayed.

Fonts

Fonts added to the app bundle are available for use with in-app messaging. To add fonts, please read the The UIKit Custom Fonts Guide.

Customization

In-app messages are fully customizable. Minor modifications can be accomplished by overriding the styles with a plist, but more advanced customizations can employ an adapter for the given message type.

Styles

Plists can be used to modify any of the default message styles that the SDK provides. Each message type can be customized with a different plist:

  • Banner: UAInAppMessageBannerStyle.plist
  • HTML: UAInAppMessageHTMLStyle.plist
  • FullScreen: UAInAppMessageFullScreenStyle.plist
  • Modal: UAInAppMessageModalStyle.plist

Individual messages can be customized by setting a custom factory block on the in-app message which configures a display adapter with the appropriate style:

[[UAirship inAppMessageManager] setFactoryBlock:^id<UAInAppMessageAdapterProtocol> (UAInAppMessage *message) {
    UAInAppMessageHTMLAdapter *adapter = [UAInAppMessageHTMLAdapter adapterForMessage:message];
    adapter.style = [UAInAppMessageHTMLStyle style];
    adapter.style.additionalPadding = [UAPadding paddingWithTop:20 bottom:20 leading:0 trailing:0];
    return adapter;
} forDisplayType:UAInAppMessageDisplayTypeHTML];
UAirship.inAppMessageManager().setFactoryBlock({ (message) -> UAInAppMessageAdapterProtocol in
    let adapter = UAInAppMessageHTMLAdapter.adapter(for:message)
    let style = UAInAppMessageHTMLStyle()
    style.additionalPadding = UAPadding(top: 20, bottom: 20, leading: 0, trailing: 0)
    adapter.style = style
    return adapter
}, for: .HTML)

Plist values

Banner

  • additionalPadding: Padding. Adds padding around the view.
  • headerStyle: Text Style. Customizes the message's header.
  • bodyStyle: Text Style. Customizes the message's body.
  • mediaStyle: Media Style. Customizes the message's media.
  • buttonStyle: Buttons Style. Customzies the message's buttons.
  • maxWidth: Points. Max width.

FullScreen

  • headerStyle: Text Style. Customizes the banner's header.
  • bodyStyle: Text Style. Customizes the banner's body.
  • mediaStyle: Media Style. Customizes the banner's media.
  • buttonStyle: Buttons Style. Customzies the banner's buttons.
  • dismissIconResource: String. Resource name for a custom dismiss icon.

Modal

  • additionalPadding: Padding. Adds padding around the view.
  • headerStyle: Text Style. Customizes the banner's header.
  • bodyStyle: Text Style. Customizes the banner's body.
  • mediaStyle: Media Style. Customizes the banner's media.
  • buttonStyle: Buttons Style. Customzies the banner's buttons.
  • dismissIconResource: String. Resource name for a custom dismiss icon.
  • maxWidth: Points. Max width.
  • maxHeight: Points. Max height.

HTML

  • additionalPadding: Padding. Adds padding around the view.
  • dismissIconResource: String. Resource name for a custom dismiss icon.
  • maxWidth: Points. Max width.
  • maxHeight: Points. Max height.

Padding

  • top: Points. Top padding.
  • botttom: Points. Bottom padding.
  • leading: Points. Leading padding.
  • trailing: Points. Trailing padding.

Buttons Style

  • additionalPadding: Padding. Adds padding around the button area.
  • buttonHeight: Points. Button height.
  • stackedButtonSpacing: Points. Button spacing in the stacked layout.
  • separatedButtonSpacing: Points. Button spacing in the separated layout.
  • borderWidth: Points. Button's border width.
  • buttonTextStyle: Text Style. Text style for each button.

Text Style

  • additionalPadding: Padding. Adds padding around the view.
  • letterSpacing: Points. Spacing between the letters.
  • lineSpacing: Points. Spacing between lines.

Media Style

  • additionalPadding: Padding. Adds padding around the view.

Custom adapters

Providing an adapter allows defining the behavior of the custom type or overriding any of the default message types. The adapter will be created by the in-app messaging manager when a message's schedule is triggered. Once created, the adapter will be called to first prepare the in-app message, giving the adapter time to download any resources such as images. After the adapter prepares the message, the adapter will be called to display the message.

After the message is displayed, the caller of the display method must be notified that the message is finished displaying by passing a UAInAppMessageResolution into the display method's completion handler. This will allow for subsequent in-app messages to be displayed.

Example custom adapter:

@implementation CustomInAppMessageAdapter

+(instancetype)adapterForMessage:(UAInAppMessage *)message {
    return [[CustomInAppMessageAdapter alloc] initWithMessage:message];
}

-(instancetype)initWithMessage:(UAInAppMessage *)message {
    self = [super init];

    if (self) {
        self.message = message;
    }

    return self;
}

-(void)prepare:(void (^)(UAInAppMessagePrepareResult))completionHandler {
    // Download any resources for the in-app message before displaying

    // Call the completion handler with the correct result
    completionHandler(UAInAppMessagePrepareResultSuccess)
}

-(BOOL)isReadyToDisplay {
    // Return ready state
    return true
}

-(void)display:(void (^)(UAInAppMessageResolution *))completionHandler {
    // Display the in-app message

    // Create a message resolution object corresponding to the correct resolution type
    UAInAppMessageResolution *messageResolution = [UAInAppMessageResolution messageClickResolution];

    // Call the completion handler with the correct resolution
    completionHandler(messageResolution)
}

@end
final class CustomAdapter : NSObject, UAInAppMessageAdapterProtocol {

    var message: UAInAppMessage

    init(message: UAInAppMessage) {
        self.message = message
    }

    static func adapter(for message: UAInAppMessage) -> CustomAdapter {
        return CustomAdapter(message: message)
    }

    func prepare(_ completionHandler: @escaping (UAInAppMessagePrepareResult) -> Void) {
        // Download any resources for the in-app message before displaying
        // Call the completion handler with the correct result
        completionHandler(.success)
    }

    func isReadyToDisplay() -> Bool {
        // Return ready state
        return true
    }

    func display(_ completionHandler: @escaping (UAInAppMessageResolution) -> Void) {
        // Display the in-app message

        // When the display is finished, notify the completion handler with the result
        completionHandler(UAInAppMessageResolution.messageClick())
    }
}

Set the factory block on the UAInAppMessageManager instance to provide the new adapter:

[[UAirship inAppMessageManager] setFactoryBlock:^id<UAInAppMessageAdapterProtocol> (UAInAppMessage *message) {
    return [CustomInAppMessageAdapter adapterForMessage:message];
} forDisplayType:UAInAppMessageDisplayTypeCustom];
UAirship.inAppMessageManager().setFactoryBlock({ (message) -> UAInAppMessageAdapterProtocol in
    return CustomAdapter(message: message)
}, for: .custom)

Standard In-App Messages

Standard in-app messages delivered through push messages are managed by the legacy in-app message manager. The UALegacyInAppMessageBuilderExtender allows customizing both the schedule and message when the legacy message is being mapped to an in-app automation banner message.

Example UALegacyInAppMessageBuilderExtender:

- (void)extendScheduleInfoBuilder:(UAInAppMessageScheduleInfoBuilder *)builder
                          message:(UALegacyInAppMessage *)message {

    builder.limit = 2;
}

- (void)extendMessageBuilder:(UAInAppMessageBuilder *)builder
                     message:(UALegacyInAppMessage *)message {
    UAInAppMessageBannerDisplayContent *bannerDisplayContent = (UAInAppMessageBannerDisplayContent *) builder.displayContent;
    [bannerDisplayContent extend:^(UAInAppMessageBannerDisplayContentBuilder * _Nonnull builder) {
        builder.borderRadiusPoints = 10;
    }];

    builder.displayContent = bannerDisplayContent;
}
func extend(_ builder: UAInAppMessageScheduleInfoBuilder, message: UALegacyInAppMessage) {
    // Apply any schedule info changes to the builder
    builder.limit = 2
}

func extend(_ builder: UAInAppMessageBuilder, message: UALegacyInAppMessage) {
    // Apply any message changes to the builder
    let bannerDisplayContent = builder.displayContent as! UAInAppMessageBannerDisplayContent
    bannerDisplayContent.extend { (builder) in
        builder.borderRadiusPoints = 10;
    }

    builder.displayContent = bannerDisplayContent
}

Setting the builder extender

[UAirship legacyInAppMessaging].builderExtender = builderExtender;
UAirship.legacyInAppMessaging().builderExtender = builderExtender

For more information on how to customize this conversion process, see the In-App Messages Migration guide.