做爲開發人員都知道,客戶端的版本更新對於用戶來講代價是很大的。爲了知足客戶端可以快速更新迭代的要求,許多app都內嵌入了H5,好比不少電商平臺,淘寶、京東、
聚划算等等。這類技術的關鍵就是在於Android客戶與Web前端之間的交互。不少大型項目的接口爲了防止Spammer的侵入,都是要求只能由客戶端發起請求的。因此本項目
就封裝了一個module,實現客戶端接收前端的調用,而後由客戶端發起Http請求的功能。
複製代碼
開始介紹項目以前,先來快速回顧一下Android客戶端與Web前端之間交互的幾種方式。
複製代碼
android客戶端代碼:javascript
private void initWebView() {
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true); // 設置與Js交互的權限
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); // 設置容許JS彈窗
webView.loadUrl("file:///android_asset/javascript.html");
webView.setWebChromeClient(new WebChromeClient() {
@Override
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
AlertDialog.Builder b = new AlertDialog.Builder(SimpleWebViewActivity.this);
b.setTitle("Alert");
b.setMessage(message);
b.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
});
b.setCancelable(false);
b.create().show();
return true;
}
});
}
private void setListener() {
btnLoadUrl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
webView.post(new Runnable() {
@Override
public void run() {
// 此處的callJS方法名與JS中的function方法名必需要一致
webView.loadUrl("javascript:callJS()");
}
});
}
});
}
複製代碼
javascript前端代碼:html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Carson_Ho</title>
// JS代碼
<script>
// Android須要調用的方法
function callJS() {
alert("Android調用了JS的callJS方法");
}
</script>
</head>
</html>
複製代碼
運行結果如圖
複製代碼
btnEvaluateJavascript.setOnClickListener(new View.OnClickListener() {
@TargetApi(19)
@Override
public void onClick(final View v) {
webView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//此處爲 js 返回的結果
Log.d(TAG, "value---" + value);
}
});
}
});
複製代碼
運行結果跟上圖是同樣的。
複製代碼
兩種交互方式的比較
複製代碼
調用方式 | 優勢 | 缺點 | 使用場景 |
---|---|---|---|
使用loadUrl() | 方便簡潔 | 效率低;獲取返回值麻煩 | 不須要使用返回值,對性能要求較低 |
使用evaluateJavascript() | 效率高 | 向下兼容性差(僅Android 4.4以上可用) | Android 4.4及以上 |
// Android版本變量
final int version = Build.VERSION.SDK_INT;
// 由於該方法在 Android 4.4 版本纔可以使用,因此使用時需進行版本判斷
if (version < 18) {
webView.loadUrl("javascript:callJS()");
} else {
webView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//此處爲 js 返回的結果
}
});
}
複製代碼
代碼再也不貼出,詳細代碼請參見:代碼地址 運行結果以下: 前端
代碼再也不貼出,詳細代碼請參見:代碼地址 運行結果以下: java
代碼再也不貼出,詳細代碼請參見:代碼地址 運行結果以下: android
2.3.1 onJsAlert()、onJsConfirm()、onJsPrompt()三者之間的比較
方法 | 做用 | 返回值 |
---|---|---|
alert() | 彈出警告框 | 沒有 |
confirm() | 彈出確認框 | 兩個返回值(true或false) |
prompt() | 彈出輸入框 | 任意設置返回值 |
2.3.2 總結
經常使用的攔截是:攔截 JS的輸入框(即prompt()方法),由於只有prompt()能夠返回任意類型的值,操做最全面方便、更加靈活,
而alert()對話框沒有返回值,confirm()對話框只能返回兩種狀態(肯定 / 取消)兩個值。
複製代碼
調用方式 | 優勢 | 缺點 | 使用場景 |
---|---|---|---|
經過WebView的addJavascriptInterface() 進行對象映射 |
方便簡潔 | Android 4.2如下存在漏洞問題 | Android 4.2以上相對簡單的互調場景 |
經過 WebViewClient 的方法shouldOverrideUrlLoading() 回調攔截 url |
不存在漏洞問題 | 有協議約束,客戶端向前端傳值繁瑣 | 不須要返回值的互調場景 |
經過 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法 回調攔截JS對話框alert()、confirm()、prompt()消息 |
不存在漏洞問題 | 有協議約束 | 能知足大多數狀況下的互調場景 |
附:WebView的addJavascriptInterface()方法在Android 4.2如下存在的漏洞git
先來看一下項目運行的效果圖:
複製代碼
你們會說,這個不是跟攔截JS的prompt()方法同樣麼,沒錯,js和android之間的交互,也無非上面提到的幾種方法,這裏作的封裝採用的是:
js調android:經過WebView的addJavascriptInterface()進行對象映射
android回調js:android 4.4以上採用WebView的evaluateJavascript()方法,android 4.4如下采用loadUrl()方法
複製代碼
android端代碼:
複製代碼
JsBridgeWebView 這是一個繼承WebView的類,它裏面向JS注入了一個對象供JS調用,JS能夠經過這個對象調用Native的方法,調哪一個方法,傳哪些參數,徹底由JS決定,方法名必須兩端協議,Native經過反射找到對應的方法。傳遞過來的參數重包含了JS回調方法的方法名,客戶端執行完相應的操做以後再去執行JS的方法。github
js代碼:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Carson</title>
<script>
function callAndroid(){
// 因爲對象映射,因此調用jsCallback對象等於調用Android映射的對象
var json = "{\"name\": \"zlove\", \"_dscbstub\": \"callback\"}"
_jsbridge.call("testAsync", json);
}
function callback(result) {
alert("客戶端返回的結果是:" + result)
}
</script>
</head>
<body>
<!-- 點擊按鈕則調用callAndroid函數 -->
<button type="button" id="button1" style="font-size:30px" onclick="callAndroid()">Call Android</button>
</body>
</html>
複製代碼
var json = "{\"name\": \"zlove\", \"_dscbstub\": \"callback\"}"
_jsbridge.call("testAsync", json);
_jsbridge表示客戶端注入的對象,testAsync是方法名,json是參數,而_dscbstub對應的callback是js的回調方法。
複製代碼
原本覺得要寫不少,事實上其實把基礎原理寫清楚了,也就這麼多😂😂😂。
I hope this will help you!
複製代碼
附:源碼地址web