In-app message UI delegate
Use the optional
BrazeInAppMessageUIDelegate
to customize the presentation of in-app messages and react to various lifecycle events. This delegate protocol can be used to receive triggered in-app message payloads for further processing, receive display lifecycle events, and control display timing.
Prerequisites
To use BrazeInAppMessageUIDelegate
:
- You must be using the default
BrazeInAppMessageUI
implementation as yourinAppMessagePresenter
. - You must include the
BrazeUI
library in your project.
Setting the in-app message delegate
Set your BrazeInAppMessageUIDelegate
delegate object on the Braze instance by following this sample code:
First, implement the BrazeInAppMessageUIDelegate
protocol and any corresponding methods you wish. In our example below, we are implementing this protocol in our application’s AppDelegate
class.
1
2
3
extension AppDelegate: BrazeInAppMessageUIDelegate {
// Implement your protocol methods here.
}
Then assign the delegate
object on the BrazeInAppMessageUI
instance before assigning this in-app message UI as your inAppMessagePresenter
.
1
2
3
let inAppMessageUI = BrazeInAppMessageUI()
inAppMessageUI.delegate = self
AppDelegate.braze?.inAppMessagePresenter = inAppMessageUI
First, implement the BrazeInAppMessageUIDelegate
protocol and any corresponding methods you wish. In our example below, we are implementing this protocol in our application’s AppDelegate
class.
1
2
3
4
5
6
7
@interface AppDelegate () <BrazeInAppMessageUIDelegate>
@end
@implementation AppDelegate
// Implement your protocol methods here.
@end
Then assign the delegate
object on the BrazeInAppMessageUI
instance before assigning this in-app message UI as your inAppMessagePresenter
.
1
2
3
BrazeInAppMessageUI *inAppMessageUI = [[BrazeInAppMessageUI alloc] init];
inAppMessageUI.delegate = self;
AppDelegate.braze.inAppMessagePresenter = inAppMessageUI;
Not all delegate methods are available in Objective-C due to the incompatibility of their parameters with the language runtime.
Step-by-step guide
For a step-by-step implementation of the in-app message UI delegate, refer to this tutorial.
Customizing in-app message orientation for iOS
Setting a preferred orientation
You can configure all in-app messages to be presented in a specific orientation regardless of device orientation. To set a preferred orientation, use the inAppMessage(_:prepareWith:)
delegate method to set the preferredOrientation
property on the PresentationContext
.
For example, to create a preferred orientation of portrait:
1
2
3
4
5
6
func inAppMessage(
_ ui: BrazeInAppMessageUI,
prepareWith context: inout BrazeInAppMessageUI.PresentationContext
) {
context.preferredOrientation = .portrait
}
1
2
3
4
- (void)inAppMessage:(BrazeInAppMessageUI *)ui
prepareWith:(BrazeInAppMessageUIPresentationContextRaw *)context {
context.preferredOrientation = BRZInAppMessageRawOrientationPortrait;
}
Once the in-app message has been presented, any device orientation changes while the message is still displayed will cause the message to rotate with the device, provided it is supported under the message’s orientation
configuration.
Note that the device orientation must also be supported by the in-app message’s orientation
property for the message to display. Additionally, the preferredOrientation
setting will only be respected if it is included in your application’s supported interface orientations under the Deployment Info section of your target’s settings in Xcode.
The orientation is applied only for the presentation of the message. After the device changes orientation, the message view adopts one of the orientations it supports. On smaller devices (iPhones, iPod Touch), setting a landscape orientation for a modal or full in-app message may lead to truncated content.
Modifying message orientations
You may alternatively set the orientation on a per-message basis. This property defines all the available orientation types for that message. To do this, set the orientation
property on a given Braze.InAppMessage
:
1
2
3
4
5
6
7
8
// Set inAppMessage orientation to support any configuration
inAppMessage.orientation = .any
// Set inAppMessage orientation to only display in portrait
inAppMessage.orientation = .portrait
// Set inAppMessage orientation to only display in landscape
inAppMessage.orientation = .landscape
1
2
3
4
5
6
7
8
// Set inAppMessage orientation to support any configuration
inAppMessage.orientation = BRZInAppMessageRawOrientationAny;
// Set inAppMessage orientation to only display in portrait
inAppMessage.orientation = BRZInAppMessageRawOrientationPortrait;
// Set inAppMessage orientation to only display in landscape
inAppMessage.orientation = BRZInAppMessageRawOrientationLandscape;
Disabling dark mode
To prevent in-app messages from adopting dark mode styling when the user device has dark mode enabled, implement the inAppMessage(_:prepareWith:)
delegate method method. The PresentationContext
passed to the method contains a reference to the InAppMessage
object to be presented. Each InAppMessage
has a themes
property containing a dark
and light
mode theme. If you set the themes.dark
property to nil
, Braze will automatically present the in-app message using its light theme.
In-app message types with buttons have an additional themes
object on their buttons
property. To prevent buttons from adopting dark mode styling, you can use map(_:)
to create a new array of buttons with a light
theme and no dark
theme.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
func inAppMessage(
_ ui: BrazeInAppMessageUI,
prepareWith context: inout BrazeInAppMessageUI.PresentationContext
) {
switch context.message {
case .slideup:
guard var slideup = context.message.slideup else { return }
slideup.themes.dark = nil
context.message.slideup = slideup
case .modal:
guard var modal = context.message.modal else { return }
modal.themes.dark = nil
modal.buttons = modal.buttons.map {
var newButton = $0
newButton.themes = .init(themes: ["light": $0.themes.light])
return newButton
}
context.message.modal = modal
case .modalImage:
guard var modalImage = context.message.modalImage else { return }
modalImage.themes.dark = nil
modalImage.buttons = modalImage.buttons.map {
var newButton = $0
newButton.themes = .init(themes: ["light": $0.themes.light])
return newButton
}
context.message.modalImage = modalImage
case .full:
guard var full = context.message.full else { return }
full.themes.dark = nil
full.buttons = full.buttons.map {
var newButton = $0
newButton.themes = .init(themes: ["light": $0.themes.light])
return newButton
}
context.message.full = full
case .fullImage:
guard var fullImage = context.message.fullImage else { return }
fullImage.themes.dark = nil
fullImage.buttons = fullImage.buttons.map {
var newButton = $0
newButton.themes = .init(themes: ["light": $0.themes.light])
return newButton
}
context.message.fullImage = fullImage
default:
break
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
- (void)inAppMessage:(BrazeInAppMessageUI *)ui
prepareWith:(BrazeInAppMessageUIPresentationContextRaw *)context {
switch (context.message.type) {
case BRZInAppMessageRawTypeSlideup: {
NSMutableDictionary *updatedThemes = [context.message.themes mutableCopy];
[updatedThemes removeObjectForKey:@"dark"];
context.message.themes = updatedThemes;
break;
}
case BRZInAppMessageRawTypeModal:
case BRZInAppMessageRawTypeFull:
{
NSMutableDictionary *updatedThemes = [context.message.themes mutableCopy];
[updatedThemes removeObjectForKey:@"dark"];
context.message.themes = updatedThemes;
NSMutableArray *updatedButtons = [NSMutableArray arrayWithCapacity:context.message.buttons.count];
for (BRZInAppMessageRawButton *button in context.message.buttons) {
BRZInAppMessageRawButtonTheme *lightTheme = BRZInAppMessageRawButtonTheme.defaultLight;
BRZInAppMessageRawButton *newButton = [button mutableCopy];
newButton.textColor = lightTheme.textColor;
newButton.backgroundColor = lightTheme.backgroundColor;
newButton.borderColor = lightTheme.borderColor;
[updatedButtons addObject:newButton];
}
context.message.buttons = updatedButtons;
break;
}
default:
break;
}
}
Customizing button clicks
To access in-app message button information or override the click behavior, implement BrazeInAppMessageUIDelegate.inAppMessage(_:shouldProcess:)
. Return true
to allow Braze to process the click action, or return false
to override the behavior.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
func inAppMessage(
_ ui: BrazeInAppMessageUI, shouldProcess clickAction: Braze.InAppMessage.ClickAction,
buttonId: String?, message: Braze.InAppMessage, view: InAppMessageView
) -> Bool {
guard let buttonId,
let idInt = Int(buttonId)
else { return true }
var button: BrazeKit.Braze.InAppMessage.Button? = nil
switch message {
case .modal(let modal):
button = modal.buttons[idInt]
case .modalImage(let modalImage):
button = modalImage.buttons[idInt]
case .full(let full):
button = full.buttons[idInt]
case .fullImage(let fullImage):
button = fullImage.buttons[idInt]
default:
break
}
print(button?.id)
print(button?.text)
print(button?.clickAction)
return true
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (BOOL)inAppMessage:(BrazeInAppMessageUI *)ui
shouldProcess:(enum BRZInAppMessageRawClickAction)clickAction
url:(NSURL *)uri
buttonId:(NSString *)buttonId
message:(BRZInAppMessageRaw *)message
view:(UIView *)view {
NSInteger buttonInt = [buttonId integerValue];
if (message.type == BRZInAppMessageRawTypeFull || message.type == BRZInAppMessageRawTypeModal) {
BRZInAppMessageRawButton *button = message.buttons[buttonInt];
NSLog(@"%ld", (long)button.identifier);
NSLog(@"%@", button.text);
NSLog(@"%ld", (long)button.clickAction);
}
return YES;
}
Hiding the status bar during display
For Full
, FullImage
and HTML
in-app messages, the SDK will hide the status bar by default. For other types of in-app messages, the status bar is left untouched. To configure this behavior, use the inAppMessage(_:prepareWith:)
delegate method to set the statusBarHideBehavior
property on the PresentationContext
. This field takes one of the following values:
Status Bar Hide Behavior | Description |
---|---|
.auto |
The message view decides the status bar hidden state. |
.hidden |
Always hide the status bar. |
.visible |
Always display the status bar. |
Customizing display timing
You can control if an available in-app message will display during certain points of your user experience. If there are situations where you would not want the in-app message to appear, such as during a fullscreen game or on a loading screen, you can delay or discard pending in-app message messages. To control the timing of in-app message, use the inAppMessage(_:displayChoiceForMessage:)
delegate method to set the BrazeInAppMessageUI.DisplayChoice
property.
1
2
3
4
func inAppMessage(
_ ui: BrazeInAppMessageUI,
displayChoiceForMessage message: Braze.InAppMessage
) -> BrazeInAppMessageUI.DisplayChoice
1
- (enum BRZInAppMessageUIDisplayChoice)inAppMessage:(BrazeInAppMessageUI *)ui displayChoiceForMessage:(BRZInAppMessageRaw *)message
Configure BrazeInAppMessageUI.DisplayChoice
to return one of the following values:
Display Choice | Behavior |
---|---|
.now |
The message will be displayed immediately. This is the default value. |
.reenqueue |
The message will be not be displayed and will be placed back on the top of the stack. |
.later |
The message will be not be displayed and will be placed back on the top of the stack. (Deprecated, please use .reenqueue ) |
.discard |
The message will be discarded and will not be displayed. |
Implementation samples
See InAppMessageUI
in our Examples folder for a sample in Swift and Objective-C