1. 程式人生 > >WebView使用解析(二)之WebViewClient/WebChromeClient

WebView使用解析(二)之WebViewClient/WebChromeClient

WebViewClient—–在影響View的事件到來時,會通過WebViewClient中的方法回撥通知使用者。
WebChromeClient—–當影響瀏覽器的事件到來時,就會通過WebChromeClient中的方法回撥通知用法。
通過上面的對比,我們發現WebViewClient和WebChromeClient都是針對不同事件的回撥,而google將這些回撥進行分類集合,就產生了WebViewClient、WebChromeClient這兩個大類,其中管理著針對不同型別的回撥而已。

WebViewClient

WebViewClient中函式概述:

/**
 * 在開始載入網頁時會回撥
 */
public void onPageStarted(WebView view, String url, Bitmap favicon) /** * 在結束載入網頁時會回撥 */ public void onPageFinished(WebView view, String url) /** * 攔截 url 跳轉,在裡邊新增點選連結跳轉或者操作 */ public boolean shouldOverrideUrlLoading(WebView view, String url) /** * 載入錯誤的時候會回撥,在其中可做錯誤處理,比如再請求載入一次,或者提示404的錯誤頁面 */ public void onReceivedError(WebView view, int errorCode,String description, String failingUrl) /** * 當接收到https錯誤時,會回撥此函式,在其中可以做錯誤處理 */
public void onReceivedSslError(WebView view, SslErrorHandler handler,SslError error) /** * 在每一次請求資源時,都會通過這個函式來回調 */ public WebResourceResponse shouldInterceptRequest(WebView view, String url) { return null; }

我們一個個來看:

1. WebViewClient之onPageStarted與onPageFinished

onPageStarted:通知主程式頁面當前開始載入。
onPageFinished:通知主程式頁面載入結束。

舉個例子:開始載入時顯示載入圓圈,結束載入時隱藏載入圓圈。

public class MainActivity extends Activity {
    private WebView mWebView;

    private ProgressDialog mProgressDialog;
    private String TAG = "watson";
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView = (WebView)findViewById(R.id.webview);
        mProgressDialog = new ProgressDialog(this);
        mWebView.getSettings().setJavaScriptEnabled(true);

        mWebView.loadUrl("http://blog.csdn.net/huaxun66");
        mWebView.setWebViewClient(new WebViewClient(){

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                mWebView.loadUrl(url);
                return true;
            }

            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                mProgressDialog.show();
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                mProgressDialog.hide();
            }
        });
    }
}

從圖中可以看出,在載入頁面的時候會顯示圓形載入框,在載入成功以後會隱藏載入框。
這裡寫圖片描述

2. WebViewClient之shouldOverrideUrlLoading

(1)如何在WebView中載入線上網址
上篇文章也說過,如果要在WebView中載入線上網址,必須重寫WebViewClient,其實給webview設定一個空的WebViewClient物件即可,沒必要重寫WebViewClient的方法。使用它的預設回撥就可以實現在WebView中載入線上URL了:

mWebView.setWebViewClient(new WebViewClient());

(2)shouldOverrideUrlLoading用途
由於每次超連結在載入前都會先走shouldOverrideUrlLoading回撥,所以我們如果想攔截某個URL,將其轉換成其它URL可以在這裡做。
比如,我們攔截所有包含“blog.csdn.net”的地址,將其替換成”www.baidu.com”:

mWebView.setWebViewClient(new WebViewClient(){
     @Override
     public boolean shouldOverrideUrlLoading(WebView view, String url) {
            if (url.contains("blog.csdn.net")){
                 view.loadUrl("http://www.baidu.com");
            }
            return false;
      }
});

效果圖如下:
這裡寫圖片描述

這裡需要非常注意的是:返回值是boolean型別,表示是否遮蔽WebView繼續載入URL的預設行為。因為這個函式是WebView載入URL前回調的,所以如果我們return true,則WebView接下來就不會再載入這個URL了。如果我們return false,則系統就認為上層沒有做處理,接下來還是會繼續載入這個URL的。WebViewClient預設就是return false的。
一般建議大家return false,我們只關心我們關心的攔截內容,對於不攔截的內容,讓系統自己來處理即可。就像我們上面的程式碼。

3. WebViewClient之onReceivedError
onReceivedError的完整宣告如下:

public void onReceivedError(WebView view, int errorCode,String description, String failingUrl)

