JSBrige系列直通車,由淺入深理解JS-Native的通信過程:
JSbridge系列解析(一):JS-Native調(diào)用方法
JSbridge系列解析(二):lzyzsd/JsBridge使用方法
JSbridge系列解析(三):lzyzsd/JsBridge源碼解析
JSbridge系列解析(四):Web端發(fā)消息給Native代碼流程具體分析
web具有開發(fā)速度快扣甲,上線方便等優(yōu)點(diǎn)恼除;而native開發(fā)則展示效果好细诸,但開發(fā)節(jié)奏慢园爷。在開發(fā)中镜会,經(jīng)常需要將web開發(fā)和native開發(fā)相結(jié)合巾陕,這就需要了解JS和Native之間相互調(diào)用的方法了魂奥。
基本知識(shí)
安卓提供Webview用來加載html頁面菠剩,以安卓4.4系統(tǒng)為分水嶺,之前的webview內(nèi)核采用webkit耻煤;4.4及之后改為chromium內(nèi)核具壮。
JS -> Native
常用的JS調(diào)用Java代碼的方法,主要包括以下三種:
1)通過WebView的addJavascriptInterface進(jìn)行對(duì)象映射
2)通過 WebViewClient 的shouldOverrideUrlLoading方法回調(diào)攔截 url
3) 通過 WebChromeClient 的onJsAlert哈蝇、onJsConfirm棺妓、onJsPrompt方法回調(diào)攔截JS對(duì)話框alert、confirm炮赦、prompt 消息
今天主要介紹第一種怜跑,也是最常用的使用方案。首先需要打開WebView的一個(gè)設(shè)置選項(xiàng)吠勘。如下:
//允許運(yùn)行js代碼
mWebView.getSettings().setJavaScriptEnabled(true);
WebView提供addJavascriptInterface方法性芬,用于注入Java函數(shù)以便JS調(diào)用。示例如下:
/**
This method can be used to allow JavaScript to control the host application. This is a powerful feature, but also presents a security risk for applications targeted to API level [JELLY_BEAN](http://developer.android.com/reference/android/os/Build.VERSION_CODES.html#JELLY_BEAN)
or below, because JavaScript could use reflection to access an injected object's public fields. Use of this method in a WebView containing untrusted content could allow an attacker to manipulate the host application in unintended ways, executing Java code with the permissions of the host application. Use extreme care when using this method in a WebView which could contain untrusted content.
JavaScript interacts with Java object on a private, background thread of this WebView. Care is therefore required to maintain thread safety.
The Java object's fields are not accessible
*/
//注入js對(duì)象jsInterface
mWebView.addJavascriptInterface(new JSInterface(), "jsInterface");
根據(jù)安卓官方的api說明看幼,addJavaScriptInterface方法存在安全漏洞批旺。因?yàn)镴S可以通過反射訪問注入對(duì)象。官方在4.2及以后的系統(tǒng)中修復(fù)了該問題诵姜,要求注入的遠(yuǎn)程方法必須使用注解@JavascriptInterface
//JAVA代碼
class JsObject {
@JavascriptInterface
public String toString() { return "injectedObject"; }
}
webView.addJavascriptInterface(new JsObject(), "injectedObject");
//JS調(diào)用注入對(duì)象示例【java代碼】
webView.loadUrl("javascript:alert(injectedObject.toString())");
針對(duì)4.2以下的系統(tǒng)汽煮,可以利用JS的事件來解決,如prompt, alert等棚唆。這樣的動(dòng)作都會(huì)對(duì)應(yīng)到WebChromeClient類中相應(yīng)的方法暇赤,對(duì)于prompt,它對(duì)應(yīng)的方法是onJsPrompt方法宵凌,這個(gè)方法的聲明如下:
public boolean onJsPrompt(WebView view, String url, String message,
String defaultValue, JsPromptResult result)
prompt方案可參考PhoneGap的實(shí)現(xiàn)鞋囊,主要包括以下幾點(diǎn)
【1】在4.2以下系統(tǒng),js對(duì)象未注入的情況下瞎惫,可讓JS調(diào)用prompt方法溜腐,通過prompt把JS中的信息傳遞到Java部分。這些信息應(yīng)該是我們定義的一段有特定含義的文本瓜喇,可能包含:特定標(biāo)識(shí)挺益,方法名稱,參數(shù)等乘寒。在onJsPrompt方法中望众,我們?nèi)ソ馕鰝鬟f過來的文本,得到方法名,參數(shù)等烂翰,再通過反射機(jī)制夯缺,調(diào)用指定的方法,從而調(diào)用到Java對(duì)象的方法甘耿。
【2】關(guān)于返回值踊兜,可以通過prompt返回回去,這樣就可以把Java中方法的處理結(jié)果返回到Js中棵里。
【3】我們需要?jiǎng)討B(tài)注入一段JavaScript初始化的腳本润文,可通過webview的loadUrl來加載,從而注冊(cè)到html頁面中殿怜。如PhoneGap中的js文件
注意:1)注入JS方法不能過早典蝌,一般在onPageFinished方法,否則注入可能無效
2)在Android 3.0以下头谜,安卓系統(tǒng)添加了一個(gè)名為searchBoxJavaBridge_的Js接口骏掀,需要調(diào)用removeJavascriptInterface方法刪除該方法,以解決安全風(fēng)險(xiǎn)柱告。
3)記憶中在4.4系統(tǒng)之前截驮,onJsPrompt運(yùn)行在主線程中;而4.4及以后际度,該方法運(yùn)行在非主線程葵袭。請(qǐng)各位看客驗(yàn)證
Native -> JS
Java調(diào)用JS的方法,包括以下兩種:
1)通過WebView的loadUrl方法乖菱,該方法必須在主線程中調(diào)用
2)通過WebView的evaluateJavascript坡锡,該方法可獲取JS返回值,但4.4及以上才能使用