JS Bridge 通信原理,吃透这份前端高级工程师面试497题解析

iOS UIWebView

iOS 侧代码:

// 获取 JS 上下文

JSContext *context = [webview valueForKeyPath:@“documentView.webView.mainFrame.javaScriptContext”];

// 注入 Block

context[@“callHandler”] = ^(JSValue * data) {

// 处理调用方法和参数

// 调用 Native 功能

// 回调 JS Callback

}

JS 代码:

window.callHandler(JSON.stringify({

type: “scan”,

data: “”,

callback: function(data) {

}

}));

这种方式的牛逼之处在于,JS 调用是同步的,可以立马拿到返回值。

我们也不再需要像拦截方式一样,每次传值都要把对象做 JSON.stringify,可以直接传 JSON 过去,也支持直接传一个函数过去。

iOS WKWebView

WKWebView 里面通过 addScriptMessageHandler 来注入对象到 JS 上下文,可以在 WebView 销毁的时候调用 removeScriptMessageHandler 来销毁这个对象。

前端调用注入的原生方法之后,可以通过 didReceiveScriptMessage 来接收前端传过来的参数。

WKWebView *wkWebView = [[WKWebView alloc] init];

WKWebViewConfiguration *configuration = wkWebView.configuration;

WKUserContentController *userCC = configuration.userContentController;

// 注入对象

[userCC addScriptMessageHandler:self name:@“nativeObj”];

// 清除对象

[userCC removeScriptMessageHandler:self name:@“nativeObj”];

// 客户端处理前端调用

- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message

{

// 获取前端传来的参数

NSDictionary *msgBody = message.body;

// 如果是 nativeObj 就进行相应处理

if (![message.name isEqualToString:@“nativeObj”]) {

//

return;

}

}

使用 addScriptMessageHandler 注入的对象实际上只有一个 postMessage 方法,无法调用更多自定义方法。前端的调用方式如下:

window.webkit.messageHandlers.nativeObj.postMessage(data);

需要注意的是,这种方式要求 iOS8 及以上,而且返回不是同步的。和 UIWebView 一样的是,也支持直接传 JSON 对象,不需要 stringify。

Android addJavascriptInterface

安卓4.2之前注入 JS 一般是使用 addJavascriptInterface ,和前面的 addScriptMessageHandler 有一些类似,但又没有它的限制。

public void addJavascriptInterface() {

mWebView.addJavascriptInterface(new DatePickerJSBridge(), “DatePickerBridge”);

}

private class PickerJSBridge {

public void _pick(…) {

}

}

在 JS 里面调用:

window.DatePickerBridge._pick(…)

但这种方案有一定风险,可以参考这篇文章:WebView中接口隐患与手机挂马利用

在 Android4.2 之后提供了 @JavascriptInterface 注解,暴露给 JS 的方法必须要带上这个。

所以前面的 _pick 方法需要带上这个注解。

private class PickerJSBridge {

@JavascriptInterface

public void _pick(…) {

}

}

Native 调用 JS


Native 调用 JS 一般就是直接 JS 代码字符串,有些类似我们调用 JS 中的 eval 去执行一串代码。一般有 loadUrlevaluateJavascript 等几种方法,这里逐一介绍。

但是不管哪种方式,客户端都只能拿到挂载到 window 对象上面的属性和方法。

Android

在 Android 里面需要区分版本,在安卓4.4之前的版本支持 loadUrl,使用方式类似我们在 a 标签的 href 里面写 JS 脚本一样,都是javascript:xxx 的形式。

这种方式无法直接获取返回值。

webView.loadUrl(“javascript:foo()”)

在安卓4.4以上的版本一般使用 evaluateJavascript 这个 API 来调用。这里需要判断一下版本。

if (Build.VERSION.SDK_INT > 19) //see what wrapper we have

{

webView.evaluateJavascript(“javascript:foo()”, null);

} else {

webView.loadUrl(“javascript:foo()”);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值