載入錯誤的時候會產生這個回撥,在其中可做錯誤處理,比如我們可以載入一個錯誤提示頁面
這裡有四個引數:

  • WebView view:當前的WebView例項
  • int errorCode:錯誤碼
  • String description:錯誤描述
  • String failingUrl:當前出錯的URL

我們可以先寫一個錯誤提示的本地頁面:(error.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1 id="h">出錯了……</h1>
</body>
</html>

然後在載入返回錯誤時,重新載入錯誤頁面:

mWebView.setWebViewClient(new WebViewClient(){
    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
        super.onReceivedError(view, errorCode, description, failingUrl);
        mWebView.loadUrl("file:///android_asset/error.html");
    }
});

最後讓webview載入一個錯誤的URL。

這裡寫圖片描述

4.WebViewClient之onReceivedSslError
我們知道HTTPS協議是通過SSL來通訊的,所以當使用HTTPS通訊的網址(以https://開頭的網站)出現錯誤時,就會通過onReceivedSslError回撥通知過來,它的函式宣告為:

/**
 * 當接收到https錯誤時,會回撥此函式,在其中可以做錯誤處理
 */
public void onReceivedSslError(WebView view, SslErrorHandler handler,SslError error)
  • WebView view:當前的WebView例項
  • SslErrorHandler handler:當前處理錯誤的Handler,它只有兩個函式SslErrorHandler.proceed()和SslErrorHandler.cancel(),SslErrorHandler.proceed()表示忽略錯誤繼續載入,SslErrorHandler.cancel()表示取消載入。在onReceivedSslError的預設實現中是使用的SslErrorHandler.cancel()來取消載入,所以一旦出來SSL錯誤,HTTPS網站就會被取消載入了,如果想忽略錯誤繼續載入就只有重寫onReceivedSslError,並在其中呼叫SslErrorHandler.proceed()
  • SslError error:當前的的錯誤物件,SslError包含了當前SSL錯誤的基本所有資訊

預設載入SSL出錯的網站——出現空白頁面
12306是通過Https協議來傳輸的,但是它的SSL證書不是CA頒發的,不被我們APP認可,所以我們就以12306網站為例:

public class MainActivity extends Activity {
    private WebView mWebView;
    private String TAG = "watson";
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWebView = (WebView)findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);

        mWebView.loadUrl("https://www.12306.cn/");
        mWebView.setWebViewClient(new WebViewClient(){
            @Override
            public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
                super.onReceivedSslError(view, handler, error);
            }
        });
    }
}

在這裡僅僅重寫onReceivedSslError,並呼叫super.onReceivedSslError(view, handler, error);來呼叫預設的處理方式。發現頁面顯示空白。

我們修改一下程式碼:

public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
//      一定要註釋掉!    
//      super.onReceivedSslError(view, handler, error);
        handler.proceed();
}

這裡做了兩個改變:
第一:註釋掉super.onReceivedSslError(view, handler, error);,取消系統的預設行為,我們看原始碼,可以發現WebViewClient中onReceivedSslError的預設實現是handler.cancel(); 即取消繼續載入。
第二:呼叫handler.proceed();來忽略錯誤繼續載入頁面。

所以此時的效果圖為:
這裡寫圖片描述

對於onReceivedSslError結論:
1.當出現SSL錯誤時,WebView預設是取消載入當前頁面,只有去掉onReceivedSslError的預設操作,然後新增SslErrorHandler.proceed()才能繼續加載出錯頁面
2.當HTTPS傳輸出現SSL錯誤時,錯誤會只通過onReceivedSslError回撥傳過來,不會執行onReceivedError

5. WebViewClient之shouldInterceptRequest
在每一次請求資源時,都會通過這個函式來回調,比如超連結、JS檔案、CSS檔案、圖片等,也就是說瀏覽器中每一次請求資源時,都會回調回來,無論任何資源!但是必須注意的是shouldInterceptRequest函式是在非UI執行緒中執行的,在其中不能直接做UI操作,如果需要做UI操作,則需要利用Handler來實現,該函式宣告如下:

public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
    return null;
}

該函式會在請求資源前呼叫,我們可以通過返回WebResourceResponse的處理結果來讓WebView直接使用我們的處理結果。如果我們不想處理,則直接返回null,系統會繼續載入該資源。
利用這個特性,我們可以解決一個需求:假如網頁中需要載入本地的圖片,我們就可以通過攔截shouldInterceptRequest,並返回結果即可 。
比如下面的一段HTML程式碼中,img欄位載入圖片的地址是:http://localhost/android.png,這是我自定義的一個網址,在Android中,當發現要載入這個地址的資源時,我們將它換成本地的圖片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1 id="h">WebView使用解析</h1>
    <img src="http://localhost/android.png"/>
