1. 程式人生 > >webview最全面總結(二)全面介紹webview用法

webview最全面總結(二)全面介紹webview用法

簡單介紹

為了方便開發者實現在app內展示網頁並與網頁互動的需求,Android SDK提供了WebView元件
它有如下功能:

  • 顯示和渲染Web頁面
  • 直接使用html檔案(網路上或本地assets中)作佈局
  • 可和JavaScript互動呼叫
  • WebView控制元件功能強大,除了具有一般View的屬性和設定外,還可以對url請求、頁面載入、渲染、頁面互動進行強大的處理。

基本使用

下面簡單介紹下WebView的基本使用:

首先新建一個工程,在layout檔案裡放入一個WebView控制元件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <WebView android:id="@+id/webview1" android:layout_width="match_parent"
android:layout_height="match_parent">
</WebView> </RelativeLayout>

然後在Activity初始化方法裡寫入如下程式碼:

  String url = "https://www.kkj.cn";

  WebView webView = (WebView) findViewById(R.id.web_view);
  webView.loadUrl(url);
  WebSettings webSettings = webview.getSettings();  
  webSettings.setJavaScriptEnabled
(true); webSettings.setJavaScriptCanOpenWindowsAutomatically(true);

不要忘了在AndroidManifest宣告訪問網路的許可權:

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

然後bingo執行,我們會發現,納尼,居然在外部的預設瀏覽器中打開了這個連結。

因為預設情況下,一個WebView提供的是不像瀏覽器的控制元件,沒有開啟JavaScript並且忽略網頁錯誤。如果你的目的是僅僅顯示一些HTML作為你的UI的一部分,那顯示可能是沒有問題的(顯示正常),使用者僅僅閱讀網頁而不需要與之互動,並且網頁也不需要和使用者互動。

如果你想要在webview內部開啟,則需要自定義WebChromeClient 方法。
一般我們重寫最多的就是shouldOverrideUrlLoading()、onPageStarted()、onPageFinished()問題。

webview.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {

             return false;
            }
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                //webview頁面載入開始時就會執行此方法、一般用作重定向時的初始化工作
                //該方法在WebView開始載入頁面且僅在Main frame loading(即整頁載入)時回撥,一次Main frame的載入只會回撥該方法一次。我們可以在這個方法裡設定開啟一個載入的動畫,告訴使用者程式在等待網路的響應。
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                //該方法只在WebView完成一個頁面載入時呼叫一次(同樣也只在Main frame loading時呼叫),我們可以可以在此時關閉載入動畫,進行其他操作。

            }
        });

這樣重寫之後,我們就能在webview裡面開啟我們想要開啟的頁面了。然而,我們發現,當我們在我們開啟頁面的頁面中繼續跳轉時候,再按系統返回鍵,會發現,直接關閉了webview,這顯然不是我們想要的結果。

  @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        //這是一個監聽用的按鍵的方法,keyCode 監聽使用者的動作,如果是按了返回鍵,同時Webview要返回的話,WebView執行回退操作,因為mWebView.canGoBack()返回的是一個Boolean型別,所以我們把它返回為true
        if(keyCode==KeyEvent.KEYCODE_BACK&&webview.canGoBack()){
            webview.goBack();
            return true;
        }

        return super.onKeyDown(keyCode, event);
    }

重寫返回鍵之後就能實現,在網頁中返回上一步。

詳細看一下webview的各個知識點。

載入方式

1、loadUrl(String url)

用的最多的載入方式,

