Skip to content

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 your inAppMessagePresenter.
  • 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.

Supported orientations in Xcode.

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:

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:

Implementation samples

See InAppMessageUI in our Examples folder for a sample in Swift and Objective-C

HOW HELPFUL WAS THIS PAGE?
New Stuff!