</body>
</html>
public class MainActivity extends Activity {
    private WebView mWebView;
    private String TAG = "watson";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);

        mWebView.setWebViewClient(new WebViewClient() {
            @Override
            public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
                try {
                    if (url.equals("http://localhost/android.png")) {
                        AssetFileDescriptor fileDescriptor = getAssets().openFd("qqq.jpg");
                        InputStream stream = fileDescriptor.createInputStream();
                        WebResourceResponse response = new WebResourceResponse("image/png", "UTF-8", stream);
                        return response;
                    }
                } catch (Exception e) {
                    Log.e(TAG, e.getMessage());
                }
                return super.shouldInterceptRequest(view, url);
            }
        });
        mWebView.loadUrl("file:///android_asset/web.html");
    }
}

這裡程式碼比較容易理解,當發現當前載入資源的url是我們自定義的http://localhost/android.jpg時,就直接將本地的圖片qqq.jpg作為結果返回。
這裡寫圖片描述

6. WebViewClient之其餘函式

/**
 * 在載入頁面資源時會呼叫,每一個資源(比如圖片)的載入都會呼叫一次
 */
public void onLoadResource(WebView view, String url) 
 /**
 *  (WebView發生改變時呼叫) 
 *  可以參考http://www.it1352.com/191180.html的用法
 */
 public void onScaleChanged(WebView view, float oldScale, float newScale)
 /**
 * 重寫此方法才能夠處理在瀏覽器中的按鍵事件。
 * 是否讓主程式同步處理Key Event事件,如過濾選單快捷鍵的Key Event事件。
 * 如果返回true,WebView不會處理Key Event,
 * 如果返回false,Key Event總是由WebView處理。預設:false
 */
public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event)
 /**
 * 是否重發POST請求資料,預設不重發。
 */
onFormResubmission(WebView view, Message dontResend, Message resend)
 /**
 * 更新訪問歷史
 */
doUpdateVisitedHistory(WebView view, String url, boolean isReload)
 /**
 * 通知主程式輸入事件不是由WebView呼叫。是否讓主程式處理WebView未處理的Input Event。
 * 除了系統按鍵,WebView總是消耗掉輸入事件或shouldOverrideKeyEvent返回true。
 * 該方法由event 分發非同步呼叫。注意:如果事件為MotionEvent,則事件的生命週期只存在方法呼叫過程中,
 * 如果WebViewClient想要使用這個Event,則需要複製Event物件。
 */
onUnhandledInputEvent(WebView view, InputEvent event)
 /**
 * 通知主程式執行了自動登入請求。
 */
onReceivedLoginRequest(WebView view, String realm, String account, String args)
/**
 * 通知主程式:WebView接收HTTP認證請求,主程式可以使用HttpAuthHandler為請求設定WebView響應。預設取消請求。
 */
onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm)
/**
 * 通知主程式處理SSL客戶端認證請求。如果需要提供金鑰,主程式負責顯示UI介面。
 * 有三個響應方法:proceed(), cancel() 和 ignore()。
 * 如果呼叫proceed()和cancel(),webview將會記住response,
 * 對相同的host和port地址不再呼叫onReceivedClientCertRequest方法。
 * 如果呼叫ignore()方法,webview則不會記住response。該方法在UI執行緒中執行,
 * 在回撥期間,連線被掛起。預設cancel(),即無客戶端認證
 */
onReceivedClientCertRequest(WebView view, ClientCertRequest request)

WebChromeClient

WebChromeClient的常用函式:

/**
 * 當網頁呼叫alert()來彈出alert彈出框前回調,用以攔截alert()函式
 */
public boolean onJsAlert(WebView view, String url, String message,JsResult result)
/**
 * 當網頁呼叫confirm()來彈出confirm彈出框前回調,用以攔截confirm()函式
 */
public boolean onJsConfirm(WebView view, String url, String message,JsResult result)
/**
 * 當網頁呼叫prompt()來彈出prompt彈出框前回調,用以攔截prompt()函式
 */
 public boolean onJsPrompt(WebView view, String url, String message,String defaultValue, JsPromptResult result) 
 /**
 * 列印 console 資訊
 */
 public boolean onConsoleMessage(ConsoleMessage consoleMessage)
 /**
 * 通知程式當前頁面載入進度
 */
 public void onProgressChanged(WebView view, int newProgress)

