当前位置: 移动技术网 > IT编程>移动开发>Android > Android WebView与JS交互全面详解(小结)

Android WebView与JS交互全面详解(小结)

2019年07月24日  | 移动技术网IT编程  | 我要评论

刘璟钰,林熙越老婆,网游之杀戮情缘

android 和 h5 都是移动开发应用的非常广泛。市面上很多app都是使用android开发的,但使用android来开发一些比较复杂附属类,提示性的页面是得不偿失的。而h5具有开发速度快,更新不用依赖于app的更新,只需要服务端更新相应的页面即可,所以,app和h5页面相结合就显得尤为重要。而android和h5都不可能每次都是独立存在的,而是相互影响也相互的调用,获取信息等,例如,h5页面要获取app中的用户的基本信息,或者app端要操作h5页面等,下面来看看这两是怎么交互的

目录


1. 交互方式总结

android与js通过webview互相调用方法,实际上是:

  1. android去调用js的代码
  2. js去调用android的代码

二者沟通的桥梁是webview

对于android调用js代码的方法有2种:

  1. 通过webview的loadurl()
  2. 通过webview的evaluatejavascript()

对于js调用android代码的方法有3种:

  1. 通过webview的addjavascriptinterface()进行对象映射
  2. 通过 webviewclient 的shouldoverrideurlloading ()方法回调拦截 url
  3. 通过 webchromeclient的onjsalert()、onjsconfirm()、onjsprompt()方法回调拦截js对话框alert()、confirm()、prompt()消息

2. 具体分析

2.1 android通过webview调用 js 代码

方式1:通过webview的loadurl()

实例介绍:点击android按钮,即调用webview js(文本名为javascript)中calljs()

具体使用:

步骤1:将需要调用的js代码以.html格式放到src/main/assets文件夹里

为了方便展示,本文是采用andorid调用本地js代码说明;

实际情况时,android更多的是调用远程js代码,即将加载的js代码路径改成url即可

需要加载js代码:javascript.html

// 文本名:javascript
<!doctype html>
<html>

  <head>
   <meta charset="utf-8">
   <title>carson_ho</title>

// js代码
   <script>
// android需要调用的方法
  function calljs(){
   alert("android调用了js的calljs方法");
  }
</script>

  </head>

</html>

步骤2:在android里通过webview设置调用js代码

public class mainactivity extends appcompatactivity {

  webview mwebview;
  button button;

  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main);

    mwebview =(webview) findviewbyid(r.id.webview);

    websettings websettings = mwebview.getsettings();

    // 设置与js交互的权限
    websettings.setjavascriptenabled(true);
    // 设置允许js弹窗
    websettings.setjavascriptcanopenwindowsautomatically(true);

    // 先载入js代码
    // 格式规定为:file:///android_asset/文件名.html
    mwebview.loadurl("file:///android_asset/javascript.html");

    button = (button) findviewbyid(r.id.button);


    button.setonclicklistener(new view.onclicklistener() {
      @override
      public void onclick(view v) {
        // 必须另开线程进行js方法调用(否则无法调用)
        mwebview.post(new runnable() {
          @override
          public void run() {

            // 注意调用的js方法名要对应上
            // 调用javascript的calljs()方法
            mwebview.loadurl("javascript:calljs()");
          }
        });

      }
    });

    // 由于设置了弹窗检验调用结果,所以需要支持js对话框
    // webview只是载体,内容的渲染需要使用webviewchromclient类去实现
    // 通过设置webchromeclient对象处理javascript的对话框
    //设置响应js 的alert()函数
    mwebview.setwebchromeclient(new webchromeclient() {
      @override
      public boolean onjsalert(webview view, string url, string message, final jsresult result) {
        alertdialog.builder b = new alertdialog.builder(mainactivity.this);
        b.settitle("alert");
        b.setmessage(message);
        b.setpositivebutton(android.r.string.ok, new dialoginterface.onclicklistener() {
          @override
          public void onclick(dialoginterface dialog, int which) {
            result.confirm();
          }
        });
        b.setcancelable(false);
        b.create().show();
        return true;
      }

    });


  }
}

效果图

特别注意:js代码调用一定要在 onpagefinished() 回调之后才能调用,否则不会调用。

onpagefinished()属于webviewclient类的方法,主要在页面加载结束时调用

方式2:通过webview的evaluatejavascript()

优点:

  1. 该方法比第一种方法效率更高、使用更简洁。
  2. 因为该方法的执行不会使页面刷新,而第一种方法(loadurl )的执行则会。

android 4.4 后才可使用

具体使用

// 只需要将第一种方法的loadurl()换成下面该方法即可
  mwebview.evaluatejavascript("javascript:calljs()", new valuecallback<string>() {
    @override
    public void onreceivevalue(string value) {
      //此处为 js 返回的结果
    }
  });
}

2.1.2 方法对比

方式对比图

