Pass Data Between WebView and App February 4, 2017

I'll be sharing a simple method to pass data between an WKWebView and an iOS App. I came across this while building a search form in a WKWebView with a set of dropdown fields that would build-out a URL to hit a search API, and then pass that URL back to the App. In xCode, create a ViewController with an WKWebView. The user script is how your native application talks to JavaScript. The script messages is how JavaScript communicates back to your native app.

            
      import UIKit
      import WebKit

      class ViewController: UIViewController, WKScriptMessageHandler {
          
          @IBOutlet var containerView : UIView! = nil
          var webView: WKWebView?
          
          override func loadView() {
              super.loadView()
              
              let contentController = WKUserContentController();
              let userScript = WKUserScript(
                  source: "redHeader()",
                  injectionTime: WKUserScriptInjectionTime.atDocumentEnd,
                  forMainFrameOnly: true
              )
              contentController.addUserScript(userScript)
              contentController.add(
                  self,
                  name: "callbackHandler"
              )
              
              let config = WKWebViewConfiguration()
              config.userContentController = contentController
              
              self.webView = WKWebView(
                  frame: self.view.bounds,
                  configuration: config
              )
              self.view = self.webView!
          }
          
          override func viewDidLoad() {
              super.viewDidLoad()
              
              let url = NSURL(string:"http://127.0.0.1:8080/")
              let req = NSURLRequest(url:url as! URL)
              self.webView!.load(req as URLRequest)
          }
          
          func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
              if(message.name == "callbackHandler") {
                  print("JavaScript is sending a message \(message.body)")
              }
          }
          
          override func didReceiveMemoryWarning() {
              super.didReceiveMemoryWarning()
          }
      }
      
          

Create a local WebServer with Node.js with a basic HTML page 'index.html'. Include the main.js script in the header with script type="text/javascript" src="main.js". Create a file main.js

            
      function callNativeApp () {
        try {
            webkit.messageHandlers.callbackHandler.postMessage("Hi, I'm the internet.");
        } catch(err) {
            console.log('The native context does not exist yet');
        }
      }

      setTimeout(function () {
          callNativeApp();
      }, 5000);

      function redHeader() {
          document.querySelector('h1').style.color = "red";
      }
      
          

The App wait 5 seconds and then pass back "Hi, I'm the internet." that hits this function.

            
       func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
              if(message.name == "callbackHandler") {
                  print("JavaScript is sending a message \(message.body)")
              }
          }
        
          

That's it! Have fun and #CompileSwift.