WebView 用法

WebView 常用的类

  • WebView
  • WebSettings
  • WebViewClient
  • WebChromeClient
  • addJavascriptInterface

必要权限

一、WebView

(1)创建WebView


WebView webview = new WebView(this);

(2)加载url

  • 加载网页 url地址
webView.loadUrl("http://www.jianshu.com/")
  • 加载本地asset目录下的网页

注意:将index.html 放在asset目录下

webView.loadUrl("file:///android_asset/html/index.html"); //加载本地assert目录下网页
  • 加载Sdcard上的html

(3) 返回和后退

webview是否可以返回到上一页面 webView.canGoBack()
webview返回到上一页面 webView.goBack();
webview是否可以前进 webView.canGoForward()
webview前进 webView.goForward();

二、WebSettings Webview设置类

设置WebView的一些属性、状态等,例如允许使用javascript,允许使用缓存,允许使用内置的缩放组件,设置支持IS等

//声明WebSettings子类
WebSettings webSettings = webView.getSettings();

//如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript
webSettings.setJavaScriptEnabled(true);  
// 若加载的 html 里有JS 在执行动画等操作,会造成资源浪费(CPU、电量)
// 在 onStop 和 onResume 里分别把 setJavaScriptEnabled() 给设置成 false 和 true 即可

//支持插件
webSettings.setPluginsEnabled(true); 

//设置自适应屏幕,两者合用
webSettings.setUseWideViewPort(true); //将图片调整到适合webview的大小 
webSettings.setLoadWithOverviewMode(true); // 缩放至屏幕的大小

//缩放操作
webSettings.setSupportZoom(true); //支持缩放,默认为true。是下面那个的前提。
webSettings.setBuiltInZoomControls(true); //设置内置的缩放控件。若为false,则该WebView不可缩放
webSettings.setDisplayZoomControls(false); //隐藏原生的缩放控件

//其他细节操作
webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //关闭webview中缓存 
webSettings.setAllowFileAccess(true); //设置可以访问文件 
webSettings.setJavaScriptCanOpenWindowsAutomatically(true); //支持通过JS打开新窗口 
webSettings.setLoadsImagesAutomatically(true); //支持自动加载图片
webSettings.setDefaultTextEncodingName("utf-8");//设置编码格式


三、WebViewClient : 主要负责请求事件和各种通知(例如开始加载、加载完毕之后的动作、加载错误、对加载url链接的拦截)

webView.setWebViewClient(new WebViewClient() {
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        //页面开始加载时
        super.onPageStarted(view, url, favicon);
    }
    @Override
    public void onPageFinished(WebView view, String url) {
        //页面加载结束时
        super.onPageFinished(view, url);
    }
    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
        super.onReceivedError(view, errorCode, description, failingUrl);
        // 这里进行无网络或错误处理,具体可以根据errorCode的值进行判断,
    }
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        view.loadUrl(url);
        /**
         * 网页跳转:
         * 1.在当前的webview跳转到新连接
         * view.loadUrl(url);
         * 2.调用系统浏览器跳转到新网页
         * Intent i = new Intent(Intent.ACTION_VIEW);
         * i.setData(Uri.parse(url));
         * startActivity(i);
         */
        return true;
    }
});

四、WebChromeClient

辅助处理 javaScript的各种对话框、网站标题、网站图标、加载进度等。

webView.setWebChromeClient(new WebChromeClient() {
    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        // 获得网页的加载进度
        super.onProgressChanged(view, newProgress);
    }
    @Override
    public void onReceivedTitle(WebView view, String title) {
        // 获取网页的title,客户端可以在这里动态修改页面的title
        // 另外,当加载错误时title为“找不到该网页”
        super.onReceivedTitle(view, title);
    }
   @Override
    public final boolean onJsPrompt(WebView view, String url, String message,
                                    String defaultValue, JsPromptResult result) {
        if (view instanceof WebViewSafe) {
            if (handleJsInterface(view, url, message, defaultValue, result)) {
                return true;
            }
        }
    
        return super.onJsPrompt(view, url, message, defaultValue, result);
    }
});

