原生android与H5交互

前面讲解方法,结尾放代码

android调用H5方法

首先需要一个WebView

/*查找到WebView控件*/
mWebView = (WebView) findViewById(R.id.webView);

/*给WebView一个H5的链接,这里使用的是自己启动的Vue项目*/
mWebView.loadUrl("http://10.20.58.190:8081/");

/*对WebView进行设置*/
WebSettings webSettings = mWebView.getSettings();

/*既然要调用H5的方法,那么一定不能禁用JS方法*/
webSettings.setJavaScriptEnabled(true);
  • 方法一:使用WebView的loadUrl()方法,以loadUrl(script)的方式调用

android方法:

/*在某处写入这一行代码即可*/
mWebView.loadUrl("javascript:test1Fun('使用这种方法无法取得返回参数,且会刷新页面,如果js函数有返回值,则页面会仅展示返回值')");

需要H5支持:

/*
这里使用的是Vue,对data里的test1Content 进行了修改
*/
test1Fun(str){
	this.test1Content = str;
	// return "调用test1Fun成功";
}

/*
要注意的是,如果使用原生H5,直接在页面的JavaScript标签里写入一个方法即可
但是如果使用vue来写的话,需要将此方法暴露给window,如下
*/
mounted(){
	window.test1Fun = this.test1Fun;
}

这种方法比较简单,但是缺点在于android无法获取函数的返回值
注:如果调用的函数存在返回值的话,那么H5的页面会只显示返回值

  • 方法二:使用WebView的evaluateJavascript()方法

android方法:

mWebView.evaluateJavascript("test2Fun('使用这种方法可以取得返回参数,且不会刷新页面')", new ValueCallback<String>() {
	@Override
	public void onReceiveValue(String value) {
		text2.setText(value);
	}
});

这种方法同样需要H5支持,同上:

test2Fun(str){
	this.test2Content = str;
	return "调用test2Fun成功";
}

/*同样需要暴露到window*/
mounted(){
	window.test2Fun = this.test2Fun;
}

这种方法比上一种方法更为灵活,且能够获取返回值

H5调用android

  • 方法一:使用WebView的addJavascriptInterface()方法注入对象。

android注入:

/*将JsInteration注入到h5的window.android中*/
mWebView.addJavascriptInterface(new JsInteration(), "android");

/*这里实现JsInteration */
public class JsInteration {
        @JavascriptInterface
        public String JsCallJava1(String value) {
            text3.setText(value);
            return "调用JsCallJava1成功";
        }
    }

H5调用:

useJsCallJava1(){
            let a = window.android.JsCallJava1("我是JsCallJava1的返回值");
            this.JsCallJava1Content = a;
        }

这种方式运用最为广泛,一些企业级的项目都是以此为基础搭建H5调用android的桥方法,当然,为了防止注入过多的方法,参数一般是JSON字符串格式,在android获取到参数后,会将其转换为JSON,然后根据其状态,进行后续的操作反馈。

  • 方法二:使用WebViewClient 的shouldOverrideUrlLoading()方法回调拦截请求。

android方法:

/*这里的url是H5将要进行跳转的链接,使用这个方法进行拦截*/
mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                if (url.equals("http://10.20.58.190:8081/intercept")) {
                    text4.setText("intercept");
//                    startActivity(new Intent(MainActivity.this,SecondFragment.class));
                    return true;
                } else {
                    mWebView.loadUrl(url);
                    return false;
                }
            }
        });

H5调用:

location.href = "http://10.20.58.190:8081/intercept";

注:这里一般是用于拦截链接,如果shouldOverrideUrlLoading的返回值为true,则会进行拦截,H5不进行跳转,否则则进行跳转

  • 方法三:重写 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、confirm()、prompt() 消息。

android方法:

mWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result){
                if (message.equals("alert")){
                    alert.setText("成功");
                }
                return super.onJsAlert(view, url, message, result);
            }

            @Override
            public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {

                if (message.equals("confirm")){
                    confirm.setText("成功");
                }

                return super.onJsConfirm(view, url, message, result);
            }

            @Override
            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                if (message.equals("prompt")){
                    prompt.setText("成功");
                }

                return super.onJsPrompt(view, url, message, defaultValue, result);
            }
        });

H5触发:

useJsCallJava3(judge){
            if(judge == 1){
                alert('alert')
            }
            if(judge == 2){
                confirm('confirm')
            }
            if(judge == 3){
                prompt('prompt')
            }
        }

此方法将会监听三种弹窗,用户可以根据弹窗内容进行判断,但是请注意
如果在android拦截后,return了true,则会默认客户会对弹窗进行处理,所以我们要对弹窗进行额外处理,否则H5页面就会卡死。
因此这种方法为了避免麻烦,还是少用为好,并且不对弹窗进行拦截,仅监听即可。

最后,完整的demo如下

MainActivity.java:

package com.example.study_android_java_javascript;

