Android-Java 和 JavaScript 相互呼叫

姜家志發表於2017-04-07

當前的Android開發中,會使用大量的h5(html5+css+js),甚至出現了混合開發模式(Hybrid),使用Hybrid開發,h5頁面開發效率高和移植便利性為主。
但在一些地方使用h5開發的確會不太容易實現,這個時候就需要呼叫Java原生方法來完成,就會遇到JavasSript和Java相互呼叫,用Java原生方法實現那些Javascript程式碼不容易實現的功能,比如,非同步執行緒,呼叫資料庫等..... 然後再暴露給JavaScript呼叫。

JavascriptInterface

Android 4.2之前使用addjavascriptinterface可以把原生的Java方法,給JavaScript呼叫,但是這種方案卻存在安全風險,在頁面中執行一些不可信的Javascript程式碼即有可能控制使用者的手機,詳情見:WebView中介面隱患與手機掛馬利用
Android 4.2之後提供了@JavascriptInterface物件註解的方式建立Javascript物件和android原生物件的繫結,提供給JavaScript呼叫的方法必須帶有@JavascriptInterface
當前4.0及4.0之前的系統市場佔有量已經很低了,因此可以考慮使用minSdkVersion為17,只支援4.2版本以上的手機,低版本的系統不再支援了。
下面就看下Java和Javascript是如何通訊的。

載入本地html

為了方便使用,下面使用的示例,不會使用server,所以就需要在webview中使用本地的html檔案,為了方便把html檔案都放在assets資料夾中,使用本地載入的方式,這樣就不需要伺服器的支援了。
先定義一個html檔案:

<!DOCTYPE html>
<html>
    <body>
        <h1>this is html</h1>
    </body>
</html>複製程式碼

使用file:///android_asset/index.html載入到webview中:

    private void initView() {
        webView = (WebView) findViewById(R.id.webView);
        webView.loadUrl("file:///android_asset/index.html");
    }複製程式碼

下面就可以在index.html中試用Java和JavaScript的呼叫了。

Javascript呼叫Java方法

以Android的Toast的為例,下面看下如何從Javascript程式碼中呼叫系統的Toast
先定義一個AndroidToast的Java類,它有一個show的方法用來顯示Toast:

public class AndroidToast {
        @JavascriptInterface
        public void show(String str) {
            Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
        }
    }複製程式碼

再對WebView進行設定,開啟JavaScipt,註冊JavascriptInterface的方法:

private void initView() {
        webView = (WebView) findViewById(R.id.webView);

        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setDefaultTextEncodingName("UTF-8");
        webView.addJavascriptInterface(new AndroidToast(), "AndroidToast");
        webView.loadUrl("file:///android_asset/index.html");
 }複製程式碼

addJavascriptInterface的作用是把AndroidToast類對映為Javascript中的AndroidToast。這樣就可以在JavaScript中呼叫Java中的方法了。
在Javascript中呼叫Java程式碼:

function toastClick(){
        window.AndroidToast.show('from js');
}複製程式碼

通過window屬性可以找到對映的物件AndroidToast,直接呼叫它的show方法即可。
注意這裡傳輸的資料只能是基本資料型別和string,可以傳輸string就意味著可以使用json傳輸結構化資料。
這裡呼叫的方法並沒有返回值,如果需要在JavaScript中需要得到返回值怎麼辦呢?

JavaScript呼叫Java有返回值

如果想從Javascript調的方法裡面獲取到返回值,只需要定義一個帶返回值的@JavascriptInterface方法即可:


    public class AndroidMessage {
        @JavascriptInterface
        public String getMsg() {
            return "form java";
        }
    }複製程式碼

新增Javascript的對映:

webView.addJavascriptInterface(new AndroidMessage(), "AndroidMessage");複製程式碼

在JavaScript直接呼叫:

function showAlert(){
        var str=window.AndroidMessage.getMsg();
        console.log(str);
 }複製程式碼

這樣就完成了有返回值的方法呼叫。還有一種場景是,在Java中主動觸發JavaScript方法,就需要在Java中呼叫JavaScript方法了。

Java呼叫JavaScript方法

Java在呼叫JavaScript方法的時候,需要使用WebView.loadUrl()方法,它可以直接在頁面裡執行JavaScript方法。
首先定義一個JavaScript方法給Java呼叫:

function callFromJava(str){
        console.log(str);
    }複製程式碼

在Java中直接呼叫該方法:

public void  javaCallJS(){
        webView.loadUrl("javascript:callFromJava('call from java')");
    }複製程式碼

可以在loadUrl中給Javascript方法直接傳參,如果JavaScript方法有返回值,使用WebView.loadUrl()是無法獲取到返回值的,需要JavaScript返回值給Java的話,可以定義一個Java方法提供給JavaScript呼叫,然後Java呼叫JavaScript之後,JavaScript觸發該方法把返回值再傳遞給Java。
注意WebView.loadUrl()必須在Ui執行緒中執行,不然會會報錯。

專案地址:github.com/jjz/android…

相關文章