WebView與JavaScript的交互總結(jié)

WebView與JavaScript的交互總結(jié)

1、交互總結(jié)

WebView與JS之間的交互總結(jié)可以概括為下面兩種:

  • Android客戶端去調(diào)用JS代碼
  • JS端去調(diào)用Android原生代碼

它們之間互相調(diào)用的橋梁是WebView。

2、交互前準備

2.1 Android客戶端代碼

Activity:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    webView = findViewById(R.id.web_view);
    //android調(diào)用JS代碼的Button
    btnAndroidCallJS = findViewById(R.id.btn_call_js);

    //防止外部瀏覽器調(diào)用此鏈接
    webView.setWebViewClient(new WebViewClient());

    WebSettings settings = webView.getSettings();
    //允許WebView使用JS
    settings.setJavaScriptEnabled(true);
    //支持通過JS打開新窗口(允許JS彈窗)
    settings.setJavaScriptCanOpenWindowsAutomatically(true);
}

XML:

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/container"
    tools:context="com.zw.plugins.MainActivity">

    <WebView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toTopOf="@id/btn_call_js"
        android:id="@+id/web_view"></WebView>

    <Button
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:id="@+id/btn_call_js"
        android:text="Android調(diào)用JS"
        app:layout_constraintTop_toBottomOf="@id/web_view"
        app:layout_constraintBottom_toBottomOf="parent"
        />

</android.support.constraint.ConstraintLayout>

2.2 JS端代碼

test.html:

<head>

</head>

<body>
    <h1 onClick='callAndroid()'>這是JS調(diào)用原生1</h1>
    <h1 onClick='callAndroid2()'>這是JS調(diào)用原生2</h1>
    <h1 onClick='callAndroid3()'>這是JS調(diào)用原生3</h1>
    
    <Script>
        //Android原生調(diào)用JS方法
        function callJS(){
            alert("Android調(diào)用了JS的callJS方法");
            return "Android調(diào)用了JS的callJS()"
        }

        //JS調(diào)用Android原生方法
        function callAndroid(){
            // 由于對象映射,所以調(diào)用android對象等于調(diào)用Android映射的對象
            android.callAndroid("js調(diào)用了");
        }

        //JS調(diào)用通過shouldOverrideUrlLoading()調(diào)用Android原生方法
        function callAndroid2(){
            //document.location代表當前頁面的url
            document.location = "js://webview?arg1=111&arg2=222"
        }

        //JS調(diào)用通過prompt()調(diào)用Android原生方法
        function callAndroid3(){
            var result = prompt("js://webview?arg1=111");

            alert(result);
        }

    </Script>
</body>

3、Android端調(diào)用JS代碼

3.1 Android端調(diào)用JS代碼有2種方法:

  1. 通過WebView的loadUrl()
  2. 通過WebView的evaluateJavascript()

這兩種方式調(diào)用JS代碼時,格式都是以javascript:開頭的,后面接JavaScript的方法名。

3.2 通過WebView的loadUrl()

    //Android調(diào)用JS代碼
    btnAndroidCallJS.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            webView.loadUrl("javascript:callJS()");
        }
    });

注意:JS代碼調(diào)用一定要在WebViewClientonPageFinished()回調(diào)之后才能調(diào)用,否則不會調(diào)用。

3.3 通過WebView的evaluateJavascript()

//Android調(diào)用JS代碼
btnAndroidCallJS.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        webView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
            @Override
            public void onReceiveValue(String s) {
                //s是JS方法的返回值
                Log.e("zw",s); //這里s是“Android調(diào)用了JS的callJS()”
            }
        });
    }
});

這種方式比第一種方式效率高(執(zhí)行時不會刷新頁面),同時可以獲取返回值。缺點是只兼容到Android4.4版本以后。

4、JS端調(diào)用Android端代碼

3.1 JS端調(diào)用Android端代碼有3種方法:

  1. 通過WebView的addJavascriptInterface()進行對象映射
  2. 通過WebViewClientshouldOverrideUrlLoading()方法回調(diào)攔截url
  3. 通過WebChromeClientonJsAlert()onJsConfirm()、onJsPrompt()方法回調(diào)攔截JS對話框alert()、confirm()、prompt()消息

3.2 通過WebView的addJavascriptInterface()進行對象映射

