目錄介紹
- 01.前沿說明
- 1.1 案例展示效果
- 1.2 該庫功能和優(yōu)勢
- 1.3 相關(guān)類介紹說明
- 02.如何使用
- 2.1 如何引入
- 2.2 最簡單使用
- 2.3 常用api
- 2.4 使用建議
- 03.js調(diào)用
- 3.1 如何使用項目js調(diào)用
- 3.2 js的調(diào)用時機(jī)分析
- 04.問題反饋
- 4.0.1 視頻播放寬度超過屏幕
- 4.0.2 x5加載office資源
- 4.0.3 WebView播放視頻問題
- 4.0.4 無法獲取webView的正確高度
- 4.0.5 使用scheme協(xié)議打開鏈接風(fēng)險
- 4.0.6 如何處理加載錯誤
- 05.webView優(yōu)化
- 5.0.1 視頻全屏播放按返回頁面被放大
- 5.0.2 加快加載webView中的圖片資源
- 5.0.3 自定義加載異常error的狀態(tài)頁面
- 5.0.4 WebView硬件加速導(dǎo)致頁面渲染閃爍
- 5.0.5 WebView加載證書錯誤
- 5.0.6 web音頻播放銷毀后還有聲音
- 5.0.7 DNS采用和客戶端API相同的域名
- 5.0.8 如何設(shè)置白名單操作
- 06.關(guān)于參考
- 07.其他說明介紹
01.前沿說明
- 基于騰訊x5封源庫,提高webView開發(fā)效率,大概要節(jié)約你百分之六十的時間成本。該案例支持處理js的交互邏輯且無耦合、同時暴露進(jìn)度條加載進(jìn)度、可以監(jiān)聽異常error狀態(tài)、支持視頻播放并且可以全頻、支持加載word,xls,ppt,pdf,txt等文件文檔、發(fā)短信、打電話、發(fā)郵件、打開文件操作上傳圖片、喚起原生App、x5庫為最新版本,功能強(qiáng)大。
1.1 案例展示效果
- WebView啟動過程大概分為以下幾個階段,這里借鑒美團(tuán)的一張圖片
- image
- 案例效果圖展示
- 在這里插入圖片描述
- 在這里插入圖片描述
- 在這里插入圖片描述
- 在這里插入圖片描述
- 在這里插入圖片描述
- 在這里插入圖片描述
- 在這里插入圖片描述
- 在這里插入圖片描述
1.2 該庫功能和優(yōu)勢
- 提高webView開發(fā)效率,大概要節(jié)約你百分之六十的時間成本,一鍵初始化操作;
- 支持處理js的交互邏輯,方便快捷,并且無耦合;
- 暴露進(jìn)度條加載進(jìn)度,結(jié)束,以及異常狀態(tài)listener給開發(fā)者;
- 支持視頻播放,可以切換成全頻播放視頻,可旋轉(zhuǎn)屏幕;
- 集成了騰訊x5的WebView,最新版本,功能強(qiáng)大;
- 支持打開文件的操作,比如打開相冊,然后選中圖片上傳,兼容版本(5.0)
- 支持加載word,xls,ppt,pdf,txt等文件文檔,使用方法十分簡單
1.3 相關(guān)類介紹說明
- BridgeHandler 接口,主要處理消息回調(diào)邏輯
- BridgeUtil 工具類,靜態(tài)常量,以及獲取js消息的一些方法,final修飾
- BridgeWebView 自定義WebView類,主要處理與js之間的消息
- CallBackFunction js回調(diào)
- DefaultHandler 默認(rèn)的BridgeHandler
- InterWebListener 接口,web的接口回調(diào),包括常見狀態(tài)頁面切換【狀態(tài)頁面切換】,進(jìn)度條變化【顯示和進(jìn)度監(jiān)聽】等
- Message 自定義消息Message實體類
- ProgressWebView 自定義帶進(jìn)度條的webView
- WebViewJavascriptBridge js橋接接口
- X5WebChromeClient 自定義x5的WebChromeClient,處理進(jìn)度監(jiān)聽,title變化,以及上傳圖片,后期添加視頻處理邏輯
- X5WebUtils 工具類,初始化騰訊x5瀏覽器webView,及調(diào)用該類init方法
- X5WebView 可以使用這個類,方便統(tǒng)一初始化WebSettings的一些屬性,如果不用這里的,想單獨(dú)初始化setting屬性,也可以直接使用BridgeWebView
- X5WebViewClient 自定義x5的WebViewClient,如果要自定義WebViewClient必須要集成此類,一定要繼承該類,因為注入js監(jiān)聽是在該類中操作的
02.如何使用
2.1 如何引入
-
如何引用,該x5的庫已經(jīng)更新到最新版本
implementation 'cn.yc:WebViewLib:1.1.2'
2.2 最簡單使用
-
項目初始化
X5WebUtils.init(this); -
最普通使用,需要自己做手動設(shè)置setting相關(guān)屬性
<BridgeWebView android:id="@+id/web_view" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbarSize="3dp" /> -
也可以使用X5WebView,已經(jīng)做了常見的setting屬性設(shè)置
<X5WebView android:id="@+id/web_view" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbarSize="3dp" /> -
如果想有帶進(jìn)度的,可以使用ProgressWebView
<可以使用ProgressWebView android:id="@+id/web_view" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbarSize="3dp" />
2.3 常用api
-
關(guān)于web的接口回調(diào),包括常見狀態(tài)頁面切換,進(jìn)度條變化等監(jiān)聽處理
mWebView.getX5WebChromeClient().setWebListener(interWebListener); private InterWebListener interWebListener = new InterWebListener() { @Override public void hindProgressBar() { pb.setVisibility(View.GONE); } @Override public void showErrorView() { //設(shè)置自定義異常錯誤頁面 } @Override public void startProgress(int newProgress) { pb.setProgress(newProgress); } }; -
關(guān)于視頻播放的時候,web的接口回調(diào),主要是視頻相關(guān)回調(diào),比如全頻,取消全頻,隱藏和現(xiàn)實webView
x5WebChromeClient = x5WebView.getX5WebChromeClient(); x5WebChromeClient.setVideoWebListener(new VideoWebListener() { @Override public void showVideoFullView() { //視頻全頻播放時監(jiān)聽 } @Override public void hindVideoFullView() { //隱藏全頻播放,也就是正常播放視頻 } @Override public void showWebView() { //顯示webView } @Override public void hindWebView() { //隱藏webView } });
2.4 使用建議
-
優(yōu)化一下相關(guān)的操作
- 關(guān)于設(shè)置js支持的屬性
@Override public void onResume() { super.onResume(); if (mWebView != null) { mWebView.getSettings().setJavaScriptEnabled(true); } } @Override protected void onStop() { super.onStop(); if (mWebView != null) { mWebView.getSettings().setJavaScriptEnabled(false); } }- 關(guān)于destroy銷毀邏輯
@Override protected void onDestroy() { try { if (webView != null) { webView.stopLoading(); webView.destroy(); webView = null; } } catch (Exception e) { Log.e("X5WebViewActivity", e.getMessage()); } super.onDestroy(); }
03.js調(diào)用
3.1 如何使用項目js調(diào)用
-
代碼如下所示,下面中的jsname代表的是js這邊提供給客戶端的方法名稱
mWebView.registerHandler("jsname", new BridgeHandler() { @Override public void handler(String data, CallBackFunction function) { } }); -
如何回調(diào)數(shù)據(jù)給web那邊
function.onCallBack("回調(diào)數(shù)據(jù)");
3.2 js的調(diào)用時機(jī)分析
-
onPageFinished()或者onPageStarted()方法中注入js代碼
- 做過WebView開發(fā),并且需要和js交互,大部分都會認(rèn)為js在WebViewClient.onPageFinished()方法中注入最合適,此時dom樹已經(jīng)構(gòu)建完成,頁面已經(jīng)完全展現(xiàn)出來。但如果做過頁面加載速度的測試,會發(fā)現(xiàn)WebViewClient.onPageFinished()方法通常需要等待很久才會回調(diào)(首次加載通常超過3s),這是因為WebView需要加載完一個網(wǎng)頁里主文檔和所有的資源才會回調(diào)這個方法。
- 能不能在WebViewClient.onPageStarted()中注入呢?答案是不確定。經(jīng)過測試,有些機(jī)型可以,有些機(jī)型不行。在WebViewClient.onPageStarted()中注入還有一個致命的問題——這個方法可能會回調(diào)多次,會造成js代碼的多次注入。
- 從7.0開始,WebView加載js方式發(fā)生了一些小改變,官方建議把js注入的時機(jī)放在頁面開始加載之后。
-
WebViewClient.onProgressChanged()方法中注入js代碼
- WebViewClient.onProgressChanged()這個方法在dom樹渲染的過程中會回調(diào)多次,每次都會告訴我們當(dāng)前加載的進(jìn)度。
- 在這個方法中,可以給WebView自定義進(jìn)度條,類似微信加載網(wǎng)頁時的那種進(jìn)度條
- 如果在此方法中注入js代碼,則需要避免重復(fù)注入,需要增強(qiáng)邏輯??梢远x一個boolean值變量控制注入時機(jī)
- 那么有人會問,加載到多少才需要處理js注入邏輯呢?
- 正是因為這個原因,頁面的進(jìn)度加載到80%的時候,實際上dom樹已經(jīng)渲染得差不多了,表明WebView已經(jīng)解析了<html>標(biāo)簽,這時候注入一定是成功的。在WebViewClient.onProgressChanged()實現(xiàn)js注入有幾個需要注意的地方:
- 1 上文提到的多次注入控制,使用了boolean值變量控制
- 2 重新加載一個URL之前,需要重置boolean值變量,讓重新加載后的頁面再次注入js
- 3 如果做過本地js,css等緩存,則先判斷本地是否存在,若存在則加載本地,否則加載網(wǎng)絡(luò)js
- 4 注入的進(jìn)度閾值可以自由定制,理論上10%-100%都是合理的,不過建議使用了75%到90%之間可以。
- WebViewClient.onProgressChanged()這個方法在dom樹渲染的過程中會回調(diào)多次,每次都會告訴我們當(dāng)前加載的進(jìn)度。
04.問題反饋
4.0.1 視頻播放寬度超過屏幕
- 視頻播放寬度比webView設(shè)置的寬度大,超過屏幕:這個時候可以設(shè)置ws.setLoadWithOverviewMode(false);
4.0.2 x5加載office資源
- 關(guān)于加載word,pdf,xls等文檔文件注意事項:Tbs不支持加載網(wǎng)絡(luò)的文件,需要先把文件下載到本地,然后再加載出來
- 還有一點要注意,在onDestroy方法中調(diào)用此方法mTbsReaderView.onStop(),否則第二次打開無法瀏覽。更多可以看FileReaderView類代碼!
4.0.3 WebView播放視頻問題
- 1、此次的方案用到WebView,而且其中會有視頻嵌套,在默認(rèn)的WebView中直接播放視頻會有問題, 而且不同的SDK版本情況還不一樣,網(wǎng)上搜索了下解決方案,在此記錄下. webView.getSettings.setPluginState(PluginState.ON);webView.setWebChromeClient(new WebChromeClient());
- 2、然后在webView的Activity配置里面加上: android:hardwareAccelerated="true"
- 3、以上可以正常播放視頻了,但是webview的頁面都finish了居然還能聽 到視頻播放的聲音, 于是又查了下發(fā)現(xiàn)webview的onResume方法可以繼續(xù)播放,onPause可以暫停播放, 但是這兩個方法都是在Added in API level 11添加的,所以需要用反射來完成。
- 4、停止播放:在頁面的onPause方法中使用:webView.getClass().getMethod("onPause").invoke(webView, (Object[])null);
- 5、繼續(xù)播放:在頁面的onResume方法中使用:webView.getClass().getMethod("onResume").invoke(webView,(Object[])null);這樣就可以控制視頻的暫停和繼續(xù)播放了。
4.0.4 無法獲取webView的正確高度
- 偶發(fā)情況,獲取不到webView的內(nèi)容高度
- 其中htmlString是一個HTML格式的字符串。
WebView view = new WebView(context); view.loadData(htmlString, "text/html", "utf-8"); view.setWebViewClient(new WebViewClient() { public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); Log.d("2", view.getContentheight() + ""); } });- 這是因為onPageFinished回調(diào)指的WebView已經(jīng)完成從網(wǎng)絡(luò)讀取的字節(jié)數(shù),這一點。在點onPageFinished被激發(fā)的頁面可能還沒有被解析。
- 第一種解決辦法:提供onPageFinished()一些延遲
webView.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); new Handler().postDelayed(new Runnable() { @Override public void run() { int contentHeight = webView.getContentHeight(); int viewHeight = webView.getHeight(); } }, 500); } }); - 第二種解決辦法:使用js獲取內(nèi)容高度,具體可以看這篇文章:http://www.itdecent.cn/p/ad22b2649fba
4.0.5 使用scheme協(xié)議打開鏈接風(fēng)險
- 常見的用法是在APP獲取到來自網(wǎng)頁的數(shù)據(jù)后,重新生成一個intent,然后發(fā)送給別的組件使用這些數(shù)據(jù)。比如使用Webview相關(guān)的Activity來加載一個來自網(wǎng)頁的url,如果此url來自url scheme中的參數(shù),如:yc://ycbjie:8888/from?load_url=http://www.taobao.com。
- 如果在APP中,沒有檢查獲取到的load_url的值,攻擊者可以構(gòu)造釣魚網(wǎng)站,誘導(dǎo)用戶點擊加載,就可以盜取用戶信息。
- 這個時候,別人非法篡改參數(shù),于是將scheme協(xié)議改成yc://ycbjie:8888/from?load_url=http://www.doubi.com。這個時候點擊進(jìn)去即可進(jìn)入釣魚鏈接地址。
- 使用建議
- APP中任何接收外部輸入數(shù)據(jù)的地方都是潛在的攻擊點,過濾檢查來自網(wǎng)頁的參數(shù)。
- 不要通過網(wǎng)頁傳輸敏感信息,有的網(wǎng)站為了引導(dǎo)已經(jīng)登錄的用戶到APP上使用,會使用腳本動態(tài)的生成URL Scheme的參數(shù),其中包括了用戶名、密碼或者登錄態(tài)token等敏感信息,讓用戶打開APP直接就登錄了。惡意應(yīng)用也可以注冊相同的URL Sechme來截取這些敏感信息。Android系統(tǒng)會讓用戶選擇使用哪個應(yīng)用打開鏈接,但是如果用戶不注意,就會使用惡意應(yīng)用打開,導(dǎo)致敏感信息泄露或者其他風(fēng)險。
4.0.6 如何處理加載錯誤(Http、SSL、Resource)
- 對于WebView加載一個網(wǎng)頁過程中所產(chǎn)生的錯誤回調(diào),大致有三種
/** * 只有在主頁面加載出現(xiàn)錯誤時,才會回調(diào)這個方法。這正是展示加載錯誤頁面最合適的方法。 * 然而,如果不管三七二十一直接展示錯誤頁面的話,那很有可能會誤判,給用戶造成經(jīng)常加載頁面失敗的錯覺。 * 由于不同的WebView實現(xiàn)可能不一樣,所以我們首先需要排除幾種誤判的例子: * 1.加載失敗的url跟WebView里的url不是同一個url,排除; * 2.errorCode=-1,表明是ERROR_UNKNOWN的錯誤,為了保證不誤判,排除 * 3failingUrl=null&errorCode=-12,由于錯誤的url是空而不是ERROR_BAD_URL,排除 * @param webView webView * @param errorCode errorCode * @param description description * @param failingUrl failingUrl */ @Override public void onReceivedError(WebView webView, int errorCode, String description, String failingUrl) { super.onReceivedError(webView, errorCode, description, failingUrl); // -12 == EventHandle.ERROR_BAD_URL, a hide return code inside android.net.http package if ((failingUrl != null && !failingUrl.equals(webView.getUrl()) && !failingUrl.equals(webView.getOriginalUrl())) /* not subresource error*/ || (failingUrl == null && errorCode != -12) /*not bad url*/ || errorCode == -1) { //當(dāng) errorCode = -1 且錯誤信息為 net::ERR_CACHE_MISS return; } if (!TextUtils.isEmpty(failingUrl)) { if (failingUrl.equals(webView.getUrl())) { //做自己的錯誤操作,比如自定義錯誤頁面 } } } /** * 只有在主頁面加載出現(xiàn)錯誤時,才會回調(diào)這個方法。這正是展示加載錯誤頁面最合適的方法。 * 然而,如果不管三七二十一直接展示錯誤頁面的話,那很有可能會誤判,給用戶造成經(jīng)常加載頁面失敗的錯覺。 * 由于不同的WebView實現(xiàn)可能不一樣,所以我們首先需要排除幾種誤判的例子: * 1.加載失敗的url跟WebView里的url不是同一個url,排除; * 2.errorCode=-1,表明是ERROR_UNKNOWN的錯誤,為了保證不誤判,排除 * 3failingUrl=null&errorCode=-12,由于錯誤的url是空而不是ERROR_BAD_URL,排除 * @param webView webView * @param webResourceRequest webResourceRequest * @param webResourceError webResourceError */ @Override public void onReceivedError(WebView webView, WebResourceRequest webResourceRequest, WebResourceError webResourceError) { super.onReceivedError(webView, webResourceRequest, webResourceError); } /** * 任何HTTP請求產(chǎn)生的錯誤都會回調(diào)這個方法,包括主頁面的html文檔請求,iframe、圖片等資源請求。 * 在這個回調(diào)中,由于混雜了很多請求,不適合用來展示加載錯誤的頁面,而適合做監(jiān)控報警。 * 當(dāng)某個URL,或者某個資源收到大量報警時,說明頁面或資源可能存在問題,這時候可以讓相關(guān)運(yùn)營及時響應(yīng)修改。 * @param webView webView * @param webResourceRequest webResourceRequest * @param webResourceResponse webResourceResponse */ @Override public void onReceivedHttpError(WebView webView, WebResourceRequest webResourceRequest, WebResourceResponse webResourceResponse) { super.onReceivedHttpError(webView, webResourceRequest, webResourceResponse); } /** * 任何HTTPS請求,遇到SSL錯誤時都會回調(diào)這個方法。 * 比較正確的做法是讓用戶選擇是否信任這個網(wǎng)站,這時候可以彈出信任選擇框供用戶選擇(大部分正規(guī)瀏覽器是這么做的)。 * 有時候,針對自己的網(wǎng)站,可以讓一些特定的網(wǎng)站,不管其證書是否存在問題,都讓用戶信任它。 * 坑:有時候部分手機(jī)打開頁面報錯,絕招:讓自己網(wǎng)站的所有二級域都是可信任的。 * @param webView webView * @param sslErrorHandler sslErrorHandler * @param sslError sslError */ @Override public void onReceivedSslError(WebView webView, SslErrorHandler sslErrorHandler, SslError sslError) { super.onReceivedSslError(webView, sslErrorHandler, sslError); //判斷網(wǎng)站是否是可信任的,與自己網(wǎng)站host作比較 if (WebViewUtils.isYCHost(webView.getUrl())) { //如果是自己的網(wǎng)站,則繼續(xù)使用SSL證書 sslErrorHandler.proceed(); } else { super.onReceivedSslError(webView, sslErrorHandler, sslError); } }
05.webView優(yōu)化
5.0.1 視頻全屏播放按返回頁面被放大(部分手機(jī)出現(xiàn))
- 至于原因暫時沒有找到,解決方案如下所示
/** * 當(dāng)縮放改變的時候會調(diào)用該方法 * @param view view * @param oldScale 之前的縮放比例 * @param newScale 現(xiàn)在縮放比例 */ @Override public void onScaleChanged(WebView view, float oldScale, float newScale) { super.onScaleChanged(view, oldScale, newScale); //視頻全屏播放按返回頁面被放大的問題 if (newScale - oldScale > 7) { //異常放大,縮回去。 view.setInitialScale((int) (oldScale / newScale * 100)); } }
5.0.2 加載webView中的資源時,加快加載的速度優(yōu)化,主要是針對圖片
- html代碼下載到WebView后,webkit開始解析網(wǎng)頁各個節(jié)點,發(fā)現(xiàn)有外部樣式文件或者外部腳本文件時,會異步發(fā)起網(wǎng)絡(luò)請求下載文件,但如果在這之前也有解析到image節(jié)點,那勢必也會發(fā)起網(wǎng)絡(luò)請求下載相應(yīng)的圖片。在網(wǎng)絡(luò)情況較差的情況下,過多的網(wǎng)絡(luò)請求就會造成帶寬緊張,影響到css或js文件加載完成的時間,造成頁面空白loading過久。解決的方法就是告訴WebView先不要自動加載圖片,等頁面finish后再發(fā)起圖片加載。
//初始化的時候設(shè)置,具體代碼在X5WebView類中 if(Build.VERSION.SDK_INT >= KITKAT) { //設(shè)置網(wǎng)頁在加載的時候暫時不加載圖片 ws.setLoadsImagesAutomatically(true); } else { ws.setLoadsImagesAutomatically(false); } /** * 當(dāng)頁面加載完成會調(diào)用該方法 * @param view view * @param url url鏈接 */ @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); //頁面finish后再發(fā)起圖片加載 if(!webView.getSettings().getLoadsImagesAutomatically()) { webView.getSettings().setLoadsImagesAutomatically(true); } }
5.0.3 自定義加載異常error的狀態(tài)頁面,比如下面這些方法中可能會出現(xiàn)error
- 當(dāng)WebView加載頁面出錯時(一般為404 NOT FOUND),安卓WebView會默認(rèn)顯示一個出錯界面。當(dāng)WebView加載出錯時,會在WebViewClient實例中的onReceivedError(),還有onReceivedTitle方法接收到錯誤
/** * 請求網(wǎng)絡(luò)出現(xiàn)error * @param view view * @param errorCode 錯誤?? * @param description description * @param failingUrl 失敗鏈接 */ @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { super.onReceivedError(view, errorCode, description, failingUrl); if (errorCode == 404) { //用javascript隱藏系統(tǒng)定義的404頁面信息 String data = "Page NO FOUND!"; view.loadUrl("javascript:document.body.innerHTML=\"" + data + "\""); } else { if (webListener!=null){ webListener.showErrorView(); } } } // 向主機(jī)應(yīng)用程序報告Web資源加載錯誤。這些錯誤通常表明無法連接到服務(wù)器。 // 值得注意的是,不同的是過時的版本的回調(diào),新的版本將被稱為任何資源(iframe,圖像等) // 不僅為主頁。因此,建議在回調(diào)過程中執(zhí)行最低要求的工作。 // 6.0 之后 @Override public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { super.onReceivedError(view, request, error); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { X5WebUtils.log("服務(wù)器異常"+error.getDescription().toString()); } //ToastUtils.showToast("服務(wù)器異常6.0之后"); //當(dāng)加載錯誤時,就讓它加載本地錯誤網(wǎng)頁文件 //mWebView.loadUrl("file:///android_asset/errorpage/error.html"); if (webListener!=null){ webListener.showErrorView(); } } /** * 這個方法主要是監(jiān)聽標(biāo)題變化操作的 * @param view view * @param title 標(biāo)題 */ @Override public void onReceivedTitle(WebView view, String title) { super.onReceivedTitle(view, title); if (title.contains("404") || title.contains("網(wǎng)頁無法打開")){ if (webListener!=null){ webListener.showErrorView(); } } else { // 設(shè)置title } }
5.0.4 WebView硬件加速導(dǎo)致頁面渲染閃爍
- 4.0以上的系統(tǒng)我們開啟硬件加速后,WebView渲染頁面更加快速,拖動也更加順滑。但有個副作用就是,當(dāng)WebView視圖被整體遮住一塊,然后突然恢復(fù)時(比如使用SlideMenu將WebView從側(cè)邊滑出來時),這個過渡期會出現(xiàn)白塊同時界面閃爍。解決這個問題的方法是在過渡期前將WebView的硬件加速臨時關(guān)閉,過渡期后再開啟
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { webview.setLayerType(View.LAYER_TYPE_SOFTWARE, null); } -
5.0.5 WebView加載證書錯誤
- webView加載一些別人的url時候,有時候會發(fā)生證書認(rèn)證錯誤的情況,這時候我們希望能夠正常的呈現(xiàn)頁面給用戶,我們需要忽略證書錯誤,需要調(diào)用WebViewClient類的onReceivedSslError方法,調(diào)用handler.proceed()來忽略該證書錯誤。
/** * 在加載資源時通知主機(jī)應(yīng)用程序發(fā)生SSL錯誤 * 作用:處理https請求 * @param view view * @param handler handler * @param error error */ @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { super.onReceivedSslError(view, handler, error); if (error!=null){ String url = error.getUrl(); X5WebUtils.log("onReceivedSslError----異常url----"+url); } //https忽略證書問題 if (handler!=null){ //表示等待證書響應(yīng) handler.proceed(); // handler.cancel(); //表示掛起連接,為默認(rèn)方式 // handler.handleMessage(null); //可做其他處理 } }
5.0.6 web音頻播放銷毀后還有聲音
- WebView頁面中播放了音頻,退出Activity后音頻仍然在播放,需要在Activity的onDestory()中調(diào)用
@Override protected void onDestroy() { try { //有音頻播放的web頁面的銷毀邏輯 //在關(guān)閉了Activity時,如果Webview的音樂或視頻,還在播放。就必須銷毀Webview //但是注意:webview調(diào)用destory時,webview仍綁定在Activity上 //這是由于自定義webview構(gòu)建時傳入了該Activity的context對象 //因此需要先從父容器中移除webview,然后再銷毀webview: if (webView != null) { ViewGroup parent = (ViewGroup) webView.getParent(); if (parent != null) { parent.removeView(webView); } webView.removeAllViews(); webView.destroy(); webView = null; } } catch (Exception e) { Log.e("X5WebViewActivity", e.getMessage()); } super.onDestroy(); }
5.0.7 DNS采用和客戶端API相同的域名
- 建立連接/服務(wù)器處理;在頁面請求的數(shù)據(jù)返回之前,主要有以下過程耗費(fèi)時間。
DNS connection 服務(wù)器處理 - DNS采用和客戶端API相同的域名
- DNS會在系統(tǒng)級別進(jìn)行緩存,對于WebView的地址,如果使用的域名與native的API相同,則可以直接使用緩存的DNS而不用再發(fā)起請求圖片。
- 舉個簡單例子,客戶端請求域名主要位于api.yc.com,然而內(nèi)嵌的WebView主要位于 i.yc.com。
- 當(dāng)我們初次打開App時:客戶端首次打開都會請求api.yc.com,其DNS將會被系統(tǒng)緩存。然而當(dāng)打開WebView的時候,由于請求了不同的域名,需要重新獲取i.yc.com的IP。靜態(tài)資源同理,最好與客戶端的資源域名保持一致。
5.0.8 如何設(shè)置白名單操作
- 客戶端內(nèi)的WebView都是可以通過客戶端的某個schema打開的,而要打開頁面的URL很多都并不寫在客戶端內(nèi),而是可以由URL中的參數(shù)傳遞過去的。上面4.0.5 使用scheme協(xié)議打開鏈接風(fēng)險已經(jīng)說明了scheme使用的危險性,那么如何避免這個問題了,設(shè)置運(yùn)行訪問的白名單?;蛘弋?dāng)用戶打開外部鏈接前給用戶強(qiáng)烈而明顯的提示。具體操作如下所示:
- 在onPageStarted開始加載資源的方法中,獲取加載url的host值,然后和本地保存的合法host做比較,這里domainList是一個數(shù)組
@Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); String host = Uri.parse(url).getHost(); LoggerUtils.i("host:" + host); if (!BuildConfig.IS_DEBUG) { if (Arrays.binarySearch(domainList, host) < 0) { //不在白名單內(nèi),非法網(wǎng)址,這個時候給用戶強(qiáng)烈而明顯的提示 } else { //合法網(wǎng)址 } } }
06.關(guān)于參考
- 感謝開源庫
- 參考博客