欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android和js、H5进行交互数据(面试必问)

程序员文章站 2022-03-09 22:39:21
android和h5、js进行交互调用 android开发过程中,我们或多或少都会用到webview,使用webview来展示一些经常变动的界面更加方便简单, 也已于维护。另一方面hybrid...

android和h5、js进行交互调用

android开发过程中,我们或多或少都会用到webview,使用webview来展示一些经常变动的界面更加方便简单,
也已于维护。另一方面hybrid app开发现在用的也越来越多了。其中native和h5之间的交互更是必不可少的。
具体android中是如何和h5交互的?或者说android中是如何和js交互的。

1 webview加载页面

我们都知道在android中是通过webview来加载html页面的。根据html文件所在的位置不同写法也不同。

例如:加载assets文件夹下的test,html页面

mwebview.loadurl("file:///android_asset/test.html")

例如:加载网页

mwebview.loadurl("https://www.baidu.com")

如果只是这样调用webview.loadurl 加载的话,那么当你点击页面中的链接的时候,页面将会在你手机默认的上打开。那如果想要在页面在app内中打开的话,那么就得设置serwebviewclient:

mwebview.setwebviewclient(new webviewclient() {
        @override
        public boolean shouldoverrideurlloading(webview view, string url) {
                //我们可以在这里拦截特定的rl请求,然后进行自己要的操作
                if (url.equals("file:///android_asset/test2.html")) {
                    log.e(tag, "shouldoverrideurlloading: " + url);
                    startactivity(new intent(mainactivity.this,main2activity.class));
                    return true;
                } else {
                //这里我们自己重新加载新的url页面,防止点击链接跳转到系统浏览器
                    mwebview.loadurl(url);
                    return true;
                }
            }
        }
    });

重写activity的onbackpressed方法,使得返回按钮不会关闭当前页面,而是返回webview上一个历史页面。

@override
    public void onbackpressed() {
        if (webview.cangoback()) {
            //返回上一个页
            webview.goback();
            return ;
        }
        super.onbackpressed();
    }

二、给webview添加加载新页面的进度条。

开启和关闭进度条

webview.setwebviewclient(new webviewclient() {

      //重写页面打开和结束的监听。打开时弹出菊花,关闭时隐藏菊花
      /**
       * 界面打开的回调
       */
      @override
      public void onpagestarted(webview view, string url, bitmap favicon) {
          if (progressdialog != null && progressdialog.isshowing()) {
              progressdialog.dismiss();
          }
          //弹出菊花
          progressdialog = new progressdialog(jsactivity.this);
          progressdialog.settitle("提示");
          progressdialog.setmessage("软软正在拼命加载……");
          progressdialog.show();

      }

      /**
       * 界面打开完毕的回调
       */
      @override
      public void onpagefinished(webview view, string url) {
          //隐藏菊花:不为空,正在显示。才隐藏关闭
          if (progressdialog != null && progressdialog.isshowing()) {
              progressdialog.dismiss();
          }
      }

  });

让进度条显示页面加载进度:

