iOS In-App Automation Customization
Import In-App Automation
In-app messaging services are available as part of the Airship framework as well as a standalone framework called AirshipAutomation.
To access the in-app messaging from the Airship framework, simply import Airship where necessary.
Import using Airship framework
@import AirshipKit;
import AirshipKit
To access in-app messaging from the AirshipAutomation standalone framework, you must add a separate import statement in your code, as shown below:
Import using AirshipAutomation framework
@import AirshipAutomation;
import AirshipAutomation
Listening for Events
A listener can be added to the in-app messaging manager to listen for when a message is displayed and finished displaying. This is useful for adding analytics events outside of Airship as well as for further processing of the in-app message.
Example
// Setting the delegate
UAInAppAutomation.shared.inAppMessageManager.delegate = automationDelegate;
- (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
}
- (UIWindowScene *)sceneForMessage:(UAInAppMessage *)message defaultScene:(nullable UIWindowScene *)defaultScene) {
// Allows overriding choice of message scene
}
// Setting the delegate
InAppAutomation.shared.inAppMessageManager.delegate = automationDelegate
func extend(_ message: InAppMessage) -> InAppMessage {
// Can be used to modify the message before it is displayed
return message
}
func messageWillBeDisplayed(_ message: InAppMessage, scheduleID: String) {
// Message displayed
}
func messageFinishedDisplaying(_ message: InAppMessage, scheduleID: String, resolution: UAInAppMessageResolution) {
// Message finished
}
func scene(for message: InAppMessage, defaultScene: UIWindowScene?) -> UIWindowScene {
// Allows overriding choice of message scene
}
Fonts
Custom 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 .
Dynamic fonts With HTML in-app messages
Most In-App message styles support automatically scaling fonts through the use of Dynamic Type. However, automatically scaling fonts in HTML In-App messages requires you to use the following Apple system fonts when specifying the CSS font property:
-apple-system-body
-apple-system-headline
-apple-system-subheadline
-apple-system-caption1
-apple-system-caption2
-apple-system-footnote
-apple-system-short-body
-apple-system-short-headline
-apple-system-short-subheadline
-apple-system-short-caption1
-apple-system-short-footnote
-apple-system-tall-body
For example, to have the HTML body default to the Apple system font body style:
body {
font: -apple-system-body; // available on Apple devices only
}
For more information about dynamic type, please see this WWDC video .
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:
[UAInAppAutomation.shared.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];
InAppAutomation.shared.inAppMessageManager.setFactoryBlock({ (message) -> InAppMessageAdapterProtocol in
let adapter = InAppMessageHTMLAdapter.adapter(for:message)
let style = InAppMessageHTMLStyle()
style.additionalPadding = Padding(20, 20, 0, 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. Customizes 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. Customizes 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. Customizes the banner’s buttons.dismissIconResource
: String. Resource name for a custom dismiss icon.maxWidth
: Points. Max width.maxHeight
: Points. Max height.extendFullScreenLargeDevice
: Boolean. True to allow the option ‘Display fullscreen on small screen device’ to extend to large devices as well.
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.extendFullScreenLargeDevice
: Boolean. True to allow the option ‘Display fullscreen on small screen device’ to extend to large devices as well.
Padding
top
: Points. Top padding.bottom
: 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)prepareWithAssets:(nonnull UAInAppMessageAssets *)assets
completionHandler:(nonnull 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
// Set the factory block on the UAInAppMessageManager instance to provide the new adapter
[UAInAppAutomation.shared.inAppMessageManager setFactoryBlock:^id<UAInAppMessageAdapterProtocol> (UAInAppMessage *message) {
return [CustomInAppMessageAdapter adapterForMessage:message];
} forDisplayType:UAInAppMessageDisplayTypeCustom];
final class CustomAdapter : NSObject, InAppMessageAdapterProtocol {
var message: InAppMessage
init(message: InAppMessage) {
self.message = message
}
static func adapter(for message: InAppMessage) -> CustomAdapter {
return CustomAdapter(message: message)
}
func prepare(with assets: InAppMessageAssets, completionHandler: @escaping (InAppMessagePrepareResult) -> 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 (InAppMessageResolution) -> Void) {
// Display the in-app message
// When the display is finished, notify the completion handler with the result
completionHandler(InAppMessageResolution.messageClick())
}
}
// Set the factory block on the UAInAppMessageManager instance to provide the new adapter
InAppAutomation.shared.inAppMessageManager.setFactoryBlock({ (message) -> InAppMessageAdapterProtocol in
return CustomAdapter(message: message)
}, for: .custom)
Overriding the Scene
The UAInAppMessageSceneDelegate facilitates overriding the UIWindowScene on which a given in-app message is displayed.
Example:
UAInAppMessageSceneManager.shared.delegate = exampleInAppMessagerSceneDelegate;
- (nullable UIWindowScene *)sceneForMessage:(UAInAppMessage *)message defaultScene:(nullable UIWindowScene *)defaultScene API_AVAILABLE(ios(13.0)) {
// Can be used to return the scene on which the message should display
return myScene;
}
InAppMessageSceneManager.shared.delegate = exampleInAppMessagerSceneDelegate
@available(iOS 13.0, *)
func scene(for message: InAppMessage, defaultScene: UIWindowScene?) -> UIWindowScene? {
// Can be used to return the scene on which the message should display
return myScene
}
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
UALegacyInAppMessaging.shared.builderExtender = builderExtender;
- (void)extendScheduleBuilder:(UAScheduleBuilder *)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;
}
LegacyInAppMessaging.shared.builderExtender = builderExtender
func extend(_ builder: ScheduleBuilder, message: LegacyInAppMessage) {
// Apply any schedule info changes to the builder
builder.limit = 2
}
func extend(_ builder: InAppMessageBuilder, message: LegacyInAppMessage) {
// Apply any message changes to the builder
let bannerDisplayContent = builder.displayContent as! InAppMessageBannerDisplayContent
bannerDisplayContent.extend { (builder) in
builder.borderRadiusPoints = 10;
}
builder.displayContent = bannerDisplayContent
}
Customizing HTML In-App Messages
In order for the Airship JavaScript interface to be loaded into the webview, the URL must be specified in the URL Allowlist.
HTML in-app messages provide a way to display custom content inside a native web view. These types of in-app messages display with a dismiss button built in, but can also be customized to provide their own buttons capable of dismissing the view. Dismissing a view requires calling the dismiss function on the UAirship JavaScript interface with a button resolution object passed in as a parameter. The button resolution object is a JSON object containing information about the interaction type and the button performing the dismissal. It should match the following format:
{
"type" : "button_click",
"button_info" : {
"id" : "button identifier",
"label" : {"text": "foo"}
}
}
The button resolution requires each of the key fields shown above. These include:
type
— The type key with the value of resolution typebutton_click
button_info
— The button info object containing required id and label fieldsid
— The button identifierlabel
— Label object containing the required text keytext
— The text key with a string value representing the label text
Providing a basic dismiss button in HTML:
<button onclick="UAirship.dismiss({
'type' : 'button_click',
'button_info' : {
'id' : 'button identifier',
'label' : {'text' : 'foo'}
}
}
);">Dismiss with resolution</button>
Categories