前两天去Tencent面试,被面试官问到这个问题,答得不是很好,于是回来总结一下,并提供了解决方法与大家分享。
在Android中,netive与js交互已经不是什么新鲜事。大多数人都知道WebView存在一个漏洞,大致是因为js可以通过webview的window对象获得Class然后通过遍历所有的方法,找到runtime方法,边,虽然该漏洞已经在Android 4.2上修复了,即使用@JavascriptInterface代替addJavascriptInterface,但是由于兼容性和安全性问题,基本上我们不会再利用Android系统为我们提供的addJavascriptInterface方法或者@JavascriptInterface注解来实现,所以我们只能另辟蹊径,去寻找既安全,又能实现兼容Android各个版本的方案。
我们发现当setWebChromeClient之后,前端调用的一些js方法如:alert、Prompt、confirm等方法都会走你自定义的WebChromeClient类中相对应的重写的方法,由于alert、confirm使用频率较高,我们不建议处理,而prompt使用频率就少多了,甚至基本没使用,于是思路来了:我们可以让前端调用prompt这个方法,传过来一些信息,然后原生拦截prompt方法,获取这些信息,然后确定需要调用的jsbridge。
代码实现:
首先看一下目录结构:
前端部分
1、在页面加载时先定义好一些方法,包括生成一段前端与原生自己定义好的内容格式(URI)、调用prompt的方法;
//JSBridge.js
//定义的URI内容格式如下:
//JSBridge://WindowJSBridge:821021544/toast?{"msg":"Hello JSBridge"}
//JSBridge:固定标识,两端统一即可;
//WindowJSBridge:要调用原生的bridge类名;
//821021544:存储在前端callback数组中的index,代表是哪个jsbridge请求的callback;
//toast:要调用的原生方法名;
//{"msg":"Hello JSBridge"}:携带给原生的参数;
(function (win) {
var hasOwnProperty = Object.prototype.hasOwnProperty;
var JSBridge = win.JSBridge || (win.JSBridge = {});
var JSBRIDGE_PROTOCOL = 'JSBridge';
var Inner = {
callbacks: {},
call: function (obj, method, params, callback) {
console.log(obj+" "+method+" "+params+" "+callback);
var port = Util.getPort();
console.log(port);
this.callbacks[port] = callback;
var uri=Util.getUri(obj,method,params,port);
console.log(uri);
window.prompt(uri, "");
},
onFinish: function (port, jsonObj){
var callback = this.callbacks[port];
callback && callback(jsonObj);
delete this.callbacks[port];
},
};
var Util = {
getPort: function () {
return Math.floor(Math.random() * (1 << 30));
},
getUri:function(obj, method, params, port){
params = this.getParam(params);
var uri = JSBRIDGE_PROTOCOL + '://' + obj + ':' + port + '/' + method + '?' + params;
return uri;
},
getParam:function(obj){
if (obj && typeof obj === 'object') {
return JSON.stringify(obj);
} else {
return obj || '';
}
}
};
for (var key in Inner) {
if (!hasOwnProperty.call(JSBridge, key)) {
JSBridge[key] = Inner[key];
}
}
})(window);
前端页面主要是通过点击button使用在上面js文件中定义好的方法调用原生方法。
<!DOCTYPE HTML , 前端页面>
<html>