2.1.3 使用建议

两种方法混合使用,即android 4.4以下使用方法1,android 4.4以上方法2

// android版本变量
final int version = build.version.sdk_int;
// 因为该方法在 android 4.4 版本才可使用,所以使用时需进行版本判断
if (version < 18) {
  mwebview.loadurl("javascript:calljs()");
} else {
  mwebview.evaluatejavascript("javascript:calljs()", new valuecallback<string>() {
    @override
    public void onreceivevalue(string value) {
      //此处为 js 返回的结果
    }
  });
}

2.2 js通过webview调用 android 代码

2.2.1 方法分析

方式1:通过 webview的addjavascriptinterface()进行对象映射

步骤1:定义一个与js对象映射关系的android类:androidtojs

androidtojs.java(注释已经非常清楚)

// 继承自object类
public class androidtojs extends object {

  // 定义js需要调用的方法
  // 被js调用的方法必须加入@javascriptinterface注解
  @javascriptinterface
  public void hello(string msg) {
    system.out.println("js调用了android的hello方法");
  }
}

步骤2:将需要调用的js代码以.html格式放到src/main/assets文件夹里

需要加载js代码:javascript.html

<!doctype html>
<html>
  <head>
   <meta charset="utf-8">
   <title>carson</title> 
   <script>


     function callandroid(){
    // 由于对象映射,所以调用test对象等于调用android映射的对象
      test.hello("js调用了android中的hello方法");
     }
   </script>
  </head>
  <body>
   //点击按钮则调用callandroid函数
   <button type="button" id="button1" onclick="callandroid()"></button>
  </body>
</html>

步骤3:在android里通过webview设置android类与js代码的映射

public class mainactivity extends appcompatactivity {

  webview mwebview;

  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main);

    mwebview = (webview) findviewbyid(r.id.webview);
    websettings websettings = mwebview.getsettings();

    // 设置与js交互的权限
    websettings.setjavascriptenabled(true);

    // 通过addjavascriptinterface()将java对象映射到js对象
    //参数1:javascript对象名
    //参数2:java对象名
    mwebview.addjavascriptinterface(new androidtojs(), "test");//androidtojs类对象映射到js的test对象

    // 加载js代码
    // 格式规定为:file:///android_asset/文件名.html
    mwebview.loadurl("file:///android_asset/javascript.html");


特点

优点:使用简单,仅将android对象和js对象映射即可

缺点:存在严重的漏洞问题

方式2:通过 webviewclient 的方法shouldoverrideurlloading ()回调拦截 url

**具体原理: **

android通过 webviewclient 的回调方法shouldoverrideurlloading ()拦截 url解析该 url 的协议

如果检测到是预先约定好的协议,就调用相应方法

即js需要调用android的方法

具体使用:

步骤1:在js约定所需要的url协议

js代码:javascript.html

以.html格式放到src/main/assets文件夹里

<!doctype html>
<html>

  <head>
   <meta charset="utf-8">
   <title>carson_ho</title>

   <script>
     function callandroid(){
      /*约定的url协议为:js://webview?arg1=111&arg2=222*/
      document.location = "js://webview?arg1=111&arg2=222";
     }
   </script>
</head>

<!-- 点击按钮则调用callandroid()方法 -->
  <body>
   <button type="button" id="button1" onclick="callandroid()">点击调用android代码</button>
  </body>
</html>

当该js通过android的mwebview.loadurl("file:///android_asset/javascript.html")加载后,就会回调shouldoverrideurlloading (),接下来继续看步骤2:

public class mainactivity extends appcompatactivity {

  webview mwebview;
//  button button;

  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main);

    mwebview = (webview) findviewbyid(r.id.webview);

    websettings websettings = mwebview.getsettings();

    // 设置与js交互的权限
    websettings.setjavascriptenabled(true);
    // 设置允许js弹窗
    websettings.setjavascriptcanopenwindowsautomatically(true);

    // 步骤1:加载js代码
    // 格式规定为:file:///android_asset/文件名.html
    mwebview.loadurl("file:///android_asset/javascript.html");


// 复写webviewclient类的shouldoverrideurlloading方法
mwebview.setwebviewclient(new webviewclient() {
                   @override
                   public boolean shouldoverrideurlloading(webview view, string url) {

                     // 步骤2:根据协议的参数,判断是否是所需要的url
                     // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
                     //假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的)

                     uri uri = uri.parse(url);                 
                     // 如果url的协议 = 预先约定的 js 协议
                     // 就解析往下解析参数
                     if ( uri.getscheme().equals("js")) {

                       // 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议
                       // 所以拦截url,下面js开始调用android需要的方法
                       if (uri.getauthority().equals("webview")) {

                         // 步骤3:
                         // 执行js所需要调用的逻辑
                         system.out.println("js调用了android的方法");
                         // 可以在协议上带有参数并传递到android上
                         hashmap<string, string> params = new hashmap<>();
                         set<string> collection = uri.getqueryparameternames();

                       }

                       return true;
                     }
                     return super.shouldoverrideurlloading(view, url);
                   }
                 }
    );
  }
    }

