Android中Webview与Js交互技巧大全(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35189116/article/details/79790607

上一篇给大家说了下WebView调用js这个应该来说比较简单,在说JS调用WebView之前如果有没看过上篇的这里有传送门,好了接下来还是直接上代码吧!

对于JS调用Android代码的方法大体来说有三种:

1,通过WebView的addJavaScriptInterface()就是对象映射的方式(虽然有瑕疵,但是这是本人非常常用的方法)

2,通过WebViewClient的shouldOverrideUrlLoading()方法回调拦截url

3,通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、

 confirm()、prompt() 消息

先看第一种通过WebView的addJavaScriptInterface()

/步骤1:定义一个与JS对象映射关系的Android类:AndroidtoJs
public class AndroidtoJs extends Object{

    //定义js需要调用的方法(必须加入@JavascriptInterface注解)
    @JavascriptInterface
    public void hello(String str){
        System.out.println(str);
    }

}

再看看html写法

<html>
  <head>
      <meta charset="utf-8">
      <title>YANXUN</title>
      <script>
          function callAndroid(){
              //由于对象映射,所以调用了test对象等于调用了Android映射的对象
              test.hello("js调用了Android当中的你好方法");
          }
      </script>
  </head>
      <body>
      <button type="button" id="b1" onclick="callAndroid()"  >调用callAndroid()方法</button>
      <style>
         button{
            width:300px;
            height:45px;
         }
      </style>
      </body>
</html>

看看activity中的写法

public class MainActivity extends AppCompatActivity {

    private WebView mWebView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mWebView = ((WebView) findViewById(R.id.wv));
        WebSettings mWebViewSettings = mWebView.getSettings();
        //与js交互的权限
        mWebViewSettings.setJavaScriptEnabled(true);
        //通过WebView的addJavascriptInterface()进行对象映射  方式使用简单.
        //但是该方法会存在严重漏洞:当JS拿到Android这个对象后,就可以调用这个Android对象中所有的方法(java反射机制),包括系统类(java.lang.Runtime 类),从而进行任意代码执行。
        /**例如:可以执行命令获取本地设备的SD卡中的文件等信息从而造成信息泄露
         *当一些APP通过扫描二维码打开一个外部网页时,攻击者就可以执行这段 js 代码进行漏洞攻击
         * 在微信盛行、扫一扫行为普及的情况下,该漏洞的危险性非常大
         */
        /*参数一:一个与JS对象映射关系的Android类
         *参数二:JS中进行映射的对象
         */
        mWebView.addJavascriptInterface(new AndroidtoJs(),"test");//AndroidtoJS类对象映射到js的test对象
        //加载h5,注意格式为:file:///android_asset/文件名
        mWebView.loadUrl("file:///android_asset/MyJs.html");

    }
}

后面的布局都是这个

<?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"
    tools:context="yanxun.com.jstowebview.MainActivity">

   <WebView
       android:layout_width="match_parent"
       android:layout_height="250dp"
       android:background="#ffffff"
       android:layout_margin="10dp"
       android:id="@+id/wv"
       />

</LinearLayout>

---------------------------------------------------------------------------------------------------------------------------------

第二种就复杂一点了!通过WebViewClient的shouldOverrideUrlLoading()方法回调拦截url

先看看html代码

<html>
      <head>
          <meta charset="utf-8">
          <title>Lebron James</title>
          <script>
              function callAndroid(){
              /*约定的url协议为:js://webview?arg1=111&arg2=222*/
              document.location = "js://webview?arg1=111&arg2=222";
              }
          </script>
      </head>
      <body>
      <button type="button" id="button1" onclick="callAndroid()">点击调用Android代码</button>
      <style>
         button{
            width:300px;
            height:45px;
         }
      </style>
      </body>
</html>

再来看看activity写法

public class Main2Activity extends AppCompatActivity {

    private WebView mWv;

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

        mWv = ((WebView) findViewById(R.id.wv));
        WebSettings webSettings = mWv.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        mWv.loadUrl("file:///android_asset/MyJsTwo.html");
        //1.重写shouldOverrideUrlLoading方法  优点是没有方法一的漏洞但获取Android方法的返回值复杂。
        mWv.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);
            }
        });
    }
}

---------------------------------------------------------------------------------------------------------------------------------

第三种则是通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、

 confirm()、prompt() 消息

先看看html的写法

<html>
    <head>
        <meta charset="UTF-8">
        <title>Kobe bryant</title>
        <script>
            function clickprompt(){
                //调用prompt()
                var result = prompt("js://demo?arg1=111&arg2=222");
                alert("demo" + result);
            }
        </script>
    </head>
    <body>
    <button type="button" id="button1" onclick="clickprompt()">点击调用Android代码</button>
    </body>
    <style>
        button{
            width:300px;
            height:45px;
        }
    </style>
</html>

再看看activity写法

public class Main3Activity extends AppCompatActivity {

    private WebView mV;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);
        mV = ((WebView) findViewById(R.id.wv));
        WebSettings mVSettings = mV.getSettings();
        mVSettings.setJavaScriptEnabled(true);
        mVSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        mV.loadUrl("file:///android_asset/MyJsThree.html");
        mV.setWebChromeClient(new WebChromeClient(){
            /*
            // 拦截输入框(原理同方式2)
            // 参数message:代表promt()的内容(不是url)
            // 参数result:代表输入框的返回值
             */
            @Override
            public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                Uri uri = Uri.parse(url);
                if(uri.getScheme().equals("js")){
                    if(uri.getAuthority().equals("demo")){
                        //
                        // 执行JS所需要调用的逻辑
                        System.out.println("js调用了Android的方法");
                        

                       //参数result:代表消息框的返回值(输入值)
                        result.confirm("js调用了Android的方法成功啦");
                    }
                    return true;
                }


                return super.onJsPrompt(view, url, message, defaultValue, result);
            }
        });
    }
}
好了以上就是三种js调用webview方法详细,注释也算很齐全,相信大家能理解,最后我来总结一下:
方式 优点 缺点 使用地方
通过WebView的addJavaScriptInterface() 使用简单 4.2以下有漏洞问题 4.2以上比较简单需求
通过WebViewClient的shouldOverrideUrlLoading()方法回调拦截url 没有漏洞 使用麻烦,需要双方约定协议,从本地往web传值麻烦 不需要返回值的时候
通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调拦截JS对话框alert()、

 confirm()、prompt() 方法

没有漏洞 需要双方约定协议 能满足大多数

猜你喜欢

转载自blog.csdn.net/qq_35189116/article/details/79790607