如果我们想实现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;
网友评论