五、与JS交互-addJavascriptInterface

mWebView.getSettings().setJavaScriptEnabled(true);  
mWebView.addJavascriptInterface(new JSInterface(), "jsInterface");  

JSInterface对象:
public class JSInterface {

    @JavascriptInterface
    public void methodA() {    }

    @JavascriptInterface
    public void methodB(String webMessage) {    }
}

六、javaScript 与 Android 代码交互

1. Android 调用javascrpit代码

// 文本名:javascript



   
      
      Carson_Ho
      
// JS代码
     

   



- webView.loadUrl();

loadUrl()方法 执行javaScript 会重新加载页面,效率低

mWebView.loadUrl("javascript:callJS()");
- 通过 wevView的evaluateJavascript()

evaluateJavascript()仅支持4.4以上的Android版本,无法向下兼容。但是onReceiveValue回调中,可以直接返回javaScript的返回值。使用方便,效率高。

// 只需要将第一种方法的loadUrl()换成下面该方法即可
    mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback() {
        @Override
        public void onReceiveValue(String value) {
            //此处为 js 返回的结果
        }
    });
}

JS 调用Android代码

- 通过shouldOverrideUrlLoading回调 拦截webView的 url,调用Android代码。
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 params = new HashMap<>();
                                                  Set collection = uri.getQueryParameterNames();

                                              }

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


- 通过WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回调 拦截 JS对话框alert()、confirm()、prompt() 消息,调用Android代码。


   
      
      Carson_Ho
      
     



   
     
   


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 params = new HashMap<>();
                                                    Set 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);
                                        }
                                    }
        );


            }

        }

- 通过JavaScriptInterface,调用Android 代码。


   
      
      Carson  
      
   
   
      //点击按钮则调用callAndroid函数
      
   


// 继承自Object类
public class AndroidtoJs extends Object {

    // 定义JS需要调用的方法
    // 被JS调用的方法必须加入@JavascriptInterface注解
    @JavascriptInterface
    public void hello(String msg) {
        System.out.println("JS调用了Android的hello方法");
    }
}

// 设置与Js交互的权限
        webSettings.setJavaScriptEnabled(true);

        // 通过addJavascriptInterface()将Java对象映射到JS对象
        //参数1:Java对象名 
        //参数2:Javascript对象名
        mWebView.addJavascriptInterface(new AndroidtoJs(), "test");//AndroidtoJS类对象映射到js的test对象

        // 加载JS代码
        // 格式规定为:file:///android_asset/文件名.html
        mWebView.loadUrl("file:///android_asset/javascript.html");

七、 WebView 漏洞

webViewde 的任意代码执行漏洞,主要有三个原因

  • WebView 中 addJavascriptInterface() 接口。
    解决 办法:
    (1)Android 4.2版本之后
    Google 在Android 4.2 版本中规定对被调用的函数以 @JavascriptInterface进行注解从而避免漏洞攻击
    (2)Android 4.2版本之前
    在Android 4.2版本之前采用拦截prompt()进行漏洞修复。

  • searchBoxJavaBridge_接口引起远程代码执行漏洞
    解决方法:删除searchBoxJavaBridge_接口

// 通过调用该方法删除接口
super.removeJavascriptInterface("searchBoxJavaBridge_");`

  • accessibility和 accessibilityTraversal接口引起远程代码执行漏洞
    删除接口
            super.removeJavascriptInterface("accessibility");
            super.removeJavascriptInterface("accessibilityTraversal");

参考链接:
WebView 常规用法:
https://www.jianshu.com/p/3c94ae673e2a

JS与Android交互
https://www.jianshu.com/p/345f4d8a5cfa

WebView漏洞分析:
https://www.jianshu.com/p/3a345d27cd42

如何点击h5中的图片 触发 Android原生的图片查看器:
https://www.jianshu.com/p/7167ee44cfcd

你可能感兴趣的:(WebView 用法)