In-App Messaging Implementation Guide

This optional and advanced implementation guide covers in-app message code considerations, three custom use cases built by our team, and accompanying code snippets. Visit our Braze Demo repository here! Please note that this implementation guide is centered around a Swift implementation, but Objective-C snippets are provided for those interested. Looking for HTML implementations? Take a look at our HTML template repository!

Code Considerations

The following guide offers an optional custom developer integration to use in addition to out-of-the-box in-app messages. Custom view controllers are included below with each use case, offering examples to extend functionality and natively customize the look and feel of your in-app messages.

ABKInAppMessage Subclasses

The code snippet below is a UI delegate method from the Braze SDK that determines what subclass view you want to populate your in-app message with. We cover a basic implementation in this guide and show how the full, slide up and modal subclasses can be implemented in captivating ways. Please note that if you want to set up your custom view controller, you must set up all other in-app message subclasses. Once you have a solid understanding of the concepts behind subclassing, check out our use cases below to get started implementing in-app messaging subclasses.

ABKInAppMessage Subclasses

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
extension AppboyManager: ABKInAppMessageUIDelegate {
  func inAppMessageViewControllerWith(_ inAppMessage: ABKInAppMessage) -> ABKInAppMessageViewController {
    switch inAppMessage {
    case is ABKInAppMessageSlideup:
      return slideupViewController(inAppMessage: inAppMessage) //Custom Method
    case is ABKInAppMessageModal: 
      return modalViewController(inAppMessage: inAppMessage) //Custom Method
    case is ABKInAppMessageFull:
      return fullViewController(inAppMessage: inAppMessage) //Custom Method
    case is ABKInAppMessageHTML:
      return ABKInAppMessageHTMLViewController(inAppMessage: inAppMessage)
    default:
      return ABKInAppMessageViewController(inAppMessage: inAppMessage)
    }
  }
}

ABKInAppMessage Subclasses

1
2
3
4
5
6
7
8
9
10
11
12
13
- (ABKInAppMessageViewController *)inAppMessageViewControllerWithInAppMessage:(ABKInAppMessage *)inAppMessage {
  if ([inAppMessage isKindOfClass:[ABKInAppMessageSlideup class]]) {
    return [self slideupViewControllerWithInAppMessage:inAppMessage]; //Custom Method
  } else if ([inAppMessage isKindOfClass:[ABKInAppMessageModal class]]) {
    return [self modalViewControllerWithInAppMessage:inAppMessage]; //Custom Method
  } else if ([inAppMessage isKindOfClass:[ABKInAppMessageFull class]]) {
    return [self fullViewControllerWithInAppMessage:inAppMessage]; //Custom Method
  } else if ([inAppMessage isKindOfClass:[ABKInAppMessageHTML class]]) {
    return [[ABKInAppMessageHTMLViewController alloc] initWithInAppMessage:inAppMessage];
  } else {
    return [[ABKInAppMessageViewController alloc] initWithInAppMessage:inAppMessage];
  }
}

Sample Use Cases

There are three sample customer use cases provided. Each sample has video walkthroughs, code snippets, and a look into how in-app messages may look and be used in the Braze dashboard:

Custom Slideup In-App Message

While building out your slide-up in-app message, you may notice you aren’t able to modify the placement of the message. While this option is not explicitly offered out-of-the-box, modification like this is made possible by subclassing the ABKInAppMessageSlideupViewController and overriding the slideConstraint value with your own custom constraint value. Visit the SlideFromBottomViewController to get started.

Adding Additional Behavior to our Default UI

Override and Set Custom Constraint
Override beforeMoveInAppMessageViewOnScreen() and set your own custom constraint value to suit your needs. The original value is set in the superclass.

1
2
3
4
override func beforeMoveInAppMessageViewOnScreen() {
  super.beforeMoveInAppMessageViewOnScreen()
  setOffset()
}