//设置进度条
        //webchromeclient与webviewclient的区别
        //webviewclient处理偏界面的操作:打开新界面,界面打开,界面打开结束
        //webchromeclient处理偏js的操作
        webview.setwebchromeclient(new webchromeclient() {
            /**
             * 进度改变的回调
             * webview:就是本身
             * newprogress:即将要显示的进度
             */
            @override
            public void onprogresschanged(webview view, int newprogress) {
                if (progressdialog != null && progressdialog.isshowing())
                    progressdialog.setmessage("软软正在拼命加载……" + newprogress + "%");
            }

三、android本地通过java调用html页面中的javascript方法

想要调用js方法那么就必须让webview支持js的代码。

//首先设置webview支持js代码
webview.getsettings().setjavascriptenabled(true);

若调用的js方法没有返回值,则可以直接调用mwebview.loadurl(“javascript:do());其中do是js中的方法;
若有返回值时我们可以调用mwebview,evalutejavascript方法;

@targetapi(build.version_codes.kitkat)
    public void onsum(view view){
        webview.evaluatejavascript("sum(1,2)", new valuecallback() {
            @override
            public void onreceivevalue(string value) {
                toast.maketext(getapplicationcontext(),
                        "相加结果:"+value, toast.length_short).show();
            }
        });
    }

    public void ondoing(view view){
        string msg = "测试";
        webview.loadurl("javascript:showinfofromjava('"+msg+"')");
    }

对应的js方法

    function sum(a,b){
    return a+b;
    }

    function showinfofromjava(){
    document.getelementbyid("p").innerhtml="java成功调的js方法";
    }

四、js调用android本地java方法

在android 4.2以上可以直接使用@javascriptinterface注解来声明,下面是在一个本地java方法

public void addjavascriptinterface(object object, string name);

1 object参数:在object对象里面添加我们想要在js里面调用的android方法,下面的代码中我们调用了showtoast方法
2 name参数:这里的name就是我们可以在js里面调用的对象名称,对应下面代码中的jstext

对应的js代码

function jsjava(){
        //调用java的方法,*对象,java方法
        //可以直接访问jstest,这是因为jstest挂载到js的window对象下了
        jstest.showtoast("我是被js执行的android代码");
    }

对应的java代码:

//java与js回调,自定义方法
        //1.java调用js
        //2.js调用java
        //首先java暴露接口,供js调用
        /**
         * obj:暴露的要调用的对象
         * interfacename:对象的映射名称 ,object的对象名,在js中可以直接调用
         * 在html的js中:jstest.showtoast(msg)
         * 可以直接访问jstest,这是因为jstest挂载到js的window对象下了
         */
        webview.addjavascriptinterface(new object() {
            //定义要调用的方法
            //msg由js调用的时候传递
            @javascriptinterface
            public void showtoast(string msg) {
                toast.maketext(getapplicationcontext(),
                        msg, toast.length_short).show();
            }
        }, "jstest");

五、重绘alert 、confirm和prompt的弹出效果,并把用户具体操作结果回调给js
alert弹窗:
Android和js、H5进行交互数据(面试必问)
重绘confirm弹窗:
Android和js、H5进行交互数据(面试必问)
重绘prompt弹窗:
Android和js、H5进行交互数据(面试必问)

具体代码:

/**
             * webview加载html中有alert()执行的时候,会回调这个方法
             * url:当前webview显示的url
             * message:alert的参数值
             * jsresult:java将结果回传到js中
             */
            @targetapi(build.version_codes.jelly_bean_mr1)
            @override
            public boolean onjsalert(webview view, string url, string message, final jsresult result) {
                alertdialog.builder builder = new alertdialog.builder(jsactivity.this);
                builder.settitle("提示:看到这个,说明java成功重写了js的alert方法");
                builder.setmessage(message);//这个message就是alert传递过来的值
                builder.setpositivebutton("确定", new onclicklistener() {

                    @override
                    public void onclick(dialoginterface dialog, int which) {
                        //处理确定按钮,且通过jsresult传递,告诉js点击的是确定按钮
                        result.confirm();
                    }
                });
                builder.show();
                //自己处理
                result.cancel();
                return true;
            }

            /**
             * webview加载html中有confirm执行的时候,会回调这个方法
             * url:当前webview显示的url
             * message:alert的参数值
             * jsresult:java将结果回传到js中
             */
            @override
            public boolean onjsconfirm(webview view, string url, string message, final jsresult result) {
                alertdialog.builder builder = new alertdialog.builder(jsactivity.this);
                builder.settitle("提示:看到这个,说明java成功重写了js的confirm方法");
                builder.setmessage(message);//这个message就是alert传递过来的值
                builder.setpositivebutton("确定", new onclicklistener() {

                    @override
                    public void onclick(dialoginterface dialog, int which) {
                        //处理确定按钮,且通过jsresult传递,告诉js点击的是确定按钮
                        result.confirm();
                    }
                });
                builder.setnegativebutton("取消", new onclicklistener() {

                    @override
                    public void onclick(dialoginterface dialog, int which) {
                        //处理取消按钮,且通过jsresult传递,告诉js点击的是取消按钮
                        result.cancel();

                    }
                });
                builder.show();
                //自己处理
                result.cancel();
                return true;
            }

            /**
             * webview加载html中有prompt()执行的时候,会回调这个方法
             * url:当前webview显示的url
             * message:alert的参数值
             *defaultvalue就是prompt的第二个参数值,输入框的默认值
             * jspromptresult:java将结果重新回传到js中
             */
            @override
            public boolean onjsprompt(webview view, string url, string message, string defaultvalue,
                                      final jspromptresult result) {
                alertdialog.builder builder = new alertdialog.builder(jsactivity.this);
                builder.settitle("提示:看到这个,说明java成功重写了js的prompt方法");
                builder.setmessage(message);//这个message就是alert传递过来的值
                //添加一个edittext
                final edittext edittext = new edittext(jsactivity.this);
                edittext.settext(defaultvalue);//这个就是prompt 输入框的默认值
                //添加到对话框
                builder.setview(edittext);
                builder.setpositivebutton("确定", new onclicklistener() {

                    @override
                    public void onclick(dialoginterface dialog, int which) {
                        //获取edittext的新输入的值
                        string newvalue = edittext.gettext().tostring().trim();
                        //处理确定按钮了,且过jsresult传递,告诉js点击的是确定按钮(参数就是输入框新输入的值,我们需要回传到js中)
                        result.confirm(newvalue);
                    }
                });
                builder.setnegativebutton("取消", new onclicklistener() {

                    @override
                    public void onclick(dialoginterface dialog, int which) {
                        //处理取消按钮,且过jsresult传递,告诉js点击的是取消按钮
                        result.cancel();

                    }
                });
                builder.show();
                //自己处理
                result.cancel();
                return true;
            }
        });

