WebView 用法

WebView 常用的類

  • WebView
  • WebSettings
  • WebViewClient
  • WebChromeClient
  • addJavascriptInterface

必要權限

<uses-permission android:name="android.permission.INTERNET" />

一、WebView

(1)創(chuàng)建WebView


WebView webview = new WebView(this);

(2)加載url

  • 加載網(wǎng)頁 url地址
webView.loadUrl("http://www.itdecent.cn/")
  • 加載本地asset目錄下的網(wǎng)頁

注意:將index.html 放在asset目錄下

webView.loadUrl("file:///android_asset/html/index.html"); //加載本地assert目錄下網(wǎng)頁
  • 加載Sdcard上的html

(3) 返回和后退

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

二、WebSettings Webview設置類

設置WebView的一些屬性、狀態(tài)等,例如允許使用javascript,允許使用緩存,允許使用內(nèi)置的縮放組件,設置支持IS等

//聲明WebSettings子類
WebSettings webSettings = webView.getSettings();

//如果訪問的頁面中要與Javascript交互,則webview必須設置支持Javascript
webSettings.setJavaScriptEnabled(true);  
// 若加載的 html 里有JS 在執(zhí)行動畫等操作,會造成資源浪費(CPU、電量)
// 在 onStop 和 onResume 里分別把 setJavaScriptEnabled() 給設置成 false 和 true 即可

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

//設置自適應屏幕,兩者合用
webSettings.setUseWideViewPort(true); //將圖片調(diào)整到適合webview的大小 
webSettings.setLoadWithOverviewMode(true); // 縮放至屏幕的大小

//縮放操作
webSettings.setSupportZoom(true); //支持縮放,默認為true。是下面那個的前提。
webSettings.setBuiltInZoomControls(true); //設置內(nèi)置的縮放控件。若為false,則該WebView不可縮放
webSettings.setDisplayZoomControls(false); //隱藏原生的縮放控件

//其他細節(jié)操作
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);
        // 這里進行無網(wǎng)絡或錯誤處理,具體可以根據(jù)errorCode的值進行判斷,
    }
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        view.loadUrl(url);
        /**
         * 網(wǎng)頁跳轉:
         * 1.在當前的webview跳轉到新連接
         * view.loadUrl(url);
         * 2.調(diào)用系統(tǒng)瀏覽器跳轉到新網(wǎng)頁
         * Intent i = new Intent(Intent.ACTION_VIEW);
         * i.setData(Uri.parse(url));
         * startActivity(i);
         */
        return true;
    }
});

四、WebChromeClient

輔助處理 javaScript的各種對話框、網(wǎng)站標題、網(wǎng)站圖標、加載進度等。

webView.setWebChromeClient(new WebChromeClient() {
    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        // 獲得網(wǎng)頁的加載進度
        super.onProgressChanged(view, newProgress);
    }
    @Override
    public void onReceivedTitle(WebView view, String title) {
        // 獲取網(wǎng)頁的title,客戶端可以在這里動態(tài)修改頁面的title
        // 另外,當加載錯誤時title為“找不到該網(wǎng)頁”
        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 調(diào)用javascrpit代碼

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

   <head>
      <meta charset="utf-8">
      <title>Carson_Ho</title>
      
// JS代碼
     <script>
// Android需要調(diào)用的方法
   function callJS(){
      alert("Android調(diào)用了JS的callJS方法");
   }
</script>

   </head>

</html>

- webView.loadUrl();

loadUrl()方法 執(zhí)行javaScript 會重新加載頁面,效率低

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

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

// 只需要將第一種方法的loadUrl()換成下面該方法即可
    mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
        @Override
        public void onReceiveValue(String value) {
            //此處為 js 返回的結果
        }
    });
}

JS 調(diào)用Android代碼