3.2.1 先定義一個和JS映射的對象

public class AndroidToJS {

    // 定義JS需要調(diào)用的方法
    // 被JS調(diào)用的方法必須加入@JavascriptInterface注解
    @JavascriptInterface
    public void callAndroid(String msg){
        Log.e("zw","JS調(diào)用了Android的callAndroid(),msg : " + msg);
    }
}

3.2.2 JavaScript內(nèi)需要有Android調(diào)用原生的方法

//JS調(diào)用Android原生方法
function callAndroid(){
    // 由于對象映射,所以調(diào)用android對象等于調(diào)用Android映射的對象
    android.callAndroid("js調(diào)用了");
}

3.2.3 Android原生調(diào)用JavaScript方法

// 通過addJavascriptInterface()將Java對象映射到JS對象
//參數(shù)1:Javascript對象名
//參數(shù)2:Java對象名
webView.addJavascriptInterface(new AndroidToJS(),"android");

結(jié)果:

E/zw: JS調(diào)用了Android的callAndroid(),msg : js調(diào)用了

這種方法優(yōu)點是使用簡單,缺點是存在嚴重的漏洞問題,請看文章:你不知道的 Android WebView 使用漏洞

3.3 通過WebViewClientshouldOverrideUrlLoading()方法回調(diào)攔截url

3.3.1 先約定好調(diào)用的URL協(xié)議

比如以js://webview?arg1=111開頭。

3.3.2 在JS中定義調(diào)用方法

//JS調(diào)用通過shouldOverrideUrlLoading()調(diào)用Android原生方法
function callAndroid2(){
    //document.location代表當前頁面的url
    document.location = "js://webview?arg1=111&arg2=222"
}

3.3.3 Android端的WebView設(shè)置WebViewClient對URL進行攔截

最好重寫兩個shouldOverrideUrlLoading()方法,避免其中一個不生效。

webView.setWebViewClient(new WebViewClient(){

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {

            Log.e("ll", url );
            if(url.startsWith("js")){
                if(url.contains("webview")){
                    Toast.makeText(getApplicationContext(),"heihei",Toast.LENGTH_SHORT).show();
                    return true;
                }
            }
            return super.shouldOverrideUrlLoading(view, url);
        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            Uri uri = request.getUrl();

            Log.e("ll", uri.getScheme() + " , " + uri.getAuthority() + " , ");
            if("js".equals(uri.getScheme())){

                if("webview".equals(uri.getAuthority())){
                    Toast.makeText(getApplicationContext(),"heihei",Toast.LENGTH_SHORT).show();
                    return true;
                }
            }

            return super.shouldOverrideUrlLoading(view, request);
        }
    });

3.4 通過WebChromeClientonJsAlert()、onJsConfirm()、onJsPrompt()方法回調(diào)攔截JS對話框alert()、confirm()、prompt()消息

關(guān)于WebChromeClientonJsAlert()、onJsConfirm()、onJsPrompt()方法,可以在我的 WebView全面解析 這篇文章中得到解答。

由于alert()沒有返回值,confirm()只能返回true或者false,而prompt()可以返回任意類型的值,因此更加的靈活,這里,以prompt()舉例。

3.4.1 先約定好在prompt()中顯示信息的協(xié)議

比如以js://webview?arg1=111開頭。

3.4.2 在JS中定義調(diào)用方法

//JS調(diào)用通過prompt()調(diào)用Android原生方法
function callAndroid3(){
    var result = prompt("js://webview?arg1=111");

    alert(result);
}

3.4.3 Android端的WebView設(shè)置WebChromeClient對傳入的參數(shù)進行解析并返回

@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {

    Log.e("ll",message + " , " + defaultValue);
    if(message.startsWith("js")){
        if(message.contains("webview")){
            //confirm表示確認(并返回值),cancel表示取消。
            result.confirm("8848");
            //返回true表示不彈出系統(tǒng)提示框
            return true;
        }
    }
    return super.onJsPrompt(view,url,message,defaultValue,result);
}

5、總結(jié)

幾種調(diào)用方式的優(yōu)缺點總結(jié)如下:

Android與JS互相調(diào)用總結(jié)

6、參考資料

最全面總結(jié) Android WebView與 JS 的交互方式

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容