Android開發之Webview中原生與JS互動
文章目錄
概述
由於手機硬體資源的快速提升,使得采用混合開發的可能性逐漸成為現實並且流行起來。Android開發中最為簡單的方式就是通過Webview來嵌入一個網頁使web作為App的一部分。
使用場景
- 非重互動場景
- 非計算密集型場景
- 對UI複雜度要求不高的場景
以上可見,《王者榮耀》斷然不會使用混合開發的,其實谷歌舉了兩個最適合的場景:
第一:內容需要動態更新的場景,例如APP裡面的法律條款展示等。
第二:總是需要通過網路來拉取展示內容的場景,例如新聞展示。
互動方式
我們知道,網頁的行為現在是使用JavaScript
來處理的,而Android原生使用的是Java(Kotlin)
,互動的意思即原生可以呼叫JavaScript方法,而JavaScript也可以呼叫原生的方法。
Java呼叫JS程式碼的方法有2種:
- 通過WebView的loadUrl() 方法
- 通過WebView的evaluateJavascript()方法
JS呼叫Java程式碼的方法有3種:
- 通過WebView的addJavascriptInterface()進行物件對映
- 通過 WebViewClient 的shouldOverrideUrlLoading ()方法回撥攔截 url
- 通過 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回撥攔截JS對話方塊alert()、confirm()、prompt() 訊息
先上一張效果圖:
Java呼叫JS程式碼
上面提到Android提供了兩種方法來實現Java執行Js程式碼,其中evaluateJavascript()
方法是從 API 19(4.4版本)開始提供的,而現在Android已經發布到 API 28 (9.0)了, 4.4以下版本佔的比例已經非常少了,相信過不了多久基本上就不存在了,所以我們要放下歷史包袱,直接使用新的方法。最重要的是,在Android 4.4及其以上版本Google 採用了 Chromium
HTML5
,CSS3
,Javascript
的支援更為廣泛,而且js執行引擎直接換成了V8,執行效率大大提升.
void evaluateJavascript(String script, ValueCallback<String> resultCallback){}
引數script : 要執行的JS程式碼。
引數 resultCallback: Js程式碼執行後的返回值
具體步驟:
第一:新建一個工程,新建一個Activity,包含一個Webview
控制元件。
第二:新建一個demo.html的文件,作為要在webview中展示的web頁面,裡面含有js程式碼。將其放在工程中的assets檔案家中。
<!DOCTYPE html>
<html>
<head lang="zh-cmn-Hans">
<meta charset="UTF-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<meta name="viewport" content="width=device-width"/>
<title>JsBridgeDemo</title>
</head>
<style>
.btn {
text-align: center;
background: #d8d8d8;
color: #222;
padding: 20px;
margin: 30px;
font-size: 24px;
border-radius: 4px;
box-shadow: 4px 2px 10px #999;
}
.btn:active {
opacity: .7;
box-shadow: 4px 2px 10px #555;
}
</style>
<body>
<div class="btn" onclick="showAndroidToast('Js呼叫Java')">Js呼叫Java函式</div>
<p id="content"></p>
<script type="text/javascript">
function showAndroidToast(toast) {
android.showToast(toast);
}
function fillContent(){
document.getElementById("content").innerHTML ="此處內容由Java呼叫Js方法展示在Webview上";
return "ok";
}
</script>
</body>
第三步:在activity中通過webview呼叫Js程式碼。
final WebView myWebView=findViewById(R.id.webView);
WebSettings webSettings=myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
myWebView.loadUrl("file:///android_asset/demo.html");
Button btnCallJs=findViewById(R.id.btn_call_js);
btnCallJs.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
myWebView.evaluateJavascript("fillContent()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
Toast.makeText(MainActivity.this,value,Toast.LENGTH_SHORT).show();
}
});
}
});
首先設定允許Webview執行Js,然後載入assets資料夾中的demo.html網頁,最後在點選按鈕的時候使用evaluateJavascript()
方法來執行Js程式碼。
JS程式碼的呼叫需要在web頁面載入完成後才可以正常執行。可以通過監聽WebViewClient的onPageFinished 回撥來完成,如下程式碼所示。
myWebView.setWebViewClient(new WebViewClient(){
@Override
public void onPageFinished(WebView view, String url){
super.onPageFinished(view, url);
//執行Js程式碼
}
});
JS呼叫Java程式碼
上面提到有三種方法可以實現Js呼叫Java程式碼的目的,其中第一種簡單明瞭,為Google推薦的方法,但是其在API 17(4.2)之前存在任意執行漏洞。但是我們前面分析了,4.4 都快沒有了,4.2 就更別說了,所以我們直接針對Android4.4程式設計,使用這個方法是安全的。
具體步驟:
第一步:新建一個介面類JavaInterface
,裡面定義給Js呼叫的方法。這些方法必須是public的,而且必須使用@JavascriptInterface
進行註解,例如下面的程式碼示例中的showTost()
。
public class JavaInterface {
private Context mContext;
JavaInterface(Context c) {
mContext = c;
}
@JavascriptInterface
public void showToast(String toast) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}
第二步:給Webview新增與Js的對映關係
myWebView.addJavascriptInterface(new JavaInterface(this),"android");
引數1:介面類的物件
引數2:Java物件對映到Js的物件名,可以在Js中使用這個物件來呼叫介面類中的方法。
第三步:在Js中呼叫Java方法
<script type="text/javascript">
function showAndroidToast(toast) {
android.showToast(toast);
}
</script>
可以看到,在js中可以使用android這個Js物件,直接呼叫我們定義在JavaInterface
類中的方法。
總結
以上就是Android開發中使用Webview 完成原生與web的互動。開篇說道除了本文介紹的方式,還有其他幾種方式,大部分不是有歷史包袱就是本意不是用來做這件事情的,所以應該優先使用本文的方式,如果有的同學需要了解其他方法,可以參考這篇部落格,寫的比較全。
如果是在專案中使用而不是為了學習,推薦使用前人寫好的三方庫,例如DSBridge,JsBridge等。特別是dsbridge,三端全有,現代簡潔,易用。