特点

优点:不存在方式1的漏洞;

缺点:js获取android方法的返回值复杂。

如果js想要得到android方法的返回值,只能通过 webview 的 loadurl ()去执行 js 方法把返回值传递回去,相关的代码如下:

// android:mainactivity.java
mwebview.loadurl("javascript:returnresult(" + result + ")");

// js:javascript.html
function returnresult(result){
  alert("result is" + result);
}

方式3:通过 webchromeclient的onjsalert()、onjsconfirm()、onjsprompt()方法回调拦截js对话框alert()、confirm()、prompt() 消息

在js中,有三个常用的对话框方法:

常用的对话框方法

方式3的原理:android通过 webchromeclient 的onjsalert()、onjsconfirm()、onjsprompt()

方法回调分别拦截js对话框 (即上述三个方法),得到他们的消息内容,然后解析即可。

下面的例子将用拦截 js的输入框(即prompt()方法)

说明 :

常用的拦截是:拦截 js的输入框(即prompt()方法)

因为只有prompt()可以返回任意类型的值,操作最全面方便、更加灵活;而alert()对话框没有返回值;confirm()对话框只能返回两种状态(确定 / 取消)两个值

步骤1:加载js代码,如下: javascript.html

以.html格式放到src/main/assets文件夹里

<!doctype html>
<html>
  <head>
   <meta charset="utf-8">
   <title>carson_ho</title>

   <script>

  function clickprompt(){
  // 调用prompt()
  var result=prompt("js://demo?arg1=111&arg2=222");
  alert("demo " + result);
}

   </script>
</head>

<!-- 点击按钮则调用clickprompt() -->
  <body>
   <button type="button" id="button1" onclick="clickprompt()">点击调用android代码</button>
  </body>
</html>

当使用mwebview.loadurl("file:///android_asset/javascript.html")加载了上述js代码后,就会触发回调onjsprompt(),具体如下:

  1. 如果是拦截警告框(即alert()),则触发回调onjsalert();
  2. 如果是拦截确认框(即confirm()),则触发回调onjsconfirm();

步骤2:在android通过webchromeclient复写onjsprompt()

public class mainactivity extends appcompatactivity {

  webview mwebview;
//  button button;

  @override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);
    setcontentview(r.layout.activity_main);

    mwebview = (webview) findviewbyid(r.id.webview);

    websettings websettings = mwebview.getsettings();

    // 设置与js交互的权限
    websettings.setjavascriptenabled(true);
    // 设置允许js弹窗
    websettings.setjavascriptcanopenwindowsautomatically(true);

// 先加载js代码
    // 格式规定为:file:///android_asset/文件名.html
    mwebview.loadurl("file:///android_asset/javascript.html");


    mwebview.setwebchromeclient(new webchromeclient() {
    // 拦截输入框(原理同方式2)
      // 参数message:代表promt()的内容(不是url)
        // 参数result:代表输入框的返回值
      @override
      public boolean onjsprompt(webview view, string url, string message, string defaultvalue, jspromptresult result) {
        // 根据协议的参数,判断是否是所需要的url(原理同方式2)
        // 一般根据scheme(协议格式) & authority(协议名)判断(前两个参数)
        //假定传入进来的 url = "js://webview?arg1=111&arg2=222"(同时也是约定好的需要拦截的)

        uri uri = uri.parse(message);
        // 如果url的协议 = 预先约定的 js 协议
        // 就解析往下解析参数
        if ( uri.getscheme().equals("js")) {

          // 如果 authority = 预先约定协议里的 webview,即代表都符合约定的协议
          // 所以拦截url,下面js开始调用android需要的方法
          if (uri.getauthority().equals("webview")) {

            //
            // 执行js所需要调用的逻辑
            system.out.println("js调用了android的方法");
            // 可以在协议上带有参数并传递到android上
            hashmap<string, string> params = new hashmap<>();
            set<string> collection = uri.getqueryparameternames();

            //参数result:代表消息框的返回值(输入值)
            result.confirm("js调用了android的方法成功啦");
          }
          return true;
        }
        return super.onjsprompt(view, url, message, defaultvalue, result);
      }

// 通过alert()和confirm()拦截的原理相同,此处不作过多讲述

      // 拦截js的警告框
      @override
      public boolean onjsalert(webview view, string url, string message, jsresult result) {
        return super.onjsalert(view, url, message, result);
      }

      // 拦截js的确认框
      @override
      public boolean onjsconfirm(webview view, string url, string message, jsresult result) {
        return super.onjsconfirm(view, url, message, result);
      }
    });
    }
    }


2.2.2 三种方式的对比 & 使用场景

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网