des:Load the given url.
as: webView.loadUrl(“http://www.kkj.cn/“); //載入網路網頁
webView.loadUrl(“file:///android_asset/html/index.html”); //載入本地assert目錄下網頁
webView.loadUrl(“content://com.Android.htmlfileprovider/sdcard/kris.html”); // 載入SD卡html

2、loadData(String data, String mimeType, String encoding)
des:Load the given data into the WebView.
as:
String summary = “You scored 192 points.”;
webview.loadData(summary, “text/html”, null);
如果後臺給的資料是包含html的字串,則需要用這種方式進行載入,這種方式省流量,速度快,但是需要注意編碼問題。
loadData()中的html data不能包含’#’,’%’,’\’,’?’四種特殊字元

3、loadDataWithBaseURL(String baseUrl, String data, String mimeType, String encoding, String historyUrl)

des:Load the given data into the WebView, use the provided URL as the base URL for the content.

webview的設定

    WebSettings webSettings = webview.getSettings();

    //支援js事件
    webSettings.setJavaScriptEnabled(true);
    /* 設定為true表示支援使用js開啟新的視窗 */
    webSettings.setJavaScriptCanOpenWindowsAutomatically(true);

    /* 設定為使用webview推薦的視窗 */
    webSettings.setUseWideViewPort(true);
    /* 設定網頁自適應螢幕大小 ---這個屬性應該是跟上面一個屬性一起用 */
    webSettings.setLoadWithOverviewMode(true);

    /* 設定是否允許webview使用縮放的功能,我這裡設為false,不允許 */
    webSettings.setBuiltInZoomControls(false);
    webSettings.setBuiltInZoomControls(true); //顯示或不顯示縮放按鈕(wap網頁不支援)。
    webSettings.setSupportMultipleWindows(true);//設定WebView是否支援多視窗。

    webSettings.setAppCacheEnabled(true); //啟用或禁用應用快取。
    webSettings.setAppCachePath("");//設定應用快取路徑,這個路徑必須是可以讓app寫入檔案的。該方法應該只被呼叫一次,重複呼叫會被無視~
    webSettings.setCacheMode(LOAD_DEFAULT);//用來設定WebView的快取模式。當我們載入頁面或從上一個頁面返回的時候,會按照設定的快取模式去檢查並使用(或不使用)快取。

篇幅限制,僅列了一些最常用的設定,webview還可以設定更多內容,儲存,預設字型大小,預設字元編碼等等,
具體可以參考,史上最全的WebSettings說明

  對於webview也有
    webView.setHorizontalScrollBarEnabled(false);//水平不顯示  
    webView.setVerticalScrollBarEnabled(false); //垂直不顯示   
    webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);// 隱藏滾動條 
    webView.requestFocus();      設定是否獲取焦點    
    webView.requestFocusFromTouch();  

WebViewClient

主要幫助WebView處理各種通知、請求事件(例如,點選連結時候如何顯示介面,頁面開始載入,載入完畢之後

webview.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
             return false;
            }
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                //webview頁面載入開始時就會執行此方法、一般用作重定向時的初始化工作
                //該方法在WebView開始載入頁面且僅在Main frame loading(即整頁載入)時回撥,一次Main frame的載入只會回撥該方法一次。我們可以在這個方法裡設定開啟一個載入的動畫,告訴使用者程式在等待網路的響應。
            }
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                //該方法只在WebView完成一個頁面載入時呼叫一次(同樣也只在Main frame loading時呼叫),我們可以可以在此時關閉載入動畫,進行其他操作。
            }
            @Override
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                 super.onReceivedError(view, errorCode, description, failingUrl);
        // 這裡進行無網路或錯誤處理,具體可以根據errorCode的值進行判斷,
    }

shouldOverrideUrlLoading()方法分析

從實踐中我們知道,當我們沒有給WebView提供WebViewClient時,WebView如果要載入一個url會向ActivityManager尋求一個適合的處理者來載入該url(比如系統自帶的瀏覽器),這通常是我們不想看到的。於是我們需要給WebView提供一個WebViewClient,並重寫該方法返回true來告知WebView url的載入就在app中進行。這時便可以實現在app內訪問網頁
簡單來說就是:

1、若沒有設定 WebViewClient 則在點選連結之後由系統處理該 url,通常是使用瀏覽器開啟或彈出瀏覽器選擇對話方塊。
2、若設定 WebViewClient 且該方法返回 true ,則說明由應用的程式碼處理該 url,WebView 不處理。
3、若設定 WebViewClient 且該方法返回 false,則說明由 WebView 處理該 url,即用 WebView 載入該 url。

WebChromeClient

輔助WebView處理Javascript的對話方塊、網站圖示、網站Title、載入進度等

webView.setWebChromeClient(new WebChromeClient() {
    @Override
    public void onProgressChanged(WebView view, int newProgress) {
        // 獲得網頁的載入進度 newProgress為當前載入百分比
        super.onProgressChanged(view, newProgress);
    }
    @Override
    public void onReceivedTitle(WebView view, String title) {
        // 獲取網頁的title,客戶端可以在這裡動態修改頁面的title
        // 另外,當載入錯誤時title為“找不到該網頁”
        super.onReceivedTitle(view, title);
    }
});

js的互動

webView.addJavascriptInterface()

通過addJavascriptInterface(Object, String)方法注入Java物件到WebView。這個方法允許你注入一個Java物件到網頁的JavaScript 的上下文,以便通過頁面中的JavaScript呼叫。

簡單粗暴時候可以這樣寫:

myWebView.addJavascriptInterface(new JSInterface(){                    
    @JavascriptInterface 
    public String methodA(){
            return ((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).getDeviceId();
        }

   @JavascriptInterface
    public void methodB(String webMessage) {    }
    }, "Android");

方法可能會很多,所以我們要學會優雅一些;

mWebView.addJavascriptInterface(new JSInterface(), "Android");  //model是自定義的,隨便起。
JSInterface物件:
public class JSInterface {

    @JavascriptInterface
    public void methodA() {    }

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

ps:SDK>=17(Android4.2)以上,必須新增@JavascriptInterface宣告,為避免因使用者訪問不安全網頁導致js漏洞盜竊使用者資訊等不安全行為。

js調java:

Java物件到WebView之後,我們要在js裡面呼叫 java方法。

所有呼叫的方法都要寫在class JSInterface{ }中。

funtion a{
      winow.Android.methodA();   //可帶引數
}

java調js:

在webview裡面呼叫js方法:

  webview.loadUrl("javascript:alert()"); 

前進後退重新整理

webview是否可以返回到上一頁面 webView.canGoBack()

webview返回到上一頁面 webView.goBack();

webview是否可以前進 webView.canGoForward()

webview前進 webView.goForward();

webview.reload(); 重新整理

舉個回退的簡單例子簡單說明

public boolean onKeyDown(int keyCode, KeyEvent event) {
     if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
         mWebView.goBack();
         return true;
     }
     return super.onKeyDown(keyCode, event);
 }

判斷Webview是否滑動到頂部或底部

if (webView.getContentHeight() * webView.getScale() == (webView.getHeight() + webView.getScrollY())) {
    // 處於底端
}
if(webView.getScrollY() == 0){
    //處於頂部
}

getScrollY() //方法返回的是當前可見區域的頂端距整個頁面頂端的距離,也就是當前內容滾動的距離.
getHeight()或者getBottom() //方法都返回當前WebView這個容器的高度
getContentHeight()返回的是整個html的高度,但並不等同於當前整個頁面的高度,因為WebView有縮放功能,所以當前整個頁面的高度實際上應該是原始html的高度再乘上縮放比例

webView的狀態

//當應用程式(存在webview)被切換到後臺時,這個方法不僅僅針對當前的webview而是全域性的全應用程式的webview
//它會暫停所有webview的layout,parsing,javascripttimer。降低CPU功耗。


@Override
    protected void onPause() {
       webview.onPause();
       webview.pauseTimers();
       super.onPause();
    }
 @Override
    protected void onResume() {
       webview.onResume();//重新啟用WebView為活躍狀態,響應網頁
       webview.resumeTimers();//恢復pauseTimers狀態
       super.onResume();
    //當頁面被失去焦點被切換到後臺不可見狀態,需要執行onPause
  //通過onPause動作通知核心暫停所有的動作,比如DOM的解析、plugin的執行、JavaScript執行。
    }

//銷燬Webview
//在關閉了Activity時,如果Webview的音樂或視訊,還在播放。就必須銷燬Webview
//但是注意:webview呼叫destory時,webview仍繫結在Activity上
//這是由於自定義webview構建時傳入了該Activity的context物件
//因此需要先從父容器中移除webview,然後再銷燬webview:
rootLayout.removeView(webView); 
webView.destroy();
    @Override  
    public void onDestroy() {  
        if (mWebView != null) {  
            mWebView.destroy();  
            mWebView = null;  
        }  
        super.onDestroy();  
    }  

webview快取

 webview的快取有四種模式,根據自己的需要選擇對應的快取模式。
       WebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); 
        //快取模式如下:
        //LOAD_CACHE_ONLY: 不使用網路,只讀取本地快取資料
        //LOAD_DEFAULT: (預設)根據cache-control決定是否從網路上取資料。
        //LOAD_NO_CACHE: 不使用快取,只從網路獲取資料.
        //LOAD_CACHE_ELSE_NETWORK,只要本地有,無論是否過期,或者no-cache,都使用快取中的資料。

快取運用:

if (NetStatusUtil.isConnected(getApplicationContext())) {
    webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);//根據cache-control決定是否從網路上取資料。
} else {
    webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);//沒網,則從本地獲取,即離線載入
}
//使用快取需要開啟這些webview的設定,並且設定快取路徑
webSettings.setDomStorageEnabled(true); // 開啟 DOM storage API 功能
webSettings.setDatabaseEnabled(true);   //開啟 database storage API 功能
webSettings.setAppCacheEnabled(true);//開啟 Application Caches 功能

String cacheDirPath = getFilesDir().getAbsolutePath() + APP_CACAHE_DIRNAME;
webSettings.setAppCachePath(cacheDirPath); //設定  Application Caches 快取目錄

清除快取:

clearCache(true);   //清除網頁訪問留下的快取,由於核心快取是全域性的因此這個方法不僅僅針對webview而是針對整個應用程式.
clearHistory ()  //清除當前webview訪問的歷史記錄,只會webview訪問歷史記錄裡的所有記錄除了當前訪問記錄.
clearFormData ()  //這個api僅僅清除自動完成填充的表單資料,並不會清除WebView儲存到本地的資料。