1. WebChromeClient之onJsAlert、onJsConfirm、onJsPrompt

我們把這三個函式一起看,因為他們都是為了處理彈出框。

(1)、為何JS中的alert()、confirm()、prompt()無效
首先,我們來舉個例子,在網頁中加上按鈕,在點選時分別呼叫alert()、confirm()、prompt()來彈出不同的對話方塊 。
web.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 id="h">WebView使用解析</h1>
<button onclick="confirm('confirm文字')">confirm</button>
<button onclick="alert('alert文字')">alert</button>
<button onclick="prompt('prompt文字')">prompt</button>
</body>
</html>

JAVA

public class MainActivity extends Activity {
    private WebView mWebView;
    private String TAG = "watson";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new WebViewClient());
        mWebView.loadUrl("file:///android_asset/web.html");
    }
}

這裡寫圖片描述
從效果圖中,雖然啟用了JavaScript但是在網頁中的confrim()、alert()、prompt()卻是沒有效果!
我們只需要在程式中加上一句話就可以實現confrim()、alert()、prompt()的彈出效果了 。

mWebView.setWebChromeClient(new WebChromeClient());

這裡寫圖片描述

(2)使用onJsAlert攔截alert()函式概述
複寫onJsAlert函式:

mWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
                Toast.makeText(MainActivity.this,"onJsAlert message="+message,Toast.LENGTH_SHORT).show();
                result.confirm();
                return true;
            }
        });

這三句話,句句非常重要:
第一句:

Toast.makeText(MainActivity.this,"onJsAlert message="+message,Toast.LENGTH_SHORT).show();

表示我們攔截html中alert函式之後,做我們自己的操作,這裡是彈出一行toast。
第二句:

result.confirm();

這句話非常重要,它表示向WebView通知操作結果,JsResult有兩個函式:JsResult.confirm()和JsResult.cancel(),JsResult.confirm()相當於點選了彈出框的確定按鈕,JsResult.cancel()則相當於點選了彈出框的取消按鈕。
如果沒有使用JsResult來告訴WebView處理結果,則WebView就會認為這個彈出框還一直彈在那裡,你再點選alert按鈕,將會無效;
第三句:

return true;

表示告訴WebView我們已經攔截了alert()函式,不需要再彈出網頁中的alert彈出框了,如果我們return false,那麼WebView就會認為我們沒有攔截alert()函式,會繼續彈出alert對話方塊。

有關confrim()和prompt()的攔截,我們就不再講了,與攔截alert()一樣!

2、WebChromeClient之onConsoleMessage

當html中呼叫console相關輸出的時候,就會通過onConsoleMessage進行通知

public boolean onConsoleMessage(ConsoleMessage consoleMessage)

引數意義:

  • ConsoleMessage consoleMessage:儲存著當前訊息的型別和訊息內容返回值:如果返回true時,就表示攔截了console輸出,系統就不再通過console輸出出來了,如果返回false則表示沒有攔截console輸出,呼叫系統預設處理。

我們來看下正常情況下,console輸出的內容及用法
先來看html內容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 id="h">WebView使用解析</h1>
<button onclick="log()">log</button>
</body>
<script type="text/javascript">
function log(){
  console.log("console.log");
  console.warn("warnning");
  console.error("error");
}
</script>
</html>

JAVA程式碼:

public class MainActivity extends Activity {
    private WebView mWebView;
    private String TAG = "watson";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new WebViewClient());
        mWebView.loadUrl("file:///android_asset/web.html");
    }
}

除了alert,prompt,confirm以外,其它時候都不需要強制設定WebChromeClient 。
當點選log按鈕時,會呼叫console的函式把log輸出出來
logcat中可以看到如下日誌:
這裡寫圖片描述

下面我們就重寫WebChromeClient的onConsoleMessage方法,把console訊息攔截掉,然後把訊息利用toast彈出來:

mWebView.setWebChromeClient(new WebChromeClient(){
            @Override
            public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
                Toast.makeText(MainActivity.this,consoleMessage.message(),Toast.LENGTH_SHORT).show();
                return  true;
            }
        });

效果圖如下:
這裡寫圖片描述
由於我們return true,訊息攔截成功,控制檯將不會再看到我們的訊息日誌了。