import android.os.Bundle;
import android.view.View;
import android.webkit.JavascriptInterface;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    public static final String TAG = "MainActivity";
    private WebView mWebView;
    private TextView text1;
    private TextView text2;
    private TextView text3;
    private TextView text4;
    private Button btn1;
    private Button btn2;
    private Button btn_clear;

    private TextView alert;
    private TextView confirm;
    private TextView prompt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        text1 =findViewById(R.id.text1);
        text2 =findViewById(R.id.text2);
        text3 = findViewById(R.id.text3);
        text4 = findViewById(R.id.text4);

        alert = findViewById(R.id.alert);
        confirm = findViewById(R.id.confirm);
        prompt = findViewById(R.id.prompt);

        btn1 = (Button) findViewById(R.id.btn1);
        btn1.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View view) {
                mWebView.loadUrl("javascript:test1Fun('使用这种方法无法取得返回参数,且会刷新页面,如果js函数有返回值,则页面会仅展示返回值')");
            }
        });
        btn2 = (Button) findViewById(R.id.btn2);
        btn2.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                mWebView.evaluateJavascript("test2Fun('使用这种方法可以取得返回参数,且不会刷新页面')", new ValueCallback<String>() {
                    @Override
                    public void onReceiveValue(String value) {
                        text2.setText(value);
                    }
                });
            }
        });
        btn_clear = findViewById(R.id.btn_clear);
        btn_clear.setOnClickListener(new View.OnClickListener(){

            @Override
            public void onClick(View view) {
                mWebView.loadUrl("javascript:clearContent()");
                text2.setText("暂无返回");
            }
        });
        mWebView = (WebView) findViewById(R.id.webView);
        mWebView.loadUrl("http://10.20.58.190:8081/");
        WebSettings webSettings = mWebView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        mWebView.addJavascriptInterface(new JsInteration(), "android");
        mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                if (url.equals("http://10.20.58.190:8081/intercept")) {
                    text4.setText("intercept");
//                    startActivity(new Intent(MainActivity.this,SecondFragment.class));
                    return true;
                } else {
                    mWebView.loadUrl(url);
                    return false;
                }
            }
        });
        mWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result){
                if (message.equals("alert")){
                    alert.setText("成功");
                }
                return super.onJsAlert(view, url, message, result);
            }

            @Override
            public boolean onJsConfirm(WebView view, String url, String message, JsResult result) {

                if (message.equals("confirm")){
                    confirm.setText("成功");
                }

                return super.onJsConfirm(view, url, message, result);
            }

            @Override
            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                if (message.equals("prompt")){
                    prompt.setText("成功");
                }

                return super.onJsPrompt(view, url, message, defaultValue, result);
            }
        });


    }
    //Android调用有返回值js方法
    public class JsInteration {
        @JavascriptInterface
        public String JsCallJava1(String value) {
            text3.setText(value);
            return "调用JsCallJava1成功";
        }
    }

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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:orientation="vertical"
    android:gravity="center_horizontal">

    <WebView
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:id="@+id/webView"
        />
    <Button
        android:id="@+id/btn1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="使用webview.loadUrl()调用JavaScript方法"/>

    <TextView
        android:id="@+id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="暂无返回"/>
    <TextView
        android:layout_width="match_parent"
        android:layout_height="20dp"/>

    <Button
        android:id="@+id/btn2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="使用webview.evaluateJavascript()调用JS方法"/>
    <TextView
        android:id="@+id/text2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="暂无返回"/>

    <Button
        android:id="@+id/btn_clear"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="清除H5的内容"
        android:layout_marginTop="20dp"/>
    <TextView
        android:layout_marginTop="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="JavaScript调用Java方法:"/>
    <TextView
        android:id="@+id/text3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="JsCallJava1返回值"/>

    <TextView
        android:layout_marginTop="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="拦截链接:"/>
    <TextView
        android:id="@+id/text4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="拦截测试数据"/>


    <TextView
        android:layout_marginTop="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="拦截弹窗"/>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="alert:"/>
        <TextView
            android:id="@+id/alert"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="confirm:"/>
        <TextView
            android:id="@+id/confirm"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""/>
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="prompt:"/>
        <TextView
            android:id="@+id/prompt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""/>
    </LinearLayout>



</LinearLayout>

indexVue.vue

<template>
    <div class="box">
        <div class="test1">
            <h3 title="123">{{test1}}</h3>
            <h4>测试内容:{{test1Content}}</h4>
        </div>

        <div class="test2">
            <h3>{{test2}}</h3>
            <h4>测试内容:{{test2Content}}</h4>
        </div>

        <button @click="useJsCallJava1">调用Java方法:JsCallJava1</button>
        <h4>返回数据:{{JsCallJava1Content}}</h4>


        <button @click="useJsCallJava2">拦截链接</button>
        <h4>   </h4>

        <button @click="useJsCallJava3(1)">测试拦截alert</button>
        <button @click="useJsCallJava3(2)">测试拦截confirm</button>
        <button @click="useJsCallJava3(3)">测试拦截prompt</button>
        
    </div>
</template>

<script>

export default {
    data(){
        return {
            test1:"Java使用webview.loadUrl()调用JavaScript方法",
            test1Content:"",
            test2:"Java使用webview.evaluateJavascript()调用JavaScript方法",
            test2Content:"",

            JsCallJava1Content:"",
        };
    },
    methods:{
        test1Fun(str){
            this.test1Content = str;
            // return "调用test1Fun成功";
        },
        test2Fun(str){
            this.test2Content = str;
            return "调用test2Fun成功";
        },
        clearContent(){
            this.test1Content = "";
            this.test2Content = "";
        },
        useJsCallJava1(){
            let a = window.android.JsCallJava1("我是JsCallJava1的返回值");
            this.JsCallJava1Content = a;
        },
        useJsCallJava2(){
            location.href = "intercept";
        },

        useJsCallJava3(judge){
            if(judge == 1){
                alert('alert')
            }
            if(judge == 2){
                confirm('confirm')
            }
            if(judge == 3){
                prompt('prompt')
            }
        }
    },
    mounted(){
        window.test1Fun = this.test1Fun;
        window.test2Fun = this.test2Fun;
        window.clearContent = this.clearContent;
    }
}
</script>

<style scoped>
    h3{
        color: blue;
    }
    h4{
        color: red;
    }
</style>
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