Skip to content

Latest commit

 

History

History
260 lines (205 loc) · 9.82 KB

File metadata and controls

260 lines (205 loc) · 9.82 KB

sample swift wkwebview javascript bridge and scheme

License Swift 4

I have tried to sample the method of javascirpt bridge and url scheme with wkwebview.

★ Web (Front) → Native
In the past, when linking with the UIWebView, we had to define a schema in the URL and parse it using scheme information.
In WKWebView, there is an additional way to do logic processing with javascript bridge.

★ Native → Web (Front)
The native-to-web forwarding / processing method is exactly the same as calling the JavaScript function ("evaluatejavascript") as in the existing UIWebView.

Info

Result image(GIF)

1. javascirpt bridge

There is a distinction between using bridge connections and natively javascript calling back from the web using the scheme of the defined url.

  • HTML file for testing: sampleBridge.html
    <html lang="ko">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <script type="text/javascript">
       // alert(1)
    
        function callNative01() {
           try {
               webkit.messageHandlers.callbackHandler.postMessage("testValue");
           } catch(error) {
               alert(error)
           }
        }
    
        function callNative02() {
            try {
                webkit.messageHandlers.callbackHandler.postMessage({key01:'testValue01', key02:'testValue02'});
            } catch(error) {
                alert(error)
            }
        }
    
        function test01() {
           alert('test01');
        }
    
        function testCallBack(message) {
            alert(message);
        }
    </script>
    <body>
        <h1> <a href="javascript:test01();">Test Click</a> </h1> <br /><br />
        <h1> <a href="javascript:callNative01();">CallNative 01 Click</a> </h1> <br /><br />
        <h1> <a href="javascript:callNative02();">CallNative 02 Click</a> </h1> <br /><br />
    <h1> This is a sample file created to test a simple "WebView".<br /></h1>
    <h1> Modify this file to test the "WebView" content.<br /></h1>
    </body>
    </html>
  • swift code : WebViewBridgeViewController.swift ← Click the details to see the code.
    .. (skip).. 
    
    private struct Constants {
        static let callBackHandlerKey = "callbackHandler"
    }
    
    .. (skip).. 
    
    func setupView() {
        // Bridge Setting
        let userController: WKUserContentController = WKUserContentController()
        let userScript: WKUserScript = WKUserScript(source: "test01()", injectionTime: WKUserScriptInjectionTime.atDocumentEnd, forMainFrameOnly: true)
        userController.addUserScript(userScript)
        
        userController.add(self, name: Constants.callBackHandlerKey)
        let configuration = WKWebViewConfiguration()
        configuration.userContentController = userController
        
        // Default WebView Setting
        self.webView = WKWebView(frame:self.safeAreaContainerView.bounds, configuration: configuration)
        self.webView.navigationDelegate = self
        self.webView.uiDelegate = self
        self.webView.translatesAutoresizingMaskIntoConstraints = false
        
        self.safeAreaContainerView.addSubview(self.webView)
        
        // WKWebView Layout Setting
        // Constraints like "UIWebView" are set.
        // This is a sample. If you are developing, use a library called "SnapKit".
        // https://github.com/SnapKit/SnapKit
        let margins = safeAreaContainerView.layoutMarginsGuide
        webView.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true
        webView.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true
        webView.topAnchor.constraint(equalTo: margins.topAnchor).isActive = true
        webView.bottomAnchor.constraint(equalTo: margins.bottomAnchor).isActive = true
    }
    
    .. (skip) ..
    
    // MARK: - WKScriptMessageHandler
    extension WebViewBridgeViewController : WKScriptMessageHandler {
        //MARK:- HERE!!!
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
          print("message.name:\(message.name)")
          if message.name == Constants.callBackHandlerKey {
              print("message.body:\(message.body)")
    
              // Just TEST CallBack
              if let dictionary = message.body as? Dictionary<String, AnyObject> {
                  print(dictionary)
                  var popupPrintString = ""
                  dictionary.forEach { (key, value) in
                      popupPrintString += "\(key):\(value) "
                  }
                  // call back!
                  self.webView.stringByEvaluatingJavaScript(script: "javascript:testCallBack('\(popupPrintString)');")
              } else {
                  // call back!
                  self.webView.stringByEvaluatingJavaScript(script: "javascript:testCallBack('\(String(describing:message.body))');")
              }
    
              // popup!
    //            self.webView.stringByEvaluatingJavaScript(script: "javascript:test01();")
    
          }
      }
    }
    
    .. (skip) ..

2. URL Scheme

  • HTML file for testing : sampleScheme.html

    <html lang="ko">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    
    <script type="text/javascript">
        //alert(2)
    
       function callNative01() {
           window.location = "nativeScheme://testHost";
       }
    
        function test02() {
            alert('test02');
        }
    
        function testCallBack(message) {
            alert(message);
        }
    </script>
    <body>
    <h1> <a href="javascript:test02();">Test Click</a> </h1> <br /><br />
    
    <h1> <a href="javascript:callNative01();">CallNative 01 Click</a> </h1> <br /><br />
    
    
    <h1> This is a sample file created to test a simple "WebView".<br /></h1>
    <h1> Modify this file to test the "WebView" content.<br /></h1>
    </body>
    </html>
  • swift code : WebViewSchemesViewController.swift ← Click the details to see the code.

    .. (skip) ..
    
    private struct Constants {
        static let schemeKey = "nativeScheme"
    }
    
    .. (skip) ..
    
    func setupView() {
        let preferences = WKPreferences()
        preferences.javaScriptEnabled = true // default YES.
        preferences.javaScriptCanOpenWindowsAutomatically = true
        
        let configuration = WKWebViewConfiguration()
        configuration.preferences = preferences
        
        self.webView = WKWebView(frame: self.view.bounds, configuration: configuration)
        self.webView.navigationDelegate = self
        self.webView.uiDelegate = self
        self.webView.translatesAutoresizingMaskIntoConstraints = false
        self.safeAreaContainerView.addSubview(self.webView)
        
        // WKWebView Layout Setting
        // Constraints like "UIWebView" are set.
        // This is a sample. If you are developing, use a library called "SnapKit".
        // https://github.com/SnapKit/SnapKit
        let margins = safeAreaContainerView.layoutMarginsGuide
        webView.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true
        webView.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true
        webView.topAnchor.constraint(equalTo: margins.topAnchor).isActive = true
        webView.bottomAnchor.constraint(equalTo: margins.bottomAnchor).isActive = true
    }
    
    .. (skip) ..
    
    // MARK: - WKNavigationDelegate
    extension WebViewSchemesViewController : WKNavigationDelegate {
    
    .. (skip) ..
    
    //MARK:- HERE!!!
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        print("\(#function)")
    
        // Check whether WebView Native is linked
        if let url = navigationAction.request.url,
            let urlScheme = url.scheme,
            let urlHost = url.host,
            urlScheme.uppercased() == Constants.schemeKey.uppercased() {
            print("url:\(url)")
            print("urlScheme:\(urlScheme)")
            print("urlHost:\(urlHost)")
    
            decisionHandler(.cancel)
    
            // call back!
            self.webView.stringByEvaluatingJavaScript(script: "javascript:testCallBack('\(urlHost)');")
    
            // popup!
    //            self.webView.stringByEvaluatingJavaScript(script: "javascript:test02();")
            return
        }
        decisionHandler(.allow)
    }
    
    .. (skip) ..

3. Common

  • ViewController.swift
    .. (skip) ..
    
    extension WKWebView {
        func stringByEvaluatingJavaScript(script: String) {
            self.evaluateJavaScript(script) { (result, error) in
                
            }
        }
    }