效果图:
Android和js、H5进行交互数据(面试必问)

界面上方是两个按钮,下方是一个webview控件,开启页面自动加载url,这里为了方便学习,
我已经写了一个html文件放置在了asset文件中,通过 file:///android_asset/test.html 来进行加载。
webview成功加载页面后,会出现四个新的按钮,点击不同的按钮,会产生不同的效果

asset文件夹下面的test.html文件

<meta charset="utf-8" />
<title></title>
<script>

    function jsalert(){
        var r = alert("我是alert的提示框");
        document.getelementbyid("p").innerhtml="java成功调的js的alert方法";
    }

    function jsconfirm(){
      var r = confirm("我是confirm的弹出框");
      if (r == true)
      {
        document.getelementbyid("p").innerhtml="用户点击了确认按钮";
      }else{
        document.getelementbyid("p").innerhtml="用户点击了取消按钮";
      }
    }
    function jsprompt(){
        //第一个参数是提示
        //第二个参数是默认值
        var r = prompt("请输入姓名:","小明同学");
        if (r != null)
        {
         document.getelementbyid("p").innerhtml="用户输入的姓名为:"+r;
        }else{
         document.getelementbyid("p").innerhtml="用户点击了取消按钮";
        }

    }
    function jsjava(){
        //调用java的方法,*对象,java方法
        //可以直接访问jstest,这是因为jstest挂载到js的window对象下了
        jstest.showtoast("我是被js执行的android代码");
    }

    function sum(a,b){
    return a+b;
    }

    function showinfofromjava(){
    document.getelementbyid("p").innerhtml="js方法成功被java调用";
    }

    </script>

界面成功初始化

调用jsalert方法
调用jsconfirm方法
调用jsprompt方法
调用jsjava方法

具体的java代码

public class jsactivity extends appcompatactivity {

    //assets下的文件的test.html所在的绝对路径
    private static final string default_url = "file:///android_asset/test.html";

    private webview webview;

    private progressdialog progressdialog;//加载界面的菊花

    @override
    protected void oncreate(bundle savedinstancestate) {
        super.oncreate(savedinstancestate);
        setcontentview(r.layout.activity_js);
        initview();
        initwebview();
    }

    /**
     * 初始化控件
     */
    private void initview() {
        webview = (webview) findviewbyid(r.id.webview);
        webview.loadurl(default_url);
    }

