x5開源庫後續知識點
目錄介紹
- 01.基礎使用目錄介紹
- 1.0.1 經常使用的基礎介紹
- 1.0.2 Android調用Js
- 1.0.3 Js調用Android
- 1.0.4 WebView.loadUrl(url)流程
- 1.0.5 js的調用時機分析
- 1.0.6 清除緩存數據方式有哪些
- 1.0.7 如何使用DeepLink
- 1.0.8 應用被做爲第三方瀏覽器打開
- 02.優化彙總目錄介紹
- 2.0.1 視頻全屏播放按返回頁面被放大
- 2.0.2 加快加載webView中的圖片資源
- 2.0.3 自定義加載異常error的狀態頁面
- 2.0.4 WebView硬件加速致使頁面渲染閃爍
- 2.0.5 WebView加載證書錯誤
- 2.0.6 web音頻播放銷燬後還有聲音
- 2.0.7 DNS採用和客戶端API相同的域名
- 2.0.8 如何設置白名單操做
- 2.0.9 後臺沒法釋放js致使發熱耗電
- 2.1.0 能夠提早顯示加載進度條
- 2.1.1 WebView密碼明文存儲漏洞優化
- 03.問題彙總目錄介紹
- 3.0.0 WebView進化史介紹
- 3.0.1 提早初始化WebView必要性
- 3.0.2 x5加載office資源
- 3.0.3 WebView播放視頻問題
- 3.0.4 沒法獲取webView的正確高度
- 3.0.5 使用scheme協議打開連接風險
- 3.0.6 如何處理加載錯誤
- 3.0.7 webView防止內存泄漏
- 3.0.8 關於js注入時機修改
- 3.0.9 視頻/圖片寬度超過屏幕
- 3.1.0 如何保證js安全性
- 3.1.1 如何代碼開啓硬件加速
- 3.1.2 WebView設置Cookie
- 3.1.4 webView加載網頁不顯示圖片
- 3.1.5 繞過證書校驗漏洞
- 3.1.6 allowFileAccess漏洞
- 3.1.7 WebView嵌套ScrollView問題
- 3.1.8 WebView中圖片點擊放大
- 3.1.9 頁面滑動期間不渲染/執行
- 3.2.0 被運營商劫持和注入問題
- 3.2.1 解決資源加載緩慢問題
- 3.2.2 判斷是否已經滾動到頁面底端
- 3.2.3 使用loadData加載html亂碼
- 3.2.4 WebView下載進度沒法監聽
- 3.2.5 webView出現302/303重定向
x5封裝庫YCWebView開源項目地址
01.基礎使用目錄介紹
1.0.1 經常使用的基礎介紹
- 在activity中最簡單的使用
- 那些因素影響頁面加載速度
- 影響頁面加載速度的因素有很是多,在對 WebView 加載一個網頁的過程進行調試發現
- 每次加載的過程當中都會有較多的網絡請求,除了 web 頁面自身的 URL 請求
- 有 web 頁面外部引用的JS、CSS、字體、圖片等等都是個獨立的http請求。這些請求都是串行的,這些請求加上瀏覽器的解析、渲染時間就會致使 WebView 總體加載時間變長,消耗的流量也對應的真多。
1.0.2 Android調用Js
- 第一種方式:native 調用 js 的方法,方法爲:
- 注意的是名字必定要對應上,要否則是調用不成功的,並且還有一點是 JS 的調用必定要在 onPageFinished 函數回調以後才能調用,要否則也是會失敗的。
- 第二種方式:
- 若是如今有需求,咱們要獲得一個 Native 調用 Web 的回調怎麼辦,Google 在 Android4.4 爲咱們新增長了一個新方法,這個方法比 loadUrl 方法更加方便簡潔,並且比 loadUrl 效率更高,由於 loadUrl 的執行會形成頁面刷新一次,這個方法不會,由於這個方法是在 4.4 版本才引入的,因此使用的時候須要添加版本的判斷:
- 兩種方式的對比
- 通常最常使用的就是第一種方法,可是第一種方法獲取返回的值比較麻煩,而第二種方法因爲是在 4.4 版本引入的,因此侷限性比較大。
- 注意問題
- 記得添加ws.setJavaScriptEnabled(true)代碼
1.0.3 Js調用Android
- 第一種方式:經過 addJavascriptInterface 方法進行添加對象映射
- 這種是使用最多的方式了,首先第一步咱們須要設置一個屬性:
- 這個函數會有一個警告,由於在特定的版本之下會有很是危險的漏洞,設置完這個屬性以後,Native須要定義一個類:
- 在 API17 版本以後,須要在被調用的地方加上 @addJavascriptInterface 約束註解,由於不加上註解的方法是沒有辦法被調用的
- JS 代碼調用
- 這種方式的好處在於使用簡單明瞭,本地和 JS 的約定也很簡單,就是對象名稱和方法名稱約定好便可,缺點就是要提到的漏洞問題。
- 第二種方式:利用 WebViewClient 接口回調方法攔截 url
- 這種方式其實實現也很簡單,使用的頻次也很高,上面介紹到了 WebViewClient ,其中有個回調接口 shouldOverrideUrlLoading (WebView view, String url)) ,就是利用這個攔截 url,而後解析這個 url 的協議,若是發現是咱們預先約定好的協議就開始解析參數,執行相應的邏輯。注意這個方法在 API24 版本已經廢棄了,須要使用 shouldOverrideUrlLoading (WebView view, WebResourceRequest request)) 替代,使用方法很相似,咱們這裏就使用 shouldOverrideUrlLoading (WebView view, String url)) 方法來介紹一下:
- 代碼很簡單,這個方法能夠攔截 WebView 中加載 url 的過程,獲得對應的 url,咱們就能夠經過這個方法,與網頁約定好一個協議,若是匹配,執行相應操做。
- 存在問題:這個代碼執行以後,就會觸發本地的 shouldOverrideUrlLoading 方法,而後進行參數解析,調用指定方法。這個方式不會存在第一種提到的漏洞問題,可是它也有一個很繁瑣的地方是,若是 web 端想要獲得方法的返回值,只能經過 WebView 的 loadUrl 方法去執行 JS 方法把返回值傳遞回去,相關的代碼以下:
- 第三種方式:利用 WebChromeClient 回調接口的三個方法攔截消息
- 這個方法的原理和第二種方式原理同樣,都是攔截相關接口,只是攔截的接口不同:
- 和 WebViewClient 同樣,此次添加的是WebChromeClient接口,能夠攔截JS中的幾個提示方法,也就是幾種樣式的對話框,在 JS 中有三個經常使用的對話框方法:
- onJsAlert 方法是彈出警告框,通常狀況下在 Android 中爲 Toast,在文本里面加入\n就能夠換行;
- onJsConfirm 彈出確認框,會返回布爾值,經過這個值能夠判斷點擊時確認仍是取消,true表示點擊了確認,false表示點擊了取消;
- onJsPrompt 彈出輸入框,點擊確認返回輸入框中的值,點擊取消返回 null。
- 可是這三種對話框都是能夠本地攔截到的,因此能夠從這裏去作一些更改,攔截這些方法,獲得他們的內容,進行解析,好比若是是 JS 的協議,則說明爲內部協議,進行下一步解析而後進行相關的操做便可,prompt 方法調用以下所示:
- 須要注意的是 prompt 裏面的內容是經過 message 傳遞過來的,並非第二個參數的 url,返回值是經過 JsPromptResult 對象傳遞。爲何要攔截 onJsPrompt 方法,而不是攔截其餘的兩個方法,這個從某種意義上來講都是可行的,可是若是須要返回值給 web 端的話就不行了,由於 onJsAlert 是不能返回值的,而 onJsConfirm 只可以返回肯定或者取消兩個值,只有 onJsPrompt 方法是能夠返回字符串類型的值,操做最全面方便。
- 以上三種方案的總結和對比
- 以上三種方案都是可行的,在這裏總結一下
- 第一種方式:是如今目前最廣泛的用法,方便簡潔,可是惟一的不足是在 4.2 系統如下存在漏洞問題;
- 第二種方式:經過攔截 url 並解析,若是是已經約定好的協議則進行相應規定好的操做,缺點就是協議的約束須要記錄一個規範的文檔,並且從 Native 層往 Web 層傳遞值比較繁瑣,優勢就是不會存在漏洞,iOS7 之下的版本就是使用的這種方式。
- 第三種方式:和第二種方式的思想實際上是相似的,只是攔截的方法變了,這裏攔截了 JS 中的三種對話框方法,而這三種對話框方法的區別就在於返回值問題,alert 對話框沒有返回值,confirm 的對話框方法只有兩種狀態的返回值,prompt 對話框方法能夠返回任意類型的返回值,缺點就是協議的制定比較麻煩,須要記錄詳細的文檔,可是不會存在第二種方法的漏洞問題。
1.0.4 WebView.loadUrl(url)流程
- WebView.loadUrl(url)加載網頁作了什麼?
- 加載網頁是一個複雜的過程,在這個過程當中,咱們可能須要執行一些操做,包括:
- 加載網頁前,重置WebView狀態以及與業務綁定的變量狀態。WebView狀態包括重定向狀態(mTouchByUser)、前端控制的回退棧(mBackStep)等,業務狀態包括進度條、當前頁的分享內容、分享按鈕的顯示隱藏等。
- 加載網頁前,根據不一樣的域拼接本地客戶端的參數,包括基本的機型信息、版本信息、登陸信息以及埋點使用的Refer信息等,有時候涉及交易、財產等還須要作額外的配置。
- 開始執行頁面加載操做時,會回調WebViewClient.onPageStarted(webview,url,favicon)。在此方法中,能夠重置重定向保護的變量(mRedirectProtected),固然也能夠在頁面加載前重置,因爲歷史遺留代碼問題,此處還沒有省去優化。
- 加載頁面的過程當中,WebView會回調幾個方法。
- 頁面加載結束後,WebView會回調幾個方法。
- 加載頁面的過程當中回調哪些方法?
- WebChromeClient.onReceivedTitle(webview, title),用來設置標題。須要注意的是,在部分Android系統版本中可能會回調屢次這個方法,並且有時候回調的title是一個url,客戶端能夠針對這種狀況進行特殊處理,避免在標題欄顯示沒必要要的連接。
- WebChromeClient.onProgressChanged(webview, progress),根據這個回調,能夠控制進度條的進度(包括顯示與隱藏)。通常狀況下,想要達到100%的進度須要的時間較長(特別是首次加載),用戶長時間等待進度條不消失一定會感到焦慮,影響體驗。其實當progress達到80的時候,加載出來的頁面已經基本可用了。事實上,國內廠商大部分都會提早隱藏進度條,讓用戶覺得網頁加載很快。
- WebViewClient.shouldInterceptRequest(webview, request),不管是普通的頁面請求(使用GET/POST),仍是頁面中的異步請求,或者頁面中的資源請求,都會回調這個方法,給開發一次攔截請求的機會。在這個方法中,咱們能夠進行靜態資源的攔截並使用緩存數據代替,也能夠攔截頁面,使用本身的網絡框架來請求數據。包括後面介紹的WebView免流方案,也和此方法有關。
- WebViewClient.shouldOverrideUrlLoading(webview, request),若是遇到了重定向,或者點擊了頁面中的a標籤實現頁面跳轉,那麼會回調這個方法。能夠說這個是WebView裏面最重要的回調之一,後面WebView與Native頁面交互一節將會詳細介紹這個方法。
- WebViewClient.onReceivedError(webview,handler,error),加載頁面的過程當中發生了錯誤,會回調這個方法。主要是http錯誤以及ssl錯誤。在這兩個回調中,咱們能夠進行異常上報,監控異常頁面、過時頁面,及時反饋給運營或前端修改。在處理ssl錯誤時,遇到不信任的證書能夠進行特殊處理,例如對域名進行判斷,針對本身公司的域名「放行」,防止進入醜陋的錯誤證書頁面。也能夠與Chrome同樣,彈出ssl證書疑問彈窗,給用戶選擇的餘地。
- 加載頁面結束回調哪些方法
- 會回調WebViewClient.onPageFinished(webview,url)。
- 這時候能夠根據回退棧的狀況判斷是否顯示關閉WebView按鈕。經過mActivityWeb.canGoBackOrForward(-1)判斷是否能夠回退。
1.0.5 js的調用時機分析
- onPageFinished()或者onPageStarted()方法中注入js代碼
- 作過WebView開發,而且須要和js交互,大部分都會認爲js在WebViewClient.onPageFinished()方法中注入最合適,此時dom樹已經構建完成,頁面已經徹底展示出來。但若是作過頁面加載速度的測試,會發現WebViewClient.onPageFinished()方法一般須要等待好久纔會回調(首次加載一般超過3s),這是由於WebView須要加載完一個網頁裏主文檔和全部的資源纔會回調這個方法。
- 能不能在WebViewClient.onPageStarted()中注入呢?答案是不肯定。通過測試,有些機型能夠,有些機型不行。在WebViewClient.onPageStarted()中注入還有一個致命的問題——這個方法可能會回調屢次,會形成js代碼的屢次注入。
- 從7.0開始,WebView加載js方式發生了一些小改變,官方建議把js注入的時機放在頁面開始加載以後。
- WebViewClient.onProgressChanged()方法中注入js代碼
- WebViewClient.onProgressChanged()這個方法在dom樹渲染的過程當中會回調屢次,每次都會告訴咱們當前加載的進度。
- 在這個方法中,能夠給WebView自定義進度條,相似微信加載網頁時的那種進度條
- 若是在此方法中注入js代碼,則須要避免重複注入,須要加強邏輯。能夠定義一個boolean值變量控制注入時機
- 那麼有人會問,加載到多少才須要處理js注入邏輯呢?
- 正是由於這個緣由,頁面的進度加載到80%的時候,實際上dom樹已經渲染得差很少了,代表WebView已經解析了標籤,這時候注入必定是成功的。在WebViewClient.onProgressChanged()實現js注入有幾個須要注意的地方:
- 1 上文提到的屢次注入控制,使用了boolean值變量控制
- 2 從新加載一個URL以前,須要重置boolean值變量,讓從新加載後的頁面再次注入js
- 3 若是作過本地js,css等緩存,則先判斷本地是否存在,若存在則加載本地,不然加載網絡js
- 4 注入的進度閾值能夠自由定製,理論上10%-100%都是合理的,不過建議使用了75%到90%之間能夠。
1.0.6 清除緩存數據方式有哪些
1.0.7 如何使用DeepLink
1.0.8 應用被做爲第三方瀏覽器打開
- 微信裏的文章頁面,能夠選擇「在瀏覽器打開」。如今不少應用都內嵌了WebView,那是否可使本身的應用做爲第三方瀏覽器打開此文章呢?
- 在Manifest文件中,給想要接收跳轉的Activity添加<intent-filter>配置:
- 而後在 X5WebViewActivity 中獲取相關傳遞數據。具體能夠看lib中的X5WebViewActivity類代碼。
- 一些重點說明
- 在微信中「經過瀏覽器」打開本身的應用,而後將本身的應用切到後臺。重複上面的操做,會一直建立應用的實例,這樣確定是很差的,爲了不這種狀況咱們設置啓動模式爲:launchMode="singleTask"。
02.優化彙總目錄介紹
2.0.1 視頻全屏播放按返回頁面被放大(部分手機出現)
2.0.2 加載webView中的資源時,加快加載的速度優化,主要是針對圖片
- html代碼下載到WebView後,webkit開始解析網頁各個節點,發現有外部樣式文件或者外部腳本文件時,會異步發起網絡請求下載文件,但若是在這以前也有解析到image節點,那勢必也會發起網絡請求下載相應的圖片。在網絡狀況較差的狀況下,過多的網絡請求就會形成帶寬緊張,影響到css或js文件加載完成的時間,形成頁面空白loading太久。解決的方法就是告訴WebView先不要自動加載圖片,等頁面finish後再發起圖片加載。
2.0.3 自定義加載異常error的狀態頁面,好比下面這些方法中可能會出現error
- 當WebView加載頁面出錯時(通常爲404 NOT FOUND),安卓WebView會默認顯示一個出錯界面。當WebView加載出錯時,會在WebViewClient實例中的onReceivedError(),還有onReceivedTitle方法接收到錯誤
2.0.4 WebView硬件加速致使頁面渲染閃爍
- 4.0以上的系統咱們開啓硬件加速後,WebView渲染頁面更加快速,拖動也更加順滑。但有個反作用就是,當WebView視圖被總體遮住一塊,而後忽然恢復時(好比使用SlideMenu將WebView從側邊滑出來時),這個過渡期會出現白塊同時界面閃爍。解決這個問題的方法是在過渡期前將WebView的硬件加速臨時關閉,過渡期後再開啓
2.0.5 WebView加載證書錯誤
- webView加載一些別人的url時候,有時候會發生證書認證錯誤的狀況,這時候咱們但願可以正常的呈現頁面給用戶,咱們須要忽略證書錯誤,須要調用WebViewClient類的onReceivedSslError方法,調用handler.proceed()來忽略該證書錯誤。
2.0.6 web音頻播放銷燬後還有聲音
- WebView頁面中播放了音頻,退出Activity後音頻仍然在播放,須要在Activity的onDestory()中調用
2.0.7 DNS採用和客戶端API相同的域名
- 創建鏈接/服務器處理;在頁面請求的數據返回以前,主要有如下過程耗費時間。
- DNS採用和客戶端API相同的域名
2.0.8 如何設置白名單操做
- 客戶端內的WebView都是能夠經過客戶端的某個schema打開的,而要打開頁面的URL不少都並不寫在客戶端內,而是能夠由URL中的參數傳遞過去的。上面4.0.5 使用scheme協議打開連接風險已經說明了scheme使用的危險性,那麼如何避免這個問題了,設置運行訪問的白名單。或者當用戶打開外部連接前給用戶強烈而明顯的提示。具體操做以下所示:
- 在onPageStarted開始加載資源的方法中,獲取加載url的host值,而後和本地保存的合法host作比較,這裏domainList是一個數組
- 設置白名單操做其實和過濾廣告是一個意思,這裏你能夠放一些合法的網址容許訪問。
2.0.9 後臺沒法釋放js致使發熱耗電
- 在有些手機你若是webView加載的html裏,有一些js一直在執行好比動畫之類的東西,若是此刻webView 掛在了後臺這些資源是不會被釋放用戶也沒法感知。
- 致使一直佔有cpu 耗電特別快,因此若是遇到這種狀況,處理方式以下所示。大概意思就是在後臺的時候,會調用onStop方法,即此時關閉js交互,回到前臺調用onResume再開啓js交互。
2.1.0 能夠提早顯示加載進度條
- 提早顯示進度條不是提高性能 , 可是對用戶體驗來講也是很重要的一點 , WebView.loadUrl("url") 不會立馬就回調 onPageStarted 或者 onProgressChanged 由於在這一時間段,WebView 有可能在初始化內核,也有可能在與服務器創建鏈接,這個時間段容易出現白屏,白屏用戶體驗是很糟糕的 ,因此建議
2.1.1 WebView密碼明文存儲漏洞優化
- WebView 默認開啓密碼保存功能 mWebView.setSavePassword(true),若是該功能未關閉,在用戶輸入密碼時,會彈出提示框,詢問用戶是否保存密碼,若是選擇」是」,密碼會被明文保到 /data/data/com.package.name/databases/webview.db 中,這樣就有被盜取密碼的危險,因此須要經過 WebSettings.setSavePassword(false) 關閉密碼保存提醒功能。
03.問題彙總目錄介紹
3.0.0 WebView進化史介紹
- 進化史以下所示
- 從Android4.4系統開始,Chromium內核取代了Webkit內核。
- 從Android5.0系統開始,WebView移植成了一個獨立的apk,能夠不依賴系統而獨立存在和更新。
- 從Android7.0 系統開始,若是用戶手機裏安裝了 Chrome , 系統優先選擇 Chrome 爲應用提供 WebView 渲染。
- 從Android8.0系統開始,默認開啓WebView多進程模式,即WebView運行在獨立的沙盒進程中。
3.0.1 提早初始化WebView必要性
- 第一次打開Web面 ,使用WebView加載頁面的時候特別慢,第二次打開就能明顯的感受到速度有提高,爲何?
- 是由於在你第一次加載頁面的時候 WebView 內核並無初始化 ,因此在第一次加載頁面的時候須要耗時去初始化WebView內核 。
- 提早初始化WebView內核 ,例如以下把它放到了Application裏面去初始化 , 在頁面裏能夠直接使用該WebView,這種方法能夠比較有效的減小WebView在App中的首次打開時間。當用戶訪問頁面時,不須要初始化WebView的時間。
- 可是這樣也有很差的地方,額外的內存消耗。頁面間跳轉須要清空上一個頁面的痕跡,更容易內存泄露。
3.0.2 x5加載office資源
- 關於加載word,pdf,xls等文檔文件注意事項:Tbs不支持加載網絡的文件,須要先把文件下載到本地,而後再加載出來
- 還有一點要注意,在onDestroy方法中調用此方法mTbsReaderView.onStop(),不然第二次打開沒法瀏覽。更多能夠看FileReaderView類代碼!
3.0.3 WebView播放視頻問題
- 一、這次的方案用到WebView,並且其中會有視頻嵌套,在默認的WebView中直接播放視頻會有問題, 並且不一樣的SDK版本狀況還不同,網上搜索了下解決方案,在此記錄下. webView.getSettings.setPluginState(PluginState.ON);webView.setWebChromeClient(new WebChromeClient());
- 二、而後在webView的Activity配置裏面加上: android:hardwareAccelerated="true"
- 三、以上能夠正常播放視頻了,可是webview的頁面都finish了竟然還能聽 到視頻播放的聲音, 因而又查了下發現webview的onResume方法能夠繼續播放,onPause能夠暫停播放, 可是這兩個方法都是在Added in API level 11添加的,因此須要用反射來完成。
- 四、中止播放:在頁面的onPause方法中使用:webView.getClass().getMethod("onPause").invoke(webView, (Object[])null);
- 五、繼續播放:在頁面的onResume方法中使用:webView.getClass().getMethod("onResume").invoke(webView,(Object[])null);這樣就能夠控制視頻的暫停和繼續播放了。
3.0.4 沒法獲取webView的正確高度
- 偶發狀況,獲取不到webView的內容高度
- 其中htmlString是一個HTML格式的字符串。
- 這是由於onPageFinished回調指的WebView已經完成從網絡讀取的字節數,這一點。在點onPageFinished被激發的頁面可能尚未被解析。
- 第一種解決辦法:提供onPageFinished()一些延遲
- 第二種解決辦法:使用js獲取內容高度,具體能夠看這篇文章:https://www.jianshu.com/p/ad22b2649fba
3.0.5 使用scheme協議打開連接風險
- 常見的用法是在APP獲取到來自網頁的數據後,從新生成一個intent,而後發送給別的組件使用這些數據。好比使用Webview相關的Activity來加載一個來自網頁的url,若是此url來自url scheme中的參數,如:yc://ycbjie:8888/from?load_url=http://www.taobao.com。
- 若是在APP中,沒有檢查獲取到的load_url的值,攻擊者能夠構造釣魚網站,誘導用戶點擊加載,就能夠盜取用戶信息。
- 這個時候,別人非法篡改參數,因而將scheme協議改爲yc://ycbjie:8888/from?load_url=http://www.doubi.com。這個時候點擊進去便可進入釣魚連接地址。
- 使用建議
- APP中任何接收外部輸入數據的地方都是潛在的攻擊點,過濾檢查來自網頁的參數。
- 不要經過網頁傳輸敏感信息,有的網站爲了引導已經登陸的用戶到APP上使用,會使用腳本動態的生成URL Scheme的參數,其中包括了用戶名、密碼或者登陸態token等敏感信息,讓用戶打開APP直接就登陸了。惡意應用也能夠註冊相同的URL Sechme來截取這些敏感信息。Android系統會讓用戶選擇使用哪一個應用打開連接,可是若是用戶不注意,就會使用惡意應用打開,致使敏感信息泄露或者其餘風險。
- 解決辦法
- 在內嵌的WebView中應該限制容許打開的WebView的域名,並設置運行訪問的白名單。或者當用戶打開外部連接前給用戶強烈而明顯的提示。具體操做能夠看5.0.8 如何設置白名單操做方式。
3.0.6 如何處理加載錯誤(Http、SSL、Resource)
- 對於WebView加載一個網頁過程當中所產生的錯誤回調,大體有三種
3.0.7 webView防止內存泄漏
3.0.9 視頻/圖片寬度超過屏幕
- 視頻播放寬度或者圖片寬度比webView設置的寬度大,超過屏幕:這個時候能夠設置ws.setLoadWithOverviewMode(false);
- 另一種讓圖片不超出屏幕範圍的方法,能夠用的是css
- 經過webView的setting屬性設置
3.1.0 如何保證js安全性
- Android和js如何通訊
- 爲了與Web頁面實現動態交互,Android應用程序容許WebView經過WebView.addJavascriptInterface接口向Web頁面注入Java對象,頁面Javascript腳本可直接引用該對象並調用該對象的方法。
- 這類應用程序通常都會有相似以下的代碼:
- 此段代碼將javaObj對象暴露給js腳本,能夠經過jsObj對象對其進行引用,調用javaObj的方法。結合Java的反射機制能夠經過js腳本執行任意Java代碼,相關代碼以下:
- 當受影響的應用程序執行到上述腳本的時候,就會執行someCmd指定的命令。
- addJavascriptInterface任何命令執行漏洞
- 在webView中使用js與html進行交互是一個不錯的方式,可是,在Android4.2(16,包含4.2)及如下版本中,若是使用addJavascriptInterface,則會存在被注入js接口的漏洞;在4.2以後,因爲Google增長了@JavascriptInterface,該漏洞得以解決。
- @JavascriptInterface註解作了什麼操做
- 以前,任何Public的函數均可以在JS代碼中訪問,而Java對象繼承關係會致使不少Public的函數均可以在JS中訪問,其中一個重要的函數就是getClass()。而後JS能夠經過反射來訪問其餘一些內容。經過引入 @JavascriptInterface註解,則在JS中只能訪問 @JavascriptInterface註解的函數。這樣就能夠加強安全性。
3.1.1 如何代碼開啓硬件加速
- 開啓軟硬件加速這個性能提高仍是很明顯的,可是會耗費更大的內存 。直接調用代碼api便可完成,webView.setOpenLayerType(true);
3.1.2 WebView設置Cookie
- h5頁面爲什麼要設置cookie,主要是避免網頁重複登陸,做用是記錄用戶登陸信息,下次進去不須要重複登陸。
- 代碼裏怎麼設置Cookie,以下所示
- 在android裏面在調用webView.loadUrl(url)以前一句調用此方法就能夠給WebView設置Cookie
- 注:這裏必定要注意一點,在調用設置Cookie以後不能再設置,不然設置Cookie無效。該處須要校驗,爲什麼???
- 還有跨域問題: 域A: test1.yc.com 域B: test2.yc.com
- Cookie的過時機制
- 能夠設置Cookie的生效時間字段名爲: expires 或 max-age。
- expires:過時的時間點
- max-age:生效的持續時間,單位爲秒。
- 若將Cookie的 max-age 設置爲負數,或者 expires 字段設置爲過時時間點,數據庫更新後這條Cookie將從數據庫中被刪除。若是將Cookie的 max-age 和 expires 字段設置爲正常的過時日期,則到期後再數據庫更新時會刪除該條數據。
- 下面列出幾個有用的接口:
- 獲取某個url下的全部Cookie:CookieManager.getInstance().getCookie(url)
- 判斷WebView是否接受Cookie:CookieManager.getInstance().acceptCookie()
- 清除Session Cookie:CookieManager.getInstance().removeSessionCookies(ValueCallback<Boolean> callback)
- 清除全部Cookie:CookieManager.getInstance().removeAllCookies(ValueCallback<Boolean> callback)
- Cookie持久化:CookieManager.getInstance().flush()
- 針對某個主機設置Cookie:CookieManager.getInstance().setCookie(String url, String value)
3.1.4 webView加載網頁不顯示圖片
- webView從Lollipop(5.0)開始webView默認不容許混合模式, https當中不能加載http資源, 而開發的時候可能使用的是https的連接, 可是連接中的圖片多是http的, 因此須要設置開啓。
3.1.5 繞過證書校驗漏洞
- webviewClient中有onReceivedError方法,當出現證書校驗錯誤時,咱們能夠在該方法中使用handler.proceed()來忽略證書校驗繼續加載網頁,或者使用默認的handler.cancel()來終端加載。
- 由於咱們使用了handler.proceed(),由此產生了該「繞過證書校驗漏洞」。若是肯定全部頁面都能知足證書校驗,則沒必要要使用handler.proceed()
3.1.6 allowFileAccess漏洞
- 若是webView.getSettings().setAllowFileAccess(boolean)設置爲true,則會面臨該問題;該漏洞是經過WebView對Javascript的延時執行和html文件替換產生的。
- 解決方案是禁止WebView頁面打開本地文件,即:webView.getSettings().setAllowFileAccess(false);
- 或者更直接的禁止使用JavaScript:webView.getSettings().setJavaScriptEnabled(false);
- 問題描述
- 當 WebView 嵌套在 ScrollView 裏面的時候,若是 WebView 先加載了一個高度很高的網頁,而後加載了一個高度很低的網頁,就會形成 WebView 的高度沒法自適應,底部出現大量空白的狀況出現。
- 解決辦法
3.1.8 WebView中圖片點擊放大
- 首先載入js
- html加載完成以後,添加監聽圖片的點擊js函數,這個能夠在onPageFinished方法中操做
- 具體看addImageArrayClickListener的實現方法。
- 最後看看js的通訊接口作了什麼
3.1.9 頁面滑動期間不渲染/執行
- 在有些需求中會有一些吸頂的元素,例如導航條,購買按鈕等;當頁面滾動超出元素高度後,元素吸附在屏幕頂部。在WebView中成了難題:在頁面滾動期間,Scroll Event不觸發。不只如此,WebView在滾動期間還有各類限定:
- setTimeout和setInterval不觸發。
- GIF動畫不播放。
- 不少回調會延遲到頁面中止滾動以後。
- background-position: fixed不支持。
- 這些限制讓WebView在滾動期間很難有較好的體驗。這些限制大部分是不可突破的,但至少對於吸頂功能仍是能夠作一些支持,解決方法:
- 在Android上,監聽touchMove事件能夠在滑動期間作元素的position切換(慣性運動期間就無效了)。
- 參考美團技術文章
3.2.0 被運營商劫持和注入問題
- 因爲WebView加載的頁面代碼是從服務器動態獲取的,這些代碼將會很容易被中間環節所竊取或者修改,其中最主要的問題出自地方運營商和一些WiFi。監測到的問題包括:
- 無視通訊規則強制緩存頁面。
- header被篡改。
- 頁面被注入廣告。
- 頁面被重定向。
- 頁面被重定向並從新iframe到新頁面,框架嵌入廣告。
- HTTPS請求被攔截。
- DNS劫持。
- 針對頁面注入的行爲,有一些解決方案:
- 1.使用CSP(Content Security Policy)
- 2.HTTPS。
- HTTPS能夠防止頁面被劫持或者注入,然而其反作用也是明顯的,網絡傳輸的性能和成功率都會降低,並且HTTPS的頁面會要求頁面內全部引用的資源也是HTTPS的,對於大型網站其遷移成本並不算低。HTTPS的一個問題在於:一旦底層想要篡改或者劫持,會致使整個連接失效,頁面沒法展現。這會帶來一個問題:原本頁面只是會被注入廣告,並且廣告會被CSP攔截,而採用了HTTPS後,整個網頁因爲受到劫持徹底沒法展現。
- 對於安全要求不高的靜態頁面,就須要權衡HTTPS帶來的利與弊了。
- 3.App使用Socket代理請求
- 若是HTTP請求容易被攔截,那麼讓App將其轉換爲一個Socket請求,並代理WebView的訪問也是一個辦法。
- 一般不法運營商或者WiFi都只能攔截HTTP(S)請求,對於自定義的包內容則沒法攔截,所以能夠基本解決注入和劫持的問題。
- Socket代理請求也存在問題:
- 首先,使用客戶端代理的頁面HTML請求將喪失邊下載邊解析的能力;根據前面所述,瀏覽器在HTML收到部份內容後就馬上開始解析,並加載解析出來的外鏈、圖片等,執行內聯的腳本……而目前WebView對外並無暴露這種流式的HTML接口,只能由客戶端徹底下載好HTML後,注入到WebView中。所以其性能將會受到影響。
- 其次,其技術問題也是較多的,例如對跳轉的處理,對緩存的處理,對CDN的處理等等……稍不留神就會埋下若干大坑。
- 此外還有一些其餘的辦法,例如頁面的MD5檢測,頁面靜態頁打包下載等等方式,具體如何選擇還要根據具體的場景抉擇。
3.2.1 解決資源加載緩慢問題
- 在資源預加載方面,其實也有不少種方式,下面主要列舉了一些:
- 第一種方式是使用 WebView 自身的緩存機制:若是咱們在 APP 裏面訪問一個頁面,短期內再次訪問這個頁面的時候,就會感受到第二次打開的時候順暢不少,加載速度比第一次的時間要短,這個就是由於 WebView 自身內部會作一些緩存,只要打開過的資源,他都會試着緩存到本地,第二次須要訪問的時候他直接從本地讀取,可是這個讀取實際上是不太穩定的東西,關掉以後,或者說這種緩存失效以後,系統會自動把它清除,咱們沒辦法進行控制。基於這個 WebView 自身的緩存,有一種資源預加載的方案就是,咱們在應用啓動的時候能夠開一個像素的 WebView ,事先去訪問一下咱們經常使用的資源,後續打開頁面的時候若是再用到這些資源他就能夠從本地獲取到,頁面加載的時間會短一些。
- 第二種方案是,本身去構建和管理緩存:把這些須要預加載的資源放在 APP 裏面,多是預先放進去的,也多是後續下載的,問題在於前端這些頁面怎麼去緩存,兩個方案,第一種是前端能夠在 H5 打包的時候把裏面的資源 URL 進行替換,這樣能夠直接訪問本地的地址;第二種是客戶端能夠攔截這些網頁發出的全部請求作替換。
- 具體能夠看美團的技術文章:美團大衆點評 Hybrid 化建設
3.2.2 判斷是否已經滾動到頁面底端
- getScrollY()方法返回的是當前可見區域的頂端距整個頁面頂端的距離,也就是當前內容滾動的距離.
- getHeight()或者getBottom()方法都返回當前WebView 這個容器的高度
- getContentHeight 返回的是整個html的高度,但並不等同於當前整個頁面的高度,由於WebView有縮放功能,因此當前整個頁面的高度實際上應該是原始html 的高度再乘上縮放比例. 所以,更正後的結果,準確的判斷方法應該是:
3.2.3 使用loadData加載html亂碼
- 能夠經過使用 WebView.loadData(String data, String mimeType, String encoding)) 方法來加載一整個 HTML 頁面的一小段內容,第一個就是咱們須要 WebView 展現的內容,第二個是咱們告訴 WebView 咱們展現內容的類型,通常,第三個是字節碼,可是使用的時候,這裏會有一些坑
- 明明已經指定了編碼格式爲 UTF-8,加載卻還會出現亂碼……
- 使用loadData()或 loadDataWithBaseURL()加載一段HTML代碼片斷
- data:是要加載的數據類型,但在數據裏面不能出現英文字符:'#', '%', '' , '?' 這四個字符,若是有的話能夠用 %23, %25, %27, %3f,這些字符來替換,在平時測試時,你的數據時,你的數據裏含有這些字符,但不會出問題,當出問題時,你能夠替換下。
- %,會報找不到頁面錯誤,頁面全是亂碼。亂碼樣式見符件。
- #,會讓你的goBack失效,但canGoBAck是可使用的。因而就會產生返回按鈕生效,但不能返回的狀況。
- \ 和? 我在轉換時,會報錯,由於它會把\看成轉義符來使用,若是用兩級轉義,也不生效,我是對它無語了。
- 咱們在使用loadData時,就意味着須要把全部的非法字符所有轉換掉,這樣就會給運行速度帶來很大的影響,由於在使用時,在頁面stytle中會使用不少%號。頁面的數據越多,運行的速度就會越慢。
- data中,有人會遇到中文亂碼問題,解決辦法:參數傳"utf-8",頁面的編碼格式也必須是utf-8,這樣編碼統一就不會亂了。別的編碼我也沒有試過。
- 解決辦法
3.2.4 WebView下載進度沒法監聽
3.2.5 webView出現302/303重定向
- 專業敘述
- 網絡解釋
- 重定向是網頁製做中的一個知識,幾個例子跟你說明,假設你如今所處的位置是一個論壇的登陸頁面,你填寫了賬號,密碼,點擊登錄,若是你的賬號密碼正確,就自動跳轉到論壇的首頁,不正確就返回登陸頁;這裏的自動跳轉,就是重定向的意思。或者能夠說,重定向就是,在網頁上設置一個約束條件,條件知足,就自動轉入到其它網頁、網址 。好比,你輸入一個網站連接,通常能夠直接進入網站,若是出現錯誤,則又跳轉到另一個網頁。
- 舉個例子
- 敘述下這種問題的狀況,就是WebView首先加載A連接,而後在WebView上點擊一個B連接進行加載,B連接會自動跳轉到C連接,這個時候調用WebView的goback方法,會返回到加載B連接,可是B連接又會跳轉到C連接,從而致使無法返回到A連接界面(固然也有朋友說快速的按兩次返回鍵-也就是連續觸發了兩次goback能夠返回到A連接,但並非全部用戶都懂這個,並且操做上也很噁心。),這就是重定向問題。
- 實現WebView的滑動監聽和優雅處理回退棧問題
- WebView可否知道某個url是否是301/302呢?固然知道,WebView可以拿到url的請求信息和響應信息,根據header裏的code很輕鬆就能夠實現,事實正是如此,交給WebView來處理重定向(return false),這時候按返回鍵,是能夠正常地回到重定向以前的那個頁面的。(PS:從上面的章節可知,WebView在5.0之後是一個獨立的apk,能夠單獨升級,新版本的WebView實現確定處理了重定向問題)
- 可是,業務對url攔截有需求,確定不能把全部的狀況都交給系統WebView處理。爲了解決url攔截問題,本文引入了另外一種思想——經過用戶的touch事件來判斷重定向。具體能夠看項目lib中的ScrollWebView!
04.關於參考
05.關於x5開源庫YCWebView
5.0.1 前沿說明
- 基於騰訊x5封源庫,提升webView開發效率,大概要節約你百分之六十的時間成本。該案例支持處理js的交互邏輯且無耦合、同時暴露進度條加載進度、能夠監聽異常error狀態、支持視頻播放而且能夠全頻、支持加載word,xls,ppt,pdf,txt等文件文檔、發短信、打電話、發郵件、打開文件操做上傳圖片、喚起原生App、x5庫爲最新版本,功能強大。
5.0.2 該庫功能和優點
- 提升webView開發效率,大概要節約你百分之六十的時間成本,一鍵初始化操做;
- 支持處理js的交互邏輯,方便快捷,而且無耦合,操做十分簡單;
- 暴露進度條加載進度,結束,以及異常狀態(分多種狀態:無網絡,404,onReceivedError,sslError異常等)listener給開發者;
- 支持視頻播放,能夠切換成全頻播放視頻,可旋轉屏幕,暴露視頻操做監聽listener給開發者;
- 集成了騰訊x5的WebView,最新版本,功能強大;
- 支持打開文件的操做,好比打開相冊,而後選中圖片上傳,兼容版本(5.0);
- 支持加載word,xls,ppt,pdf,txt等文件文檔,使用方法十分簡單;
- 支持設置仿微信加載H5頁面進度條,徹底無耦合,操做簡單,極大提升用戶體驗;
5.0.3 項目地址
歡迎關注本站公眾號,獲取更多信息