js 與原生互動分為兩種情況:js 呼叫原生方法,原生呼叫 js 方法。
本文將對這兩種情況分別講解,H5 端用 vue
實現。
一、前期準備(Vue專案準備)
本文的 H5 端用Vue
實現,所以在正式開始前先把 Vue
專案環境準備好。
專案寫好後,執行 npm run serve
命令啟動專案,啟動成功後會在命令列看到兩個地址:
http://localhost:8080/
和 http://10.0.0.188:8080/
10.0.0.188
是我本機的 ip
地址,每個人的不一樣。
在電腦的瀏覽器訪問的話哪個都行,但在手機或模擬器訪問的話需要用第二個帶 ip
地址的,且要保證手機跟電腦連線同一個 wifi
或在同一網段。
注意:這裡用的是 vue-cli 3.0,執行命令跟 vue-cli 2.X 有所區別。詳情請自行查詢官方文件。
啟動成功後在 Android 專案中將 http://10.0.0.188:8080/
地址配置給 WebView
即可
Intent intent = new Intent(getActivity(), ProgressWebviewActivity.class);
intent.putExtra("url", "http://10.0.0.188:8080/");
startActivity(intent);
複製程式碼
到此,在手機中就可以訪問 Vue
專案了。
二、Android 原生呼叫 JS 中的方法
Android 呼叫 JS 有兩種方式,都是通過 WebView
的方法:
webview.loadUrl()
webview.evaluateJavascript()
二者區別:
loadUrl()
會重新整理頁面,evaluateJavascript()
則不會使頁面重新整理,所以evaluateJavascript()
的效率更高
loadUrl()
得不到 js 的返回值,evaluateJavascript()
可以獲取返回值
evaluateJavascript()
在 Android 4.4 之後才可以使用
要實現的效果:
如下圖,頁面上有一行文字 ”哈哈“,要在 WebView
頁面載入完的時候通過 Android 原生程式碼將這行字改為 ”我通過原生方法改變了文字“ + Android 傳遞過來的引數,並給 Android 返回一個字串 ”js呼叫成功“。
2.1 Vue 程式碼
先看 Vue 中程式碼怎麼寫
mounted() {
//將要給原生呼叫的方法掛載到 window 上面
window.callJsFunction = this.callJsFunction
},
data() {
return {
msg: "哈哈"
}
},
methods: {
callJsFunction(str) {
this.msg = "我通過原生方法改變了文字" + str
return "js呼叫成功"
}
}
複製程式碼
在 methods
中定義一個供 Android 呼叫的方法 callJsFunction(str)
, 並可接收一個引數 str
,然後改變頁面中的文字。
如果只是在 methods
中定義方法,原生呼叫會找不到這個方法。所以要在頁面載入的時候將方法掛載在 window
上,這樣 WebView
就可以拿到此方法了。注意,這步很重要一定要寫!
注意一個細節,this.callJsFunction
後面不要加括號 ()
,加括號相當於直接呼叫了。
總結起來 Vue
中要做的事情就兩步:
- 在
methods
中定義方法 - 在
mounted
中將方法掛載在window
上
2.2 Android 中程式碼
需要等頁面載入完在 WebView
的 onPageFinished
方法中寫呼叫邏輯,否則不會執行。
2.2.1 loadUrl()
實現
tbsWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url, headerMap);
return true;
}
@Override
public void onPageFinished(WebView webView, String s) {
super.onPageFinished(webView, s);
//安卓呼叫js方法。注意需要在 onPageFinished 回撥裡呼叫
tbsWebView.post(new Runnable() {
@Override
public void run() {
tbsWebView.loadUrl("javascript:callJsFunction('soloname')");
}
});
}
});
}
});
複製程式碼
如果不需要傳引數,把引數去掉即可 tbsWebView.loadUrl("javascript:callJsFunction()");
2.2.2 evaluateJavascript()
實現
其他地方跟loadUrl()
一樣,只是把 tbsWebView.loadUrl("javascript:callJsFunction('soloname')");
替換掉
@Override
public void onPageFinished(WebView webView, String s) {
super.onPageFinished(webView, s);
//安卓呼叫js方法。注意需要在 onPageFinished 回撥裡呼叫
tbsWebView.post(new Runnable() {
@Override
public void run() {
tbsWebView.evaluateJavascript("javascript:callJsFunction('soloname')", new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Logger.d("js返回的結果: " + s);
}
});
}
});
}
複製程式碼
可以看到頁面更新了,第二種方法也拿到了返回的結果。
三、JS 呼叫 Android 原生方法
對於JS呼叫Android程式碼的方法有3種:
- 通過
WebView
的addJavascriptInterface()
進行物件對映 - 通過
WebViewClient
的shouldOverrideUrlLoading()
方法回撥攔截 url - 通過
WebChromeClient
的onJsAlert()
、onJsConfirm()
、onJsPrompt()
方法回撥攔截JS對話方塊alert()
、confirm()
、prompt()
訊息
對比: 第一種最簡潔,但在 Android 4. 2 以下存在漏洞;第二種和第三種使用複雜,但不存在漏洞問題。
由於目前的裝置系統版本基本都在 4.2 以上,所以用第一種就可以了,簡單快捷。時間有限本文只實現第一種,第二種和第三種就不實現了,想了解的可以參考 這篇文章 。
3.1 效果展示
要實現的效果就是點選 H5 頁面上的按鈕,彈出 Android 原生的 Toast
3.2 Vue 程式碼
methods: {
showAndroidToast() {
$App.showToast("哈哈,我是js呼叫的")
}
}
複製程式碼
在 methods
中定義方法 showAndroidToast()
, 點選頁面上按鈕 "呼叫Android原生Toast" 時呼叫。
3.3 Android 程式碼
新建類 JsJavaBridge
public class JsJavaBridge {
private Activity activity;
private WebView webView;
public JsJavaBridge(Activity activity, WebView webView) {
this.activity = activity;
this.webView = webView;
}
@JavascriptInterface
public void onFinishActivity() {
activity.finish();
}
@JavascriptInterface
public void showToast(String msg) {
ToastUtils.show(msg);
}
}
複製程式碼
然後通過 WebView
設定 Android
類與 JS 程式碼的對映
tbsWebView.addJavascriptInterface(new JsJavaBridge(this, tbsWebView), "$App");
複製程式碼
這裡將類 JsJavaBridge
在 JS 中對映為了 $App
,所以在 Vue 中可以這樣呼叫 $App.showToast("哈哈,我是js呼叫的")
。
以上就是 Android 與 JS 的互相呼叫。