    /**
     * 初始化webview
     */
    private void initwebview() {

        //首先设置webview支持js代码
        webview.getsettings().setjavascriptenabled(true);

        //webview自己处理超链接(webview的监听器非常多,封装一个特殊的监听类来处理)
        webview.setwebviewclient(new webviewclient() {

            /**
             * 当打开超链接的时候,回调的方法
             * webview:自己本身webview
             * url:即将打开的url
             */
            @override
            public boolean shouldoverrideurlloading(webview view, string url) {
                //自己处理新的url
                webview.loadurl(url);
                //true就是自己处理
                return true;
            }

            //重写页面打开和结束的监听。打开时弹出菊花
            /**
             * 界面打开的回调
             */
            @override
            public void onpagestarted(webview view, string url, bitmap favicon) {
                if (progressdialog != null && progressdialog.isshowing()) {
                    progressdialog.dismiss();
                }
                //弹出菊花
                progressdialog = new progressdialog(jsactivity.this);
                progressdialog.settitle("提示");
                progressdialog.setmessage("软软正在拼命加载……");
                progressdialog.show();

            }

            /**
             * 重写页面打开和结束的监听。打开时弹出菊花,关闭时隐藏菊花
             * 界面打开完毕的回调
             */
            @override
            public void onpagefinished(webview view, string url) {
                //隐藏菊花:不为空,正在显示。才隐藏
                if (progressdialog != null && progressdialog.isshowing()) {
                    progressdialog.dismiss();
                }
            }

        });

        //设置进度条
        //webchromeclient与webviewclient的区别
        //webviewclient处理偏界面的操作:打开新界面,界面打开,界面打开结束
        //webchromeclient处理偏js的操作
        webview.setwebchromeclient(new webchromeclient() {
            /**
             * 进度改变的回调
             * webview:就是本身
             * newprogress:即将要显示的进度
             */
            @override
            public void onprogresschanged(webview view, int newprogress) {
                if (progressdialog != null && progressdialog.isshowing())
                    progressdialog.setmessage("软软正在拼命加载……" + newprogress + "%");
            }

            /**
             * 重写alert、confirm和prompt的弹出效果,并把用户操作的结果回调给js
             */
            /**
             * webview加载html中有alert()执行的时候,会回调这个方法
             * url:当前webview显示的url
             * message:alert的参数值
             * jsresult:java将结果回传到js中
             */
            @override
            public boolean onjsalert(webview view, string url, string message, final jsresult result) {
                alertdialog.builder builder = new alertdialog.builder(jsactivity.this);
                builder.settitle("提示:看到这个,说明java成功重写了js的alert方法");
                builder.setmessage(message);//这个message就是alert传递过来的值
                builder.setpositivebutton("确定", new onclicklistener() {

                    @override
                    public void onclick(dialoginterface dialog, int which) {
                        //处理确定按钮了,且通过jsresult传递,告诉js点击的是确定按钮
                        result.confirm();
                    }
                });
                builder.setoncancellistener(new dialoginterface.oncancellistener() {
                    @override
                    public void oncancel(dialoginterface dialog) {
                        //防止用户点击对话框外围,再次点击按钮页面无响应
                        result.cancel();
                    }
                });
                builder.show();
                //自己处理
                return true;
            }

            /**
             * webview加载html中有confirm执行的时候,会回调这个方法
             * url:当前webview显示的url
             * message:alert的参数值
             * jsresult:java将结果回传到js中
             */
            @override
            public boolean onjsconfirm(webview view, string url, string message, final jsresult result) {
                alertdialog.builder builder = new alertdialog.builder(jsactivity.this);
                builder.settitle("提示:" +
                        "看到这个,说明java成功重写了js的confirm方法");
                builder.setmessage(message);//这个message就是alert传递过来的值
                builder.setpositivebutton("确定", new onclicklistener() {

                    @override
                    public void onclick(dialoginterface dialog, int which) {
                        //处理确定按钮了,且通过jsresult传递,告诉js点击的是确定按钮
                        result.confirm();
                    }
                });
                builder.setnegativebutton("取消", new onclicklistener() {

                    @override
                    public void onclick(dialoginterface dialog, int which) {
                        //处理取消按钮,且通过jsresult传递,告诉js点击的是取消按钮
                        result.cancel();

                    }
                });
                builder.setoncancellistener(new dialoginterface.oncancellistener() {
                    @override
                    public void oncancel(dialoginterface dialog) {
                        //防止用户点击对话框外围,再次点击按钮页面无反应
                        result.cancel();
                    }
                });
                builder.show();
                //自己处理
                return true;
            }

            /**
             * webview加载html中有prompt()执行的时候,会回调这个方法
             * url:当前webview显示的url
             * message:alert的参数值
             *defaultvalue就是prompt的第二个参数值,输入框的默认值
             * jspromptresult:java将结果重新回传到js中
             */
            @override
            public boolean onjsprompt(webview view, string url, string message, string defaultvalue,
                                      final jspromptresult result) {
                alertdialog.builder builder = new alertdialog.builder(jsactivity.this);
                builder.settitle("提示:看到这个,说明java成功重写了js的prompt方法");
                builder.setmessage(message);//这个message就是alert传递过来的值
                //添加一个edittext
                final edittext edittext = new edittext(jsactivity.this);
                edittext.settext(defaultvalue);//这个就是prompt 输入框的默认值
                //添加到对话框
                builder.setview(edittext);
                builder.setpositivebutton("确定", new onclicklistener() {

                    @override
                    public void onclick(dialoginterface dialog, int which) {
                        //获取edittext的新输入的值
                        string newvalue = edittext.gettext().tostring().trim();
                        //处理确定按钮了,且过jsresult传递,告诉js点击的是确定按钮(参数就是输入框新输入的值,我们需要回传到js中)
                        result.confirm(newvalue);
                    }
                });
                builder.setnegativebutton("取消", new onclicklistener() {

                    @override
                    public void onclick(dialoginterface dialog, int which) {
                        //处理取消按钮,且过jsresult传递,告诉js点击的是取消按钮
                        result.cancel();

                    }
                });
                builder.setoncancellistener(new dialoginterface.oncancellistener() {
                    @override
                    public void oncancel(dialoginterface dialog) {
                        //防止用户点击对话框外围,再次点击按钮页面无反应
                        result.cancel();
                    }
                });
                builder.show();
                //自己处理
                return true;
            }
        });

        //java与js回调,自定义方法
        //1.java调用js
        //2.js调用java
        //首先java暴露接口,供js调用
        /**
         * obj:暴露的要调用的对象
         * interfacename:对象的映射名称 ,object的对象名,在js中可以直接调用
         * 在html的js中:jstest.showtoast(msg)
         * 可以直接访问jstest,这是因为jstest挂载到js的window对象下了
         */
        webview.addjavascriptinterface(new object() {
            //定义要调用的方法
            //msg由js调用的时候传递
            @javascriptinterface
            public void showtoast(string msg) {
                toast.maketext(getapplicationcontext(),
                        msg, toast.length_short).show();
            }
        }, "jstest");

    }