3、WebChromeClient之onProgressChanged

表示當前頁面的載入速度,函式宣告如下:

public void onProgressChanged(WebView view, int newProgress)
  • WebView view:當前WebView例項
  • int newProgress:當前的載入進度,值從0到100
public void onProgressChanged(WebView view, int newProgress) {
         Log.e(TAG,"progress:"+newProgress);
         super.onProgressChanged(view, newProgress);
}

這裡寫圖片描述

大家一定要注意,底層實現時,是利用handler來定時輪循當前進度的,每隔一定時間查詢一次,所以每次拿到的進度資料是不一樣的,也就是說如果頁面較簡單,可能會直接返回100,而跳過中間的各個資料。也就是說,除了100,其它任何一個數值不是一定返回的,所以大家如果要用到進度除了數值100可以用等號來判斷,其它一定要用大於號或小於號,如果用了等號,可能永遠也不會執行到!

4、WebChromeClient之其它函式

/*
* 通知頁面標題變化
*/
nReceivedTitle(WebView view, String title)

/*
* 通知當前頁面網站新圖示
*/
onReceivedIcon(WebView view, Bitmap icon)

/*
* 通知主程式圖示按鈕URL
*/
onReceivedTouchIconUrl(WebView view, String url, boolean precomposed)

/*
* 通知主程式當前頁面將要顯示指定方向的View,該方法用來全屏播放視訊。
*/
public interface CustomViewCallback {
       // 通知當前頁面自定義的View被關閉
       public void onCustomViewHidden();
   }
onShowCustomView(View view, CustomViewCallback callback)

/*
* 與onShowCustomView對應,通知主程式當前頁面將要關閉Custom View
*/
onHideCustomView()

/**
 * 請求主程式建立一個新的Window,如果主程式接收請求,返回true並建立一個新的WebView來裝載Window,然後新增到View中,傳送帶有建立的WebView作為引數的resultMsg的給Target。如果主程式拒絕接收請求,則方法返回false。預設不做任何處理,返回false
 */
onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg)

/*
* 顯示當前WebView,為當前WebView獲取焦點。
*/
onRequestFocus(WebView view)

/*
* 通知主程式關閉WebView,並從View中移除,WebCore停止任何的進行中的載入和JS功能。
*/
onCloseWindow(WebView window)

/**
 * 告訴客戶端顯示離開當前頁面的導航提示框。如果返回true,由客戶端處理確認提示框,呼叫合適的JsResult方法。如果返回false,則返回預設值true給javascript接受離開當前頁面的導航。預設:false。JsResult設定false,當前頁面取消導航提示,否則離開當前頁面。
 */
onJsBeforeUnload(WebView view, String url, String message, JsResult result)

/**
 *通知主程式web內容嘗試使用定位API,但是沒有相關的許可權。主程式需要呼叫呼叫指定的定位許可權申請的回撥。更多說明檢視GeolocationPermissions相關API。
 */
onGeolocationPermissionsShowPrompt(String origin,GeolocationPermissions.Callback callback)

/*
 * 通知程式有定位許可權請求。如果onGeolocationPermissionsShowPrompt許可權申請操作被取消,則隱藏相關的UI介面。
 */
onGeolocationPermissionsHidePrompt()

/**
*通知主程式web內容嘗試申請指定資源的許可權(許可權沒有授權或已拒絕),主程式必須呼叫PermissionRequest#grant(String[])或PermissionRequest#deny()。如果沒有覆寫該方法,預設拒絕。
*/
onPermissionRequest(PermissionRequest request)

/**
* 通知主程式相關許可權被取消。任何相關UI都應該隱藏掉。
*/
onPermissionRequestCanceled(PermissionRequest request)

/**
* 通知主程式 執行的Js操作超時。客戶端決定是否中斷JavaScript繼續執行。如果客戶端返回true,JavaScript中斷執行。如果客戶端返回false,則執行繼續。注意:如果繼續執行,重置JavaScript超時計時器。如果Js下一次檢查點仍沒有結束,則再次提示。
*/
onJsTimeout()

/**
*當停止播放,Video顯示為一張圖片。預設圖片可以通過HTML的Video的poster屬性標籤來指定。如果poster屬性不存在,則使用預設的poster。該方法允許ChromeClient提供預設圖片。
*/
getDefaultVideoPoster()

