美文网首页
谈谈swift版的 WKWebView 与js/ts 交互

谈谈swift版的 WKWebView 与js/ts 交互

作者: Jason_风筝 | 来源:发表于2018-11-12 16:53 被阅读0次

如果我们想实现js 调用原生的方法, 或原生调用js, 相信有不少办法. 这一篇文章我们来探讨下 swift 下的webkit是如何实现交互的.
这里主要用TypeScript,它是 JavaScript 的超集,其实差不多, 如果能够看懂ts, 相信也能写出js.

  • ts 部分的code 也可以适应android , 但android 还需要在原生的code 中写相应的实现, 我们这里主要讨论iOS.android 部分只要加上 .java 部分的代码就好了.
  • 我们先创建一个baseService, 所有需要新增加的Service,只要继承它, 再调用 'callNative' 就可以.
  • 你可以这样使用ApplepayService, 继承自baseService.
ApplepayService().makePaymentRequest(params: any, callback)

下面我们来看代码.

export class BaseService {
    // 请继承的类重写此方法, 提供方法名, 注意这里的名字需要与下面swift 中写的类方法名一致
    protected getServiceName() {
        return null;
    }

    // 判断 service 是否有效,如果用的是 WKWebView , 那 window['webkit']是肯定有值的, 然后看看messageHandler是否设置了.
    public isAvailable() {
        var ios = window['webkit'];
        var serviceName = this.getServiceName();
    //  如果用的WKWebView
        if (typeof ios != 'undefined') {
            if (ios.messageHandlers[serviceName]) {
                return true;
            }
        } else {
            // 一般给android 用
            if (typeof window[serviceName] != 'undefined') return true;
        }
        return false;
    }

    // 调用方法, 
    /**
     * 
     * @param method : 方法名
     * @param params : 参数: {} 类型
     * @param callback : 回调,执行完方法,调用callback
     */
    protected callNative(method: string, params: any, callback = null) {
        var serviceName = this.getServiceName();
        var cbName = null;
        if (callback) {
            cbName = serviceName + method + "Cb";
            // 一般给android 用
            window[cbName] = function (str) {
                callback(JSON.parse(str));
                window[cbName] = null;
            };
        }
        if (cbName) {
            params['_callback'] = cbName;
        }
        params['_method'] = method;
        var webkit = window['webkit'];
        if (webkit) {
            webkit.messageHandlers[serviceName].postMessage(params);
        } else { // 一般给android 用
            console.log("calling android");
            var input = JSON.stringify(params);
            window[serviceName].postMessage(input);
            console.log("done");
        }
    }

}

我们写一个ApplepayService , 继承BaseService,请看使用.

export class ApplepayService extends BaseService {
    protected getServiceName() {
        return "ApplepayService";
    }

    public makePaymentRequest(params: any, callback) {
        if (!this.isAvailable()) return;
        this.callNative('makePaymentRequest', params, callback);
    }
    /**
     * 
     * @param params : 
     * { paymentAuthorizationStatus: "success" / "failure" / "invalid-billing-address" / "invalid-shipping-address" / "invalid-shipping-contact" / "require-pin" / "incorrect-pin" / "locked-pin"  }
     * 
     * @param callback ,optional
     */
    public completeLastTransaction(params: any, callback?) {
        if (!this.isAvailable()) return;
        this.callNative('completeLastTransaction', params, callback);
    }
}

use(使用)

    function applepayCallback = (result) => {
        var applepayReulst = JSON.stringify(result);
        console.log("applepayReulst:" + result, applepayReulst);
    }
    var applepayService = new ApplepayService()
    applepayService.makePaymentRequest(params, this.applepayCallback);

swift 部分的code

import UIKit
import WebKit
class TestWebkitControllerViewController: UIViewController {
    var webView: WKWebView! //一定是 WKWebView
    override func viewDidLoad() {
        super.viewDidLoad()

        let webConfiguration = WKWebViewConfiguration()
        let userContentController = WKUserContentController()
        // 重要一步
        // scriptMessageHandler 谁处理这个, 要实现协议, 为防止循环引用另创建一个类
        // name,消息处理程序的名称,就是ts中的serviceName
        // add(_ scriptMessageHandler: WKScriptMessageHandler, name: String)
        let serviceName = "ApplepayService"
        userContentController.add(WKScriptMsgHandler(scriptDelegate: self), name: serviceName)
        webConfiguration.userContentController = userContentController
    }

}

extension TestWebkitControllerViewController: WKScriptMessageHandler {
    // 这里方法, 就是接收到ts 发来的消息时调用. 这个协议也只有这个方法
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        let serviceName = message.name
        /// 然后 serviceName , 创建你的 service 类, 再调用相应的方法
        if(serviceName != nil) {
            
            // body就是ts 传过来的参数
            let body = message.body as! NSDictionary;
            // 取出参数 _method / _callback , 是我们ts 中定义的key name .
            let method = body["_method"] as! String;
            let callback = body["_callback"] as? String;
        } else {
            print("service not registered", serviceName)
        }
    }
    
}

class WKScriptMsgHandler: NSObject, WKScriptMessageHandler {

    weak var scriptDelegate: WKScriptMessageHandler?

    init(scriptDelegate: WKScriptMessageHandler) {
        self.scriptDelegate = scriptDelegate
    }
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        if let delegate = scriptDelegate {
            delegate.userContentController(userContentController, didReceive: message)
        }
    }


}

  • 到此,js 调用原生就完成了.

原生调用js

  • 其实原生想调用js,只要js在window上添加方法,原生就可以利用 webView.evaluateJavaScript(方法名())调用.然后再传递参数
public func callback(callback: String, params: Any) {
       var str: String = "null";
       do {
           if JSONSerialization.isValidJSONObject(params) {
               let data = try JSONSerialization.data(withJSONObject: params)
               if let s = String(data: data, encoding: String.Encoding.utf8) {
                   str = s;
               }
           }
       } catch {
           print("json serialization error")
       }

       let scriptSource = callback + "('" + str + "')"
       self.webView.evaluateJavaScript(scriptSource)
}
  • ts 提供方法
applepayCallback = (result) => {
        var applepayReulst = JSON.stringify(result);
        console.log("applepayReulst:" + result, applepayReulst);
};
window["applepayCallback"] = this.applepayCallback;

相关文章

网友评论

      本文标题:谈谈swift版的 WKWebView 与js/ts 交互

      本文链接:https://www.haomeiwen.com/subject/biqcfqtx.html