    @targetapi(build.version_codes.kitkat)
    public void onsum(view view){
        webview.evaluatejavascript("sum(1,2)", new valuecallback() {
            @override
            public void onreceivevalue(string value) {
                toast.maketext(getapplicationcontext(),
                        "相加结果:"+value, toast.length_short).show();
            }
        });
    }

    public void ondoing(view view){
        string msg = "测试";
        webview.loadurl("javascript:showinfofromjava('"+msg+"')");
    }


    @override
    public void onbackpressed() {
        if (webview.cangoback()) {
            //返回上一个页
            webview.goback();
            return ;
        }
        super.onbackpressed();
    }

}

布局文件activity_js.xml



    



代码过程描述的废话我就不多说了,注释写的算是比较仔细了,另外再强调两点需要注意的地方:

1、不要忘记通过setjavascriptenabled(true)设置webview支持js代码

2、在使用addjavascriptinterface方法添加挂载对象时,要注意在android4.2之后需要给对象方法加上@javascriptinterface注解。

3、重绘alert、confirm和prompt的弹出效果之后,在对话框结束之后一定要调用result.confirm()或者result.cancel()两个方法中的一个

,否则会出现后续再次点击html页面按钮,页面无响应的情况

项目地址:https://github.com/afinalstone/webviewandjs-master