Version 3.34.0 or earlier
1
2
3
override func beforeMoveInAppMessageViewOnScreen() {
  setSlideConstraint()
}

Override and Set Custom Constraint
Override beforeMoveInAppMessageViewOnScreen() and set your own custom constraint value to suit your needs. The original value is set in the superclass.

1
2
3
4
- (void)beforeMoveInAppMessageViewOnScreen {
  [super beforeMoveInAppMessageViewOnScreen];
  [self setOffset];
}

Version 3.34.0 or earlier
1
2
3
- (void)beforeMoveInAppMessageViewOnScreen {
  [self setSlideConstraint:self.slideConstraint];
}

Update offset Variable
Update the offset variable and set your own offset to suit your needs.

1
2
3
func setSlideConstraint() {
  offset = 0
}
1
2
3
4
5
6
7
8
override var offset: CGFloat {
  get {
    return super.offset
  }
  set {
    super.offset = newValue + adjustedOffset
  }
}

Version 3.34.0 or earlier

Update slideConstraint Variable
The slideConstraint public variable comes from the superclass ABKInAppMessageSlideupViewController.

1
2
3
func setSlideConstraint() {
    slideConstraint?.constant = bottomSpacing
}
1
2
3
private var bottomSpacing: CGFloat {
    return AppboyManager.shared.activeApplicationViewController.topMostViewController().view.safeAreaInsets.bottom
}

Visit the Braze Demo repository for the topMostViewController() function referenced above.

Update offset Variable
Update the offset variable and set your own offset to suit your needs.

1
2
3
- (void)setOffset {
  self.offset = 0;
}
1
2
3
4
5
6
7
- (CGFloat)offset {
  return [super offset];
}
 
- (void)setOffset:(CGFloat)offset {
  [super setOffset:offset + [self adjustedOffset]];
}

Version 3.34.0 or earlier

Update slideConstraint Variable
The slideConstraint public variable comes from the superclass ABKInAppMessageSlideupViewController.

1
2
3
- (void)self.setSlideConstraint:(NSLayoutConstraint *)slideConstraint {
  slideConstraint.constant = bottomSpacing;
}
1
2
3
- (CGFloat)bottomSpacing {
  return [AppboyManager shared].activeApplicationViewController.topMostViewController.view.safeAreaInsets.bottom;
}

Adjust Constraint for Device Orientation
Adjust the respective value in viewWillTransition() because the subclass assumes responsibility for keeping the constraint synced during layout changes.

Custom Modal In-App Message

An ABKInAppMessageModalViewController can be subclassed to leverage a UIPickerView offering engaging ways to collect valuable user attributes. The example below shows how you can use Connected Content to capture custom attributes from a dynamic list of items. Visit the ModalPickerViewController to get started.

Using view_type for UI Display Behavior
The ABKInAppMessage object has an extras dictionary that we can query to find the view_type key (if any) and display the correct type of view. It’s important to note that in-app messages are configured on a per-message basis, so custom and out-of-the-box modal views can work harmoniously.

1
2
3
4
5
6
7
8
func modalViewController(inAppMessage: ABKInAppMessage) -> ABKInAppMessageModalViewController {
  switch inAppMessage.extras?[InAppMessageKey.viewType.rawValue] as? String {
  case InAppMessageViewType.picker.rawValue:
    return ModalPickerViewController(inAppMessage: inAppMessage)
  default:
    return ABKInAppMessageModalViewController(inAppMessage: inAppMessage)
  }
}

Using view_type for UI Display Behavior
The ABKInAppMessage object has an extras dictionary that we can query to find the view_type key (if any) and display the correct type of view. It’s important to note that in-app messages are configured on a per-message basis, so custom and out-of-the-box modal views can work harmoniously.

