在上一篇中我們說(shuō)了WebView的基本使用安卓開(kāi)發(fā)之WebView的使用(1),里面提到了WebViewClient和WebChromeClient湿蛔。
下面我們來(lái)探究一番WebViewClient和WebChromeClient
Let's Go
先了解一下概念
Android WebView做為承載網(wǎng)頁(yè)的載體控件膀曾,他在網(wǎng)頁(yè)顯示的過(guò)程中會(huì)產(chǎn)生一些事件,并回調(diào)給我們的應(yīng)用程序阳啥,以便我們?cè)诰W(wǎng)頁(yè)加載過(guò)程中做應(yīng)用程序想處理的事情添谊。比如說(shuō)客戶(hù)端需要顯示網(wǎng)頁(yè)加載的進(jìn)度、網(wǎng)頁(yè)加載發(fā)生錯(cuò)誤等等事件察迟。
WebView提供兩個(gè)事件回調(diào)類(lèi)給應(yīng)用層斩狱,分別為WebViewClient和WebChromeClient。我們可以繼承這兩個(gè)類(lèi)扎瓶,接受相應(yīng)事件處理所踊。
WebViewClient: 主要提供網(wǎng)頁(yè)加載各個(gè)階段的通知,比如網(wǎng)頁(yè)開(kāi)始加載onPageStarted概荷,網(wǎng)頁(yè)結(jié)束加載onPageFinished等秕岛。
WebChromeClient: 主要提供網(wǎng)頁(yè)加載過(guò)程中提供的數(shù)據(jù)內(nèi)容,比如返回網(wǎng)頁(yè)的title,favicon等。
下面先從WebViewClient開(kāi)始說(shuō)起
WebViewClient的基本使用
WebViewClient的基本使用
創(chuàng)建WebViewClient實(shí)例并設(shè)置到WebView對(duì)象中瓣蛀,具體代碼參考如下:
class MyAndroidWebViewClient extends WebViewClient {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
// TODO
}
@Override
public void onPageFinished(WebView view, String url) {
}
}
webview.setWebViewClient(new MyAndroidWebViewClient ());
來(lái)看看API
public boolean shouldOverrideUrlLoading(WebView view, String url)
當(dāng)加載的網(wǎng)頁(yè)需要重定向的時(shí)候就會(huì)回調(diào)這個(gè)函數(shù)告知我們應(yīng)用程序是否需要接管控制網(wǎng)頁(yè)加載陆蟆,如果應(yīng)用程序接管,并且return true意味著主程序接管網(wǎng)頁(yè)加載惋增,如果返回false讓webview自己處理叠殷。
參數(shù)說(shuō)明:
@param view 接收WebViewClient的那個(gè)實(shí)例
@param url 即將要被加載的url
@return true 當(dāng)前應(yīng)用程序要自己處理這個(gè)url, 返回false則不處理。
Tips:
(1) 當(dāng)請(qǐng)求的方式是"POST"方式時(shí)這個(gè)回調(diào)是不會(huì)通知的。
(2) 當(dāng)我們?cè)L問(wèn)的地址需要我們應(yīng)用程序自己處理的時(shí)候判导,可以在這里截獲,比如我們發(fā)現(xiàn)跳轉(zhuǎn)到的是一個(gè)market的鏈接壶冒,那么我們可以直接跳轉(zhuǎn)到應(yīng)用市場(chǎng),或者其他app截歉。public void onPageStarted(WebView view, String url, Bitmap favicon)
當(dāng)內(nèi)核開(kāi)始加載訪(fǎng)問(wèn)的url時(shí)胖腾,會(huì)通知應(yīng)用程序,對(duì)每個(gè)main frame這個(gè)函數(shù)只會(huì)被調(diào)用一次瘪松,頁(yè)面包含iframe 或者framesets 不會(huì)另外調(diào)用一次onPageStarted咸作,當(dāng)網(wǎng)頁(yè)內(nèi)內(nèi)嵌的frame 發(fā)生改變時(shí)也不會(huì)調(diào)用onPageStarted。
參數(shù)說(shuō)明:
@param view 接收WebViewClient的那個(gè)實(shí)例宵睦,前面看到webView.setWebViewClient(new MyAndroidWebViewClient())记罚,即是這個(gè)webview。
@param url 即將要被加載的url
@param favicon 如果這個(gè)favicon已經(jīng)存儲(chǔ)在本地?cái)?shù)據(jù)庫(kù)中壳嚎,則會(huì)返回這個(gè)網(wǎng)頁(yè)的favicon桐智,否則返回為null。
Tips:
(1) iframe 可能不少人不知道什么含義烟馅,這里我解釋下说庭,iframe我們加載的一張,下面有很多鏈接焙糟,我們隨便點(diǎn)擊一個(gè)鏈接是即當(dāng)前host的一個(gè)iframe.
(2) 有個(gè)問(wèn)題可能是開(kāi)發(fā)者困惑的口渔,onPageStarted和shouldOverrideUrlLoading 在網(wǎng)頁(yè)加載過(guò)程中這兩個(gè)函數(shù)到底哪個(gè)先被調(diào)用样屠。當(dāng)我們通過(guò)loadUrl的方式重新加載一個(gè)網(wǎng)址時(shí)候穿撮,這時(shí)候會(huì)先調(diào)用onPageStarted再調(diào)用shouldOverrideUrlLoading,當(dāng)我們?cè)诖蜷_(kāi)的這個(gè)網(wǎng)址點(diǎn)擊一個(gè)link痪欲,這時(shí)候會(huì)先調(diào)用shouldOverrideUrlLoading再調(diào)用onPageStarted悦穿。
不過(guò)shouldOverrideUrlLoading不一定每次都被調(diào)用,只有需要的時(shí)候才會(huì)被調(diào)用业踢。public void onPageFinished(WebView view, String url)
當(dāng)內(nèi)核加載完當(dāng)前頁(yè)面時(shí)會(huì)通知我們的應(yīng)用程序栗柒,這個(gè)函數(shù)只有在main frame情況下才會(huì)被調(diào)用,當(dāng)調(diào)用這個(gè)函數(shù)之后,渲染的圖片不會(huì)被更新瞬沦,如果需要獲得新圖片的通知可以使用@link WebView.PictureListener#onNewPicture太伊。
參數(shù)說(shuō)明:
@param view 接收WebViewClient的那個(gè)實(shí)例,
前面看到webView.setWebViewClient(new MyAndroidWebViewClient())逛钻,即是這個(gè)webview僚焦。
@param url 即將要被加載的urlpublic void onLoadResource(WebView view, String url)
通知應(yīng)用程序WebView即將加載url 制定的資源
參數(shù)說(shuō)明:
@param view 接收WebViewClient的那個(gè)實(shí)例,
前面看到webView.setWebViewClient(new MyAndroidWebViewClient())曙痘,即是這個(gè)webview芳悲。
@param url 即將加載的url 資源public WebResourceResponse shouldInterceptRequest(WebView view, String url)
通知應(yīng)用程序內(nèi)核即將加載url制定的資源,應(yīng)用程序可以返回本地的資源提供給內(nèi)核边坤,若本地處理返回?cái)?shù)據(jù)名扛,內(nèi)核不從網(wǎng)絡(luò)上獲取數(shù)據(jù)。
參數(shù)說(shuō)明:
@param view 接收WebViewClient的那個(gè)實(shí)例茧痒,
前面看到webView.setWebViewClient(new MyAndroidWebViewClient())肮韧,即是這個(gè)webview。
@param url raw url 制定的資源
@return 返回WebResourceResponse包含數(shù)據(jù)對(duì)象旺订,或者返回null
Tips
這個(gè)回調(diào)并不一定在UI線(xiàn)程執(zhí)行惹苗,所以我們需要注意在這里操作View或者私有數(shù)據(jù)相關(guān)的動(dòng)作。
如果我們需要改變網(wǎng)頁(yè)的背景耸峭,或者需要實(shí)現(xiàn)網(wǎng)頁(yè)頁(yè)面顏色定制化的需求桩蓉,可以在這個(gè)回調(diào)時(shí)機(jī)處理。public void onReceivedError(WebView view, int errorCode, String description, String failingUrl)
當(dāng)瀏覽器訪(fǎng)問(wèn)制定的網(wǎng)址發(fā)生錯(cuò)誤時(shí)會(huì)通知我們應(yīng)用程序劳闹,比如網(wǎng)絡(luò)錯(cuò)誤院究。
參數(shù)說(shuō)明:
@param view 接收WebViewClient的那個(gè)實(shí)例,
前面看到webView.setWebViewClient(new MyAndroidWebViewClient())本涕,即是這個(gè)webview业汰。
@param errorCode 錯(cuò)誤號(hào)可以在WebViewClient.ERROR 里面找到對(duì)應(yīng)的錯(cuò)誤名稱(chēng)。
@param description 描述錯(cuò)誤的信息
@param failingUrl 當(dāng)前訪(fǎng)問(wèn)失敗的url菩颖,注意并不一定是我們主url
Tips
在onReceiveError我們可以自定義網(wǎng)頁(yè)的錯(cuò)誤頁(yè)面样漆。public void onFormResubmission(WebView view, Message dontResend, Message resend)
如果瀏覽器需要重新發(fā)送POST請(qǐng)求,可以通過(guò)這個(gè)時(shí)機(jī)來(lái)處理晦闰。默認(rèn)是不重新發(fā)送數(shù)據(jù)放祟。
參數(shù)說(shuō)明:
@param view 接收WebViewClient的那個(gè)實(shí)例,
前面看到webView.setWebViewClient(new MyAndroidWebViewClient())呻右,即是這個(gè)webview跪妥。
@param dontResent 當(dāng)瀏覽器不需要重新發(fā)送數(shù)據(jù)時(shí),可以使用這個(gè)參數(shù)声滥。
@param resent 當(dāng)瀏覽器需要重新發(fā)送數(shù)據(jù)時(shí)眉撵, 可以使用這個(gè)參數(shù)。public void doUpdateVisitedHistory(WebView view, String url, boolean isReload)
通知應(yīng)用程序可以將當(dāng)前的url存儲(chǔ)在數(shù)據(jù)庫(kù)中,意味著當(dāng)前的訪(fǎng)問(wèn)url已經(jīng)生效并被記錄在內(nèi)核當(dāng)中纽疟。
這個(gè)函數(shù)在網(wǎng)頁(yè)加載過(guò)程中只會(huì)被調(diào)用一次罐韩。注意網(wǎng)頁(yè)前進(jìn)后退并不會(huì)回調(diào)這個(gè)函數(shù)。
參數(shù)說(shuō)明:
@param view 接收WebViewClient的那個(gè)實(shí)例污朽,前面看到webView.setWebViewClient(new MyAndroidWebViewClient())伴逸,即是這個(gè)webview。
@param url 當(dāng)前正在訪(fǎng)問(wèn)的url
@ param isReload 如果是true 這個(gè)是正在被reload的urlpublic void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error)
當(dāng)網(wǎng)頁(yè)加載資源過(guò)程中發(fā)現(xiàn)SSL錯(cuò)誤會(huì)調(diào)用此方法膘壶。我們應(yīng)用程序必須做出響應(yīng)错蝴,是取消請(qǐng)求handler.cancel(),還是繼續(xù)請(qǐng)求handler.proceed();內(nèi)核的默認(rèn)行為是handler.cancel();
參數(shù)說(shuō)明:
@param view 接收WebViewClient的那個(gè)實(shí)例,
前面看到webView.setWebViewClient(new MyAndroidWebViewClient())颓芭,即是這個(gè)webview顷锰。
@param handler 處理用戶(hù)請(qǐng)求的對(duì)象。
@param error SSL錯(cuò)誤對(duì)象
Tips
內(nèi)核會(huì)記住本次選擇亡问,如果下次還有相同的錯(cuò)誤官紫,內(nèi)核會(huì)直接執(zhí)行之前選擇的結(jié)果。public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm)
通知應(yīng)用程序WebView接收到了一個(gè)Http auth的請(qǐng)求州藕,應(yīng)用程序可以使用supplied 設(shè)置webview的響應(yīng)請(qǐng)求束世。默認(rèn)行為是cancel 本次請(qǐng)求。
參數(shù)說(shuō)明:
@param view 接收WebViewClient的那個(gè)實(shí)例床玻,
前面看到webView.setWebViewClient(new MyAndroidWebViewClient())毁涉,即是這個(gè)webview。
@param handler 用來(lái)響應(yīng)WebView請(qǐng)求的對(duì)象
@param host 請(qǐng)求認(rèn)證的host
@param realm 認(rèn)真請(qǐng)求所在的域public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event)
提供應(yīng)用程序同步一個(gè)處理按鍵事件的機(jī)會(huì)锈死,菜單快捷鍵需要被過(guò)濾掉贫堰。如果返回true,webview不處理該事件待牵,如果返回false其屏, webview會(huì)一直處理這個(gè)事件,因此在view 鏈上沒(méi)有一個(gè)父類(lèi)可以響應(yīng)到這個(gè)事件缨该。默認(rèn)行為是return false偎行;
參數(shù)說(shuō)明:
@param view 接收WebViewClient的那個(gè)實(shí)例,前面看到webView.setWebViewClient(new MyAndroidWebViewClient())贰拿,即是這個(gè)webview蛤袒。
@param event 鍵盤(pán)事件名
@return 如果返回true,應(yīng)用程序處理該時(shí)間,返回false 交有webview處理壮不。public void onScaleChanged(WebView view, float oldScale, float newScale)
通知應(yīng)用程序webview 要被scale汗盘。應(yīng)用程序可以處理改事件皱碘,比如調(diào)整適配屏幕询一。public void onReceivedLoginRequest(WebView view, String realm, String account, String args)
通知應(yīng)用程序有個(gè)自動(dòng)登錄的帳號(hào)過(guò)程
參數(shù)說(shuō)明:
@param view 請(qǐng)求登陸的webview
@param realm 賬戶(hù)的域名,用來(lái)查找賬戶(hù)。
@param account 一個(gè)可選的賬戶(hù)健蕊,如果是null 需要和本地的賬戶(hù)進(jìn)行check菱阵, 如果是一個(gè)可用的賬戶(hù),則提供登錄缩功。
@param args 驗(yàn)證制定參數(shù)的登錄用戶(hù)
WebChromeClient基本使用
API
public void onProgressChanged(WebView view, int newProgress)
通知應(yīng)用程序當(dāng)前網(wǎng)頁(yè)加載的進(jìn)度晴及。
參數(shù)說(shuō)明:
@param view WebView
@newProgress 進(jìn)度public void onReceivedTitle(WebView view, String title)
當(dāng)document 的title變化時(shí),會(huì)通知應(yīng)用程序
參數(shù)說(shuō)明:
@param view WebView
@param title document的title
Tips
這個(gè)函數(shù)調(diào)用時(shí)機(jī)不確定嫡锌,有可能很早虑稼,有可能很晚,取決于網(wǎng)頁(yè)把title設(shè)置在什么位置势木,
大多數(shù)網(wǎng)頁(yè)一般把title設(shè)置到頁(yè)面的前面蛛倦,因此很多情況會(huì)比較早回調(diào)到這個(gè)函數(shù)。public void onReceivedIcon(WebView view, Bitmap icon)
當(dāng)前頁(yè)面有個(gè)新的favicon時(shí)候啦桌,會(huì)回調(diào)這個(gè)函數(shù)溯壶。
參數(shù)說(shuō)明:
@param view WebView
@param icon 當(dāng)前頁(yè)面的faviconpublic void onReceivedTouchIconUrl(WebView view, String url, boolean precomposed)
通知應(yīng)用程序 apple-touch-icon的 url
參數(shù)說(shuō)明:
@param view WebView
@param url apple-touch-icon 的服務(wù)端地址
@param precomposed 如果precomposed 是true 則touch-icon是預(yù)先創(chuàng)建的
Tips
如果應(yīng)用程序需要這個(gè)icon的話(huà), 可以通過(guò)這個(gè)url獲取得到 icon甫男。public void onShowCustomView(View view, CustomViewCallback callback)
view且改,主要是用在視頻全屏HTML5 Video support。
參數(shù)說(shuō)明:
@param view 即將要顯示的view
@param callback 當(dāng)view 需要dismiss 則使用這個(gè)對(duì)象進(jìn)行回調(diào)通知板驳。public void onHideCustomView()
隱藏view又跛,如退出視頻通知public boolean onCreateWindow(WebView view, boolean isDialog, boolean isUserGesture, Message resultMsg)
請(qǐng)求創(chuàng)建一個(gè)新的窗口,如果我們應(yīng)用程序接管這個(gè)請(qǐng)求若治,必須返回true效扫,并且創(chuàng)建一個(gè)新的webview來(lái)承載主窗口。如果應(yīng)用程序不處理直砂,則需要返回false菌仁,默認(rèn)行為和返回false表現(xiàn)一樣。
參數(shù)說(shuō)明:
@param view 請(qǐng)求創(chuàng)建新窗口的webview
@param isUserGesture 如果是true静暂,則說(shuō)明是來(lái)自用戶(hù)收拾操作行為济丘,比如用戶(hù)點(diǎn)擊鏈接
@param isDialog true 請(qǐng)求創(chuàng)建的新窗口必須是個(gè)dialog,而不是全屏的窗口洽蛀。
@param resultMsg 當(dāng)webview創(chuàng)建時(shí)需要發(fā)送一個(gè)消息摹迷。WebView.WebViewTransport.setWebView(WebView)
Tips 具體例子如下:
private void createWindow(final Message msg){
WebView.WebViewTransport transport = (WebView.WebViewTransport) msg.obj;
final Tab newTab = mWebViewController.openTab(null, Tab.this, true, true);
transport.setWebView(newTab.getWebView());
msg.sendToTarget();
}
public void onRequestFocus(WebView view)
webview請(qǐng)求得到focus,發(fā)生這個(gè)主要是當(dāng)前webview不是前臺(tái)狀態(tài)郊供,是后臺(tái)webview峡碉。public void onCloseWindow(WebView window)
通知應(yīng)用程序從關(guān)閉傳遞過(guò)來(lái)的webview并從view tree中remove。public boolean onJsAlert(WebView view, String url, String message, JsResult result)
通知應(yīng)用程序顯示javascript alert對(duì)話(huà)框驮审,如果應(yīng)用程序返回true內(nèi)核認(rèn)為應(yīng)用程序處理這個(gè)消息鲫寄,返回false吉执,內(nèi)核自己處理。
參數(shù)說(shuō)明:
@param view webview地来。
@param url 當(dāng)前請(qǐng)求彈出javascript 對(duì)話(huà)框webview 加載的url地址戳玫。
@param message 彈出的內(nèi)容信息
@result 用來(lái)響應(yīng)用戶(hù)的處理。
Tips
如果我們應(yīng)用接管處理未斑, 則必須給出result的結(jié)果咕宿,result.cancel,result.comfirm必須調(diào)用其中之后,否則內(nèi)核會(huì)hang住蜡秽。public boolean onJsConfirm(WebView view, String url, String message,JsResult result)
通知應(yīng)用程序提供confirm 對(duì)話(huà)框府阀。 參數(shù)說(shuō)明同上onJsAlertpublic boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result)
通知應(yīng)用程序顯示一個(gè)prompt對(duì)話(huà)框。
Tips
必須調(diào)用result.confirm 方法如果應(yīng)用程序接管這個(gè)方法芽突。public boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result)
通知應(yīng)用程序顯示一個(gè)對(duì)話(huà)框肌似,讓用戶(hù)選擇是否離開(kāi)當(dāng)前頁(yè)面,這個(gè)回調(diào)是javascript中的onbeforeunload事件诉瓦,如果客戶(hù)端返回true川队,內(nèi)核會(huì)認(rèn)為客戶(hù)端提供對(duì)話(huà)框。默認(rèn)行為是return false睬澡。
參數(shù)說(shuō)明和之前介紹的onJsAlert()相同固额。public void onExceededDatabaseQuota(String url, String databaseIdentifier, long quota, long estimatedDatabaseSize, long totalQuota, WebStorage.QuotaUpdater quotaUpdater)
通知應(yīng)用程序webview內(nèi)核web sql 數(shù)據(jù)庫(kù)超出配額,請(qǐng)求是否擴(kuò)大數(shù)據(jù)庫(kù)磁盤(pán)配額煞聪。默認(rèn)行為是不會(huì)增加數(shù)據(jù)庫(kù)配額斗躏。
參數(shù)說(shuō)明:
@param url 觸發(fā)這個(gè)數(shù)據(jù)庫(kù)配額的url地址
@param databaseIdentifier 指示出現(xiàn)數(shù)據(jù)庫(kù)超過(guò)配額的標(biāo)識(shí)。
@param quota 原始數(shù)據(jù)庫(kù)配額的大小昔脯,是字節(jié)單位bytes
@param estimatedDatabaseSize 到達(dá)底線(xiàn)的數(shù)據(jù)大小 bytes
@param totalQuota 總的數(shù)據(jù)庫(kù)配額大小 bytes
@param quotaUpdater 更新數(shù)據(jù)庫(kù)配額的對(duì)象啄糙,可以使用 quotaUpdater.updateQuota(newQuota);配置新的數(shù)據(jù)庫(kù)配額大小。public void onReachedMaxAppCacheSize(long requiredStorage, long quota, WebStorage.QuotaUpdater quotaUpdater)
通知應(yīng)用程序內(nèi)核已經(jīng)到達(dá)最大的appcache云稚。appcache是HTML5針對(duì)offline的一個(gè)數(shù)據(jù)處理標(biāo)準(zhǔn)隧饼。public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback)
當(dāng)前頁(yè)面請(qǐng)求是否允許進(jìn)行定位。
GeolocationPermissions.Callback的方法:
1.public void invoke(String origin, boolean allow, boolean retain);
參數(shù)說(shuō)明:
@param origin 權(quán)限設(shè)置的源地址
@param allow 是否允許定位
@retain 當(dāng)前的選擇是否讓內(nèi)核記住静陈。
2.public void onGeolocationPermissionsHidePrompt()public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType, String capture)
這個(gè)回調(diào)是私有回調(diào)燕雁, 當(dāng)頁(yè)面需要請(qǐng)求打開(kāi)系統(tǒng)的文件選擇器,則會(huì)回調(diào)這個(gè)方法鲸拥,比如我們需要上傳圖片拐格,請(qǐng)求拍照,郵件的附件上傳等等操作刑赶。如果不實(shí)現(xiàn)這個(gè)私有API捏浊,則上面的請(qǐng)求都將不會(huì)執(zhí)行。