Sharing Web Data with iOS Using WKWebView

I recently helped develop a native iOS app for a client that sells software to many different educational organizations. We wrote the app in Swift, and it interacts with our client’s pre-existing web API.

One challenge we faced was that many of our client’s customers require single-account, multiple-login (SAML) support through their own web portals. To support SAML, we needed an easy way to pass a user’s API credentials from a web page to our iOS application. In this post, I’ll show how this can be accomplished using WKWebView.

The Problem

The high-level overview of the issue we faced:

  • Our client provides software to many organizations, and each has users that must log in.
  • To log in, a user must identify his or her organization.
  • After identifying the organization, the user can log in using our client’s API or, in some cases, an external web site hosted by the organization.

With SAML, users are sent to the organization’s web page to log in, then redirected back to a landing page that our client controlls. Once that redirect occurs, we have the login credentials (for instance, a user token required by our client’s API). The question is: How do we pass that token to the native iOS app?

WKWebView

In iOS 8, Apple provided WKWebView as part of WebKit, a newer way of embedding web views in a native app. (Among other features, WKWebView boasts better performance than the older UIWebView.) In the following code samples, I will show how a developer can pass data in the form of a JavaScript object from a web page to the native iOS app.

First, create a simple UIViewController in Interface Builder and give it a custom class. I chose to name mine SamlLoginViewController. In the view controller’s loadView method, we create the WKWebView and set up the communication channel between the web and our app as follows:

See the code in the full post.

Before diving into loadView, note that there are two instance variables declared at the top: webView and userContentController. Further, we are going to add the WKScriptMessageHandler protocol to our class. Our class will handle messages passed from JavaScript on the web page.

To create a WKWebView, we first construct a WKWebViewConfiguration object and set its userContentController value to the WKUserContentController on our class. The WKWebView can then be constructed like this:

See the code in the full post.

After creating the WKWebView, we set up the message handler:

See the code in the full post.

The side-effect of addScriptMessageHandler is that it will create an object that will be added to window.webkit.messageHandlers for any webpage loaded in the WKWebView. In this case, we name the handler “userLogin” so our JavaScript code will be able to access window.webkit.messageHandlers.userLogin.

Next, we need to create the delegate method to receive messages in our view controller:

See the code in the full post.

The JavaScript Object

The last piece of the puzzle is the JavaScript needed to send the message. The following code must be run on the page loaded into the WKWebView:

See the code in the full post.

This code creates a simple HTML button and adds an even listener to call the messageHandler that is automatically set up by WKWebView. You can verify that window.webkit.messageHandlers.userLogin only exists in the context of your iOS app’s view. Just visit the URL in a browser and it will be undefined. When postMessage is called, the iOS app receives the sent JavaScript object. It’s that easy!


Originally published at spin.atomicobject.com on September 1, 2016.

Like what you read? Give Atomic Object a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.