1
2
3
4
5
6
7
8
9
10
11
- (ABKInAppMessageModalViewController *)modalViewControllerWithInAppMessage:(ABKInAppMessage *)inAppMessage {
  InAppMessageData *inAppMessageData = [[InAppMessageData alloc] init];
  NSString *key = [inAppMessageData rawValueForInAppMessageKey:InAppMessageKeyViewType];
  NSString *viewType = [inAppMessageData rawValueForInAppMessageViewType:InAppMessageViewTypePicker];
   
  if ([inAppMessage.extras objectForKey:key] && [inAppMessage.extras[key] isEqualToString:viewType]) {
    return [[ModalViewController alloc] initWithInAppMessage:inAppMessage];
  } else {
    return [[ABKInAppMessageModalViewController alloc] initWithInAppMessage:inAppMessage];
  }
}

Override and Provide Custom View
Override loadView() and set your own custom view to suit your needs.

1
2
3
4
5
6
7
override var nibname: String{
  return "ModalPickerViewController"
}

override func loadView() {
  Bundle.main.loadNibNamed(nibName, owner: self, options: nil)
}

Override and Provide Custom View
Override loadView() and set your own custom view to suit your needs.

1
2
3
4
- (void)loadView {
  NSString *nibName = @"ModalPickerViewController";
  [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil];
}

Format Variables for a Dynamic List
Before reloading the UIPickerView components, the inAppMessage message variable is output as a String. This message must be formatted as an array of items to be displayed correctly. As an example, this can be achieved using components(separatedBy: ", ").

1
2
3
4
5
6
override func viewDidLoad() {
  super.viewDidLoad()
 
  items = inAppMessage.message.separatedByCommaSpaceValue
  pickerView.reloadAllComponents()
}

Format Variables for PickerView
Before reloading the UIPickerView components, the inAppMessage message variable is output as a String. This message must be formatted as an array of items to be displayed correctly. As an example, this can be achieved using componentsSeparatedByString.

1
2
3
4
5
6
- (void)viewDidLoad {
  [super viewDidLoad];
   
  self.items = [[NSArray alloc] initWithArray:[self.inAppMessage.message componentsSeparatedByString:@", "]];
  [self.pickerView reloadAllComponents];
}

Assign Custom Attribute
Using the subclass, after a user presses submit, pass the attribute with its corresponding selected value to Braze.

1
2
3
4
5
@IBAction func primaryButtonTapped(_ sender: Any) {
  guard let item = selectedItem, !item.isEmpty, let attributeKey = inAppMessage.extras?[InAppMessageKey.attributeKey.rawValue] as? String else { return }
     
  AppboyManager.shared.setCustomAttributeWithKey(attributeKey, andStringValue: item)
}

Assign Custom Attribute
Using the subclass, after a user presses submit, pass the attribute with its corresponding selected value to Braze.

1
2
3
4
5
6
7
8
- (IBAction)primaryButtonTapped:(id)sender {
  InAppMessageData *inAppMessageData = [[InAppMessageData alloc] init];
  NSString *key = [inAppMessageData rawValueForInAppMessageKey:InAppMessageKeyAttributeKey];
   
  if (self.selectedItem.length > 0 && [self.inAppMessage.extras objectForKey:key]) {
    [[AppboyManager shared] setCustomAttributeWithKey:self.inAppMessage.extras[key] andStringValue:self.selectedItem];
  }
}

Custom Full In-App Message

Use custom full in-app messages to create interactive, user-friendly prompts to collect valuable customer data. The example below shows an implementation of the custom full in-app message reimagined as an interactive push primer with notification preferences. Visit the FullListViewController to get started.

Intercepting In-App Message Touches

Touches Intercepting in-app message touches is crucial in making the custom full in-app message buttons function correctly. By default, the ABKInAppMessageImmersive adds a tap gesture recognizer onto the message so users are able to dismiss messages without buttons. Through the use of adding a UISwitch or button to the UITableViewCell view hierarchy, the touches now get handled by our custom view. As of iOS 6, buttons and other controls have precedence when working with gesture recognizers, making our custom full in-app message work as it should.

WAS THIS PAGE HELPFUL?
New Stuff!