Displaying a Message Center Message in a Custom Webview

This guide shows the minimum integration necessary to display a Message Center message in a custom webview.

While the Airship SDK provides built-in Message Center UI, sometimes it can be useful to create a custom implementation that bypasses the default implementation's view hierarchy. Message Center messages are just HTML, and so they can be displayed in any webview. However, there are a few integration steps needed to ensure that authorization and the Native Bridge function properly.

Authentication and Loading

Message Center messages are fetched with basic authentication using the UAUser credentials in base64 encoding. This class persists a unique username and password on the iOS Keychain, and provides easy access to the information at runtime without needing to deal with the Keychain directly.

The example below shows how to fetch the credentials, set auth on the request, and load a message into the webview. This code assumes a custom view controller with an embedded WKWebView, as well as a UAInboxMessage ready to be loaded.

NSMutableURLRequest *requestObj = [NSMutableURLRequest requestWithURL:self.message.messageBodyURL];

UA_WEAKIFY(self)
[[UAirship inboxUser] getUserData:^(UAUserData *userData) {
   UA_STRONGIFY(self)
   // set the auth
   NSString *auth = [UAUtils userAuthHeaderString:userData];
   [requestObj setValue:auth forHTTPHeaderField:@"Authorization"];

   // load the request
   [self.webView loadRequest:requestObj];
} queue:dispatch_get_main_queue()];
let requestObj = NSMutableURLRequest(url:self.message.messageURL)

UAirship.inboxUser()?.getData({ data in
   // set the auth
   let auth = UAUtils.userAuthHeaderString(data)
   requestObj.setValue(auth, forHTTPHeaderField:"Authorization")

   // load the request
   self.webView.load(requestObj)
}, queue: DispatchQueue.main)

Setting up the Native Bridge

The Airship Native bridge works by intercepting all links with the uairship:// scheme and translating specially URL-encoded paths into native commands and arguments. In order to do this in a custom webview, the view controller containing the webview (or whichever class acts as the WKNavigationDelegate) must delegate navigation handling to the Native Bridge. To continue to receive these events, the original delegate can sign up as a "forward delegate", by implementing the UAWKWebViewDelegate protocol, which extends WKNavigationDelegate. The example code below shows how to do this, and assumes both native bridge property in the view controller, and that the view controller implements UAWKWebViewDelegate

- (void)viewDidLoad {
   [super viewDidLoad];

   // allow native bridge to intercept links
   self.nativeBridge = [[UAWKWebViewNativeBridge alloc] init];
   self.webView.navigationDelegate = self.nativeBridge;

   // forward navigation events back to self
   self.nativeBridge.forwardDelegate = self;

   ...
}
override func viewDidLoad() {
   super.viewDidLoad()

   // allow native bridge to intercept links
   self.nativeBridge = UAWKWebViewNativeBridge()
   self.webView.navigationDelegate = self.nativeBridge

   // forward navigation events back to self
   self.nativeBridge.forwardDelegate = self
}

Enabling the Close Command

Among other commands, the Native Bridge also exposes a UAirship.close() command to the JavaScript layer, which makes it possible for elements or JavaScript routines in the message to close the containing message view. This is optional functionality, but if you would like to add this capability to your app, you will need to implement an additional UAWKWebViewDelegate method in the view controller containing your webview.

- (void)closeWindowAnimated:(BOOL)animated {
   // dismiss the webview here
}
override func closeWindow(animated: Bool) {
   // dismiss the webview here
}