/**
* 當用戶重放視訊,在渲染第一幀前需要花費時間去緩衝足夠的資料。在緩衝期間,ChromeClient可以提供一個顯示的View。如:可以顯示一個載入動畫。
*/
getVideoLoadingProgressView()

/**
* 獲取訪問歷史Item,用於連結顏色。
*/
getVisitedHistory(ValueCallback callback)

/**
* 通知客戶端顯示檔案選擇器。用來處理file型別的HTML標籤,響應使用者點選選擇檔案的按鈕操作。呼叫filePathCallback.onReceiveValue(null)並返回true取消請求操作。
* FileChooserParams引數的列舉列表:
MODE_OPEN 開啟
MODE_OPEN_MULTIPLE 選中多個檔案開啟
MODE_OPEN_FOLDER 開啟資料夾(暫不支援)
MODE_SAVE 儲存
*/
onShowFileChooser(WebView webView, ValueCallback filePathCallback,FileChooserParams fileChooserParams)

/**
* 解析檔案選擇Activity返回的結果。需要和createIntent一起使用。
*/
parseResult(int resultCode, Intent data)

/**
* 建立Intent物件來啟動檔案選擇器。Intent支援可訪問的簡單型別檔案資源。不支援高階檔案資源如live media capture媒體快照。如果需要訪問這些資源或其他高階檔案型別資源可以自己建立Intent物件。
*/
createIntent()

/**
* 返回檔案選擇模式
*/
getMode()

/**
* 返回可訪問MIME型別陣列,如audio/*,如果沒有指定可訪問型別,陣列返回為null
*/
getAcceptTypes()

/**
* 返回優先的媒體快照型別值如Camera、Microphone。true:允許快照。false,禁止快照。使用getAcceptTypes方法確定合適的capture裝置。
*/
isCaptureEnabled()

/**
* 返回檔案選擇器的標題。如果為null,使用預設名稱。
*/
getTitle()

/**
*指定預設選中的檔名或為null
*/
getFilenameHint()

其它事件處理

上面講了有關WebViewClient的用法,但其中還有一些小問題是WebViewClient無法解決的,比如返回按鍵、滾動事件監聽等

1、返回按鍵
如果用webview點連結看了很多頁以後,如果不做任何處理,點選系統“Back”鍵,整個瀏覽器會呼叫finish()而結束自身,如果希望瀏覽的網頁回退而不是退出瀏覽器,需要在當前Activity中處理並消費掉該Back事件。 覆蓋Activity類的onKeyDown(int keyCode, KeyEvent event)方法。

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
         //改寫物理返回鍵的邏輯
        if(keyCode==KeyEvent.KEYCODE_BACK) {
            if(mWebView.canGoBack()) {
                mWebView.goBack();//返回上一頁面 
                return true;
            } else {
                System.exit(0);//退出程式 
            }
        }
        return super.onKeyDown(keyCode, event);
    }

2、滾動事件監聽
我們都知道監聽滾動事件一般都是設定setOnScrollChangedListener,可惜的是 WebView並沒有給我們提供這樣的方法,但是我們可以重寫WebView,覆蓋裡面的一個方法: protected void onScrollChanged(final int l, final int t, final int oldl,final int oldt){} 然後再對外提供一個介面,示例程式碼如下:

public class MyWebView extends WebView {

    private OnScrollChangedCallback mOnScrollChangedCallback;

    public MyWebView(Context context) {
        super(context);
    }

    public MyWebView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyWebView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (mOnScrollChangedCallback != null) {
            mOnScrollChangedCallback.onScroll(l,t,oldl,oldt);
        }
    }

    public OnScrollChangedCallback getOnScrollChangedCallback() {
        return mOnScrollChangedCallback;
    }

    public void setOnScrollChangedCallback(
            final OnScrollChangedCallback onScrollChangedCallback) {
        mOnScrollChangedCallback = onScrollChangedCallback;
    }

    public static interface OnScrollChangedCallback {
        public void onScroll(int left,int top ,int oldLeft,int oldTop);
    }
}

3、如何強制使用外部瀏覽器開啟網頁
如果不想在 webview 中顯示網頁,而是直接跳轉到瀏覽器的話,可以像下邊那樣呼叫。

Uri uri = Uri.parse("http://www.example.com"); 
Intent intent = new Intent(Intent.ACTION_VIEW, uri); 
startActivity(intent);

這裡是使用隱式Intent的方式來啟用外部應用。