Android WebView 在開發過程中有哪些坑?
最近在做 WebView 調用手機系統相冊、文件夾來上傳圖片和文件的時候,遇到了一個問題:
Android 5.0+ 重寫 onShowFileChooser 生效;Android 4.4 重寫 openFileChooser 沒有生效;Android 4.4- 重寫 openFileChooser 生效。在網上找解決方法的過程中,發現 WebView 的坑相當多,例如 openFileChooser 只會調用一次,之前使用Webview的時候還遇到了一些。不知道知乎的小夥伴們在使用 WebView 的時候都遇到了哪些坑?分享分享,好讓大家都避開這些坑,提高開發效率。
PS:問題收錄到Android-Dev-Favorites/知乎相關.md at master · ruijun/Android-Dev-Favorites · GitHub
作為Ninja瀏覽器(mthli/Ninja · GitHub)的開發者,我想我遇到的問題應該具有一些代表性吧。下面說說我比較困惑的幾個地方。
- WebViewClient.onPageFinished()。你永遠無法確定當WebView調用這個方法的時候,網頁內容是否真的載入完畢了。當前正在載入的網頁產生跳轉的時候這個方法可能會被多次調用,StackOverflow上有比較具體的解釋(How to listen for a Webview finishing loading a URL in Android?), 但其中列舉的解決方法並不完美。所以當你的WebView需要載入各種各樣的網頁並且需要在頁面載入完成時採取一些操作的話,可能WebChromeClient.onProgressChanged()比WebViewClient.onPageFinished()都要靠譜一些。
- WebView後台耗電問題。當你的程序調用了WebView載入網頁,WebView會自己開啟一些線程(?),如果你沒有正確地將WebView銷毀的話,這些殘餘的線程(?)會一直在後台運行,由此導致你的應用程序耗電量居高不下。對此我採用的處理方式比較偷懶,簡單又粗暴(不建議),即在Activity.onDestroy()中直接調用System.exit(0),使得應用程序完全被移出虛擬機,這樣就不會有任何問題了。
- 切換WebView閃屏問題。如果你需要在同一個ViewGroup中來回切換不同的WebView(包含了不同的網頁內容)的話,你就會發現閃屏是不可避免的。這應該是Android硬體加速的Bug,如果關閉硬體加速這種情況會好很多,但無法獲得很好的瀏覽體驗,你會感覺網頁滑動的時候一卡一卡的,不跟手。
- 數據積累問題。開啟緩存什麼的有利於網頁的瀏覽體驗,但你會發現即使是清除了必要的內容,比如Cache、Cookie、Form Data、History、Password等等東西,你的應用程序所佔用的存儲空間還是會越來越大,到最後只好手動到系統設置的應用信息界面里清除數據了
- 滾動條問題。Android System WebView的橫向滾動條真是好粗的有木有...
以上是我能想到的啦,沒想到的大概是不重要所以自動忽略啦~
另外針對Android System WebView的相關開發,推薦看看Google官方的示例教程 GoogleChrome/chromium-webview-samples · GitHubPS:我開發Android剛剛滿一年,如有疏漏請多多指教做過幾年瀏覽器開發,確實踩過一些坑,可惜當時習慣不好,解決完也沒記錄下來,可能再次提到具體問題,我才能想起來。
順著 @李明亮 同學的回答,我補充下。
1. onPageFinished這個也是把我坑好久,進度條該結束的時候不結束,不該結束的時候提前結束,我總結根本原因還是不同版本瀏覽器內核的實現差異導致的,也深入過內核代碼發現確實結束的回調時機有差異,除非自己做內核,否則除了儘可能的兼容處理外, 盡量保證它提前結束,因為遲遲不結束比提前結束體驗要糟糕得多。
2. webView耗電的問題,我們之前發現的一個情況是,webView切換到後台時,如果當前頁面有JS代碼仍在不時的run, 就會導致比較嚴重的耗電,所以必須確保切換到後台後暫停JS執行,同時切回來的時候恢復它。
3. webView閃屏的問題,也是確實存在的,試驗過,確實跟硬體渲染有關。
4. 數據積累也是頭疼的問題,經常有用戶抱怨它的空間被佔滿了,其實是webkit本身沒有管理好緩存,不得不讓瀏覽器開發人員涉法處理。
5.默認的webview滾動條確實很粗,但還是可以修改的。
想起來的的後面再補充:
webview原生支持js與native代碼交互,可惜在4.2以下版本上有安全漏洞,當時被烏雲報出來,事情還挺大,各大瀏覽器廠商都緊急應對,我們也還是想了其他辦法,解決了這個問題。其實所謂的WebView的各種坑,大部分是Webkit等內核的坑,其實只是它正常發展成熟過程中的一些遺留問題,隨著版本的迭代演化,也在不斷改進。 遺憾的是Android版本的嚴重碎片化,使得這些問題我們不得不面對。陸續接觸幾個月中的坑:
1:混淆時問題, 4.2之前沒問題 4.2之後 怎麼死都無法點擊 網上查到說添加 -keepattributes *Annotation* -keepattributes *JavascriptInterface* 這兩貨可以解決,實驗結果 然並卵!!! 各種g..最後 需要加上-keep class android.webkit.JavascriptInterface {*;}這個鬼!測試 ok 坑了一天!!
2:全屏播放js視頻問題,如上 4.4 以上完全不走onShowCustormer 也就是我本地監聽全屏事件,然而要我按返回鍵退出全屏...狗帶!
3:小米系列手機(2s還好,其他手機比較正常),帶js 視頻頁面 首次載入正常,點擊詳細返回後 怎麼刷新 界面都是之前那個,但裡面的數據是刷新後的 點擊的效果是點擊中的跟看到的不是同一貨!!! 不知道什麼鬼WebView 居然提供了一個超奇葩的 destroy 方法,需要自己手動去調一下才能釋放資源。否則就算依賴的 activity 或者 fragment 不在了,資源還是不會被釋放乾淨。。。
Android webview已經是移動時代的IE6了,真是各種大坑。
安卓的每個版本都喜歡對WEBVIEW做一些改動,而且還不是向下兼容的,結果就是為了保證全部兼容,基本要做大量適配工作。你可以體會下:1,實現從WEBVIEW調用APP。2,試著從WEBVIEW選擇並上傳一張圖片。
我來回答下吧,當時想做一個本地端的代理服務,把所有頁面請求通過我本地的代理髮出去,然後在本地緩存起來它們,下次訪問就可以直接從緩存裡面讀了。遇到的坑如下:
1. 在webview 從webkit 切換到 chrome之後前幾個版本,chrome 讀取本地代理設置時,只註冊偵聽並不讀取當前代理設置,結果是如果你代理設置時,webview 沒有實例化過,則之後webview會忽略你的代理設置。 (心中千萬隻草泥馬奔騰)。解決辦法 (1)設置之前new 一個新的 (2)在application里hack registerReceiver 方法,當webview 設置偵聽時,強制把當前的代理傳入 listener中2.網頁中如果有 mp3 播放,則 mp3 不會走代理,也就是說代理失效 (5.0修復了這個問題)。原因是 webview 在處理多媒體播放時,直接調用 mediaplayer,但是5.0 之前的 mediaplayer 是忽略一切代理設置的。(android 怎麼想的?)解決辦法是往頁面注入 JS,篡改 mp3 地址。
3.一般來說我們確定一個 URL 是來自哪個頁面請求,是通過 refer 來判斷的,但是上面提到的 mp3 請求,是從 mediaplayer 中發出的,尼瑪他的 refer 是空!這個沒法解決。
這個項目里還有很多坑,但是關於webview的暫時只有這些了。
使用setcookie,在4.4版本以下的好用,到了4.4webview換了核心後竟然不好用了,各種方法嘗試都不行,真坑爹。最後只能在服務端做了登陸的重定向才解決。
1 webviewclient的onPageStarted方法居然會被調用兩次也是醉了。
2 native的webview並不對js的定義順序有強制的需求,但是其他內核的webview是必須先定義js,在使用js中的方法/資源的。
3 overrideUrlLoading方法,如果你不需要做什麼,請返回false,而不是調用view.loadUrl,因為在某些內核的webview上,這會導致表單提交失敗啊我去!!!!你知道網頁有個叫類似郵件的添加附件的功能么,不久前就是網頁有個需求,就是從手機中上傳一張圖片,查了資料然後就寫了,因為原生webview裡面有這個介面,叫openFileChooser(),雖然會遇到版本問題,不過判斷一下就好了,熬夜到四點做好了,測試一直沒有問題。然後因為第二天忙著發包,我就順手打了包,為了穩定還是留了個心眼測試了一下,然後。。。。尼瑪啊,點擊無反應 ,當時就傻逼了,凌晨四點半啊啊啊啊,然後又是一陣谷歌,發現尼瑪-_-#這個介面在4.0被谷歌掐了,當時我就tm想轉iOS你知道么,因為之前也是遇到這種andriod版本升級帶來的介面不一,亂七八糟,凌晨四點誰想再來 ,但是想想明天就要更新,還是咬牙繼續查資料。越查學越絕望啊,連谷歌官方都說這個介面被閹割了。。。。。。然後我就傷心看著下面的評論,突然看到有個老外說他找到了解決方法,試了一下發現真的
成功了 ,打包要完我已經連續翹了18個小時了。嚇得我我現在也都還想轉iOS呢。附上解決方法:就是混淆代碼的時候別把這個介面混淆咯 ,後來一想dubug模式下有用,那就想到了debug下的源代碼並沒有被混淆(我之前一直不知道 )在某些手機上,Webview承載視頻時,activity銷毀後,視頻資源沒有被銷毀。解決辦法:在onDestory之前修改url為空地址。
作為先後在360手機瀏覽器和鎚子科技瀏覽器開發的工程師,我想說大部分坑是安卓版本不同導致的,小部分是不同手機自己瞎改webview導致的(我們以前瞎改過,導致開發版的手機12306客戶端有幾天不能用,恰好是搶票那就幾天,最後把代碼revert回去了)
不過具體的坑還真說不出,隱隱記得4.4剛普及的時候,打開文件的回調方法名字改了。有些方法直接調用不好使,但postRunable之後就好了。。。。補答,遇過問題總結:
敲代碼幾年,搞到焦頭爛額的其中一個東西就是webview,問題如下:1.內存泄漏問題;2.WebKit線程數不能控制,低效,例如,如果js效率出現問題或者大量js執行,直接就導致連HTTP請求都延遲,自己抓包就知道(你會傻乎乎地去指責伺服器同事怎麼你們伺服器這麼爛,網頁載入好慢);3.webcorethread的wait問題,不知道什麼時候就會發生,完全束手無策。後果是什麼?退出頁面沒有卵用,只能殺進程。
4.Android4.2以下手機的JavaScript interface的注入漏洞問題,完全不要太危險;5.弱雞的一系列ui問題,滾動,滑動,兼容,把網頁前端哥們苦不堪言,找Android前端同事投訴,Android同學很無奈,完全不知道該怎麼辦。解決方案:1.跨進程。(無法解決兼容問題)2.放棄它。
~~~~原答案~~~~
一級bug如下:
應用需求,一個頁面裡面有多個fragment,然後fragment裡面都是webview載入內容的,然後你會發現不知道什麼時候(對,就是不知道什麼時候),webview載入不出內容了,白屏一片。OK,沒問題,載入不出來無所謂啦,大不了重進,忽悠產品說,偶爾出現而已啦。然而啊,你重進頁面沒有用,你會發現整個應用任何用webview的地方都載入不出東西來,好了,玩不下去了。
跟下去,發現底層有一條叫webcore(印象中是這個名字)的線程一直處於wait的狀態,再也恢復不了了,唯一拯救就是殺進程。
這酸爽。
看到很多webview載入視頻,以及視頻全屏播放的問題,尤其高版本失效
最大的坑是ROM不同,webkit不同,差異性很大。再加上google的坑,真是坑上加坑。比如js注入問題,比如client回調介面時序問題,比如內存回收問題,etc
我不會告訴你,我幾個手機都沒有,三星手機4.4.2不會觸發openFileChooser方法,我把它刷成5.0還是不能觸發onShowFileChooser,小米的5.1.1也不會觸發,還要魅族的5.0+也不會,怎麼辦,以哭瞎.....,小米的4.4.4能觸發openFileChooser,但是然並卵啊
在實現webview顯示對應網頁內容的時候有一個bug,雙指觸摸縮放網頁的內容不起作用,並不是調用mWebView.getSettings().setSupportZoom(true);mWebView.getSettings().setBuiltInZoomControls(true)實現對整個網頁內容的縮放,而是雙指對網頁中顯示的畫板進行縮放,在Android7.0系統就有問題,雙指觸摸完全不動,控制台還報錯:
chromium: [INFO:CONSOLE(369)] "Uncaught TypeError: undefined is not a function", source: /_/js-master-REL-592/layer/sp-lvl-2.js (369)
很詭異的是用小米7.0的系統測試,這個bug就沒有了。。。
然後android7.1.1原生系統跑也沒問題。。。。
感覺應該是和webview內核有關係,不支持某些es語法,js解釋器沒解釋出來???
氣成一隻河豚。
說一個...前端mui,hbuilder打包hybrid app,紅米2a(安卓4.4)除了掉幀沒別的問題,樂視某機(安卓6.01)完全沒問題順,聯想樂檬k3note(安卓5.1)流暢。然後問題來了,鎚子m1(安卓6.01)和堅果pro(貌似安卓7),卡 得 一 逼 ,不單是掉幀那種卡,同時伴隨著不響應touch事件。控制台報錯「 Ignored attempt to cancel a touchstart event with cancelable=false, for example because scrolling is in progress and cannot be interrupted.」可是在以上機子上測試同一個項目並不報錯。天知道鎚子做了什麼。
昨天碰到一個描述很懵逼的~
一個用戶反饋webview載入h5頁面一直在失敗頁,但其它用戶都沒問題。原因是走到onReceivedError回調,被處理為顯示載入失敗頁面了,後來打出錯誤和請求數據(如下圖)看第二行這個請求地址發現不是原始請求地址,查詢ip發現是中國移動的,發現原來是webview載入的http地址被移動運營商劫持了!被劫持後的頁面出現錯誤,走到onReceivedError回調了。
可以試試騰訊瀏覽服務,上面的問題都解決了
http://x5.tencent.com
推薦閱讀:
※如何把AE的動效DEMO準確表達給軟體工程師?
※現在有獨立android開發者么,收入如何?
※安卓開發,建立應用和伺服器之間聯繫的方法?
※Android 程序猿如何繼續深入的研究技術層的知識?請教各位前輩指條明路