- 通過shouldOverrideUrlLoading回調(diào) 攔截webView的 url,調(diào)用Android代碼。
mWebView.setWebViewClient(new WebViewClient() {
                                      @Override
                                      public boolean shouldOverrideUrlLoading(WebView view, String url) {

                                          // 步驟2:根據(jù)協(xié)議的參數(shù),判斷是否是所需要的url
                                          // 一般根據(jù)scheme(協(xié)議格式) & authority(協(xié)議名)判斷(前兩個參數(shù))
                                          //假定傳入進來的 url = "js://webview?arg1=111&arg2=222"(同時也是約定好的需要攔截的)

                                          Uri uri = Uri.parse(url);                                 
                                          // 如果url的協(xié)議 = 預先約定的 js 協(xié)議
                                          // 就解析往下解析參數(shù)
                                          if ( uri.getScheme().equals("js")) {

                                              // 如果 authority  = 預先約定協(xié)議里的 webview,即代表都符合約定的協(xié)議
                                              // 所以攔截url,下面JS開始調(diào)用Android需要的方法
                                              if (uri.getAuthority().equals("webview")) {

                                                 //  步驟3:
                                                  // 執(zhí)行JS所需要調(diào)用的邏輯
                                                  System.out.println("js調(diào)用了Android的方法");
                                                  // 可以在協(xié)議上帶有參數(shù)并傳遞到Android上
                                                  HashMap<String, String> params = new HashMap<>();
                                                  Set<String> collection = uri.getQueryParameterNames();

                                              }

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


- 通過WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()方法回調(diào) 攔截 JS對話框alert()、confirm()、prompt() 消息,調(diào)用Android代碼。
<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <title>Carson_Ho</title>
      
     <script>
        
    function clickprompt(){
    // 調(diào)用prompt()
    var result=prompt("js://demo?arg1=111&arg2=222");
    alert("demo " + result);
}

      </script>
</head>

<!-- 點擊按鈕則調(diào)用clickprompt()  -->
   <body>
     <button type="button" id="button1" onclick="clickprompt()">點擊調(diào)用Android代碼</button>
   </body>
</html>

mWebView.setWebChromeClient(new WebChromeClient() {
                                        // 攔截輸入框(原理同方式2)
                                        // 參數(shù)message:代表promt()的內(nèi)容(不是url)
                                        // 參數(shù)result:代表輸入框的返回值
                                        @Override
                                        public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
                                            // 根據(jù)協(xié)議的參數(shù),判斷是否是所需要的url(原理同方式2)
                                            // 一般根據(jù)scheme(協(xié)議格式) & authority(協(xié)議名)判斷(前兩個參數(shù))
                                            //假定傳入進來的 url = "js://webview?arg1=111&arg2=222"(同時也是約定好的需要攔截的)

                                            Uri uri = Uri.parse(message);
                                            // 如果url的協(xié)議 = 預先約定的 js 協(xié)議
                                            // 就解析往下解析參數(shù)
                                            if ( uri.getScheme().equals("js")) {

                                                // 如果 authority  = 預先約定協(xié)議里的 webview,即代表都符合約定的協(xié)議
                                                // 所以攔截url,下面JS開始調(diào)用Android需要的方法
                                                if (uri.getAuthority().equals("webview")) {

                                                    //
                                                    // 執(zhí)行JS所需要調(diào)用的邏輯
                                                    System.out.println("js調(diào)用了Android的方法");
                                                    // 可以在協(xié)議上帶有參數(shù)并傳遞到Android上
                                                    HashMap<String, String> params = new HashMap<>();
                                                    Set<String> collection = uri.getQueryParameterNames();

                                                    //參數(shù)result:代表消息框的返回值(輸入值)
                                                    result.confirm("js調(diào)用了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,調(diào)用Android 代碼。
<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8">
      <title>Carson</title>  
      <script>
         
        
         function callAndroid(){
        // 由于對象映射,所以調(diào)用test對象等于調(diào)用Android映射的對象
            test.hello("js調(diào)用了android中的hello方法");
         }
      </script>
   </head>
   <body>
      //點擊按鈕則調(diào)用callAndroid函數(shù)
      <button type="button" id="button1" onclick="callAndroid()"></button>
   </body>
</html>

// 繼承自Object類
public class AndroidtoJs extends Object {

    // 定義JS需要調(diào)用的方法
    // 被JS調(diào)用的方法必須加入@JavascriptInterface注解
    @JavascriptInterface
    public void hello(String msg) {
        System.out.println("JS調(diào)用了Android的hello方法");
    }
}

// 設置與Js交互的權限
        webSettings.setJavaScriptEnabled(true);

        // 通過addJavascriptInterface()將Java對象映射到JS對象
        //參數(shù)1:Java對象名 
        //參數(shù)2:Javascript對象名
        mWebView.addJavascriptInterface(new AndroidtoJs(), "test");//AndroidtoJS類對象映射到js的test對象

        // 加載JS代碼
        // 格式規(guī)定為:file:///android_asset/文件名.html
        mWebView.loadUrl("file:///android_asset/javascript.html");

七、 WebView 漏洞

webViewde 的任意代碼執(zhí)行漏洞,主要有三個原因

  • WebView 中 addJavascriptInterface() 接口。
    解決 辦法:
    (1)Android 4.2版本之后
    Google 在Android 4.2 版本中規(guī)定對被調(diào)用的函數(shù)以 @JavascriptInterface進行注解從而避免漏洞攻擊
    (2)Android 4.2版本之前
    在Android 4.2版本之前采用攔截prompt()進行漏洞修復。

  • searchBoxJavaBridge_接口引起遠程代碼執(zhí)行漏洞
    解決方法:刪除searchBoxJavaBridge_接口

// 通過調(diào)用該方法刪除接口
super.removeJavascriptInterface("searchBoxJavaBridge_");`

  • accessibility和 accessibilityTraversal接口引起遠程代碼執(zhí)行漏洞
    刪除接口
            super.removeJavascriptInterface("accessibility");
            super.removeJavascriptInterface("accessibilityTraversal");

參考鏈接:
WebView 常規(guī)用法:
http://www.itdecent.cn/p/3c94ae673e2a

JS與Android交互
http://www.itdecent.cn/p/345f4d8a5cfa

WebView漏洞分析:
http://www.itdecent.cn/p/3a345d27cd42

如何點擊h5中的圖片 觸發(fā) Android原生的圖片查看器:
http://www.itdecent.cn/p/7167ee44cfcd

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容