前言
Android 的系統(tǒng)碎片化問題可以說是 Android 系統(tǒng)最大的硬傷了,自這個(gè)系統(tǒng)誕生以來十幾年過去了,依然沒能很好的解決,碎片化問題也是每個(gè) Android 開發(fā)工程師心中的隱痛??,每次處理系統(tǒng)碎片化帶來的問題時(shí),血壓也能分分鐘飆升到 200+,為了減輕其他同仁的痛苦以及此后再遇到類似問題能少踩幾個(gè)坑,就之前的爬坑經(jīng)歷做個(gè)記錄吧。
1、WebView
有關(guān) WebieView 的重要性和其使用不是本文的重點(diǎn),但是有幾個(gè)相關(guān)的屬性我們必須了解:
WebView 迭代歷史
在Android4.4(API level 19)系統(tǒng)以前,Android使用了原生自帶的Android Webkit內(nèi)核,這個(gè)內(nèi)核對(duì)HTML5的支持不是很好,現(xiàn)在使用4.4以下機(jī)子的也不多了,就不對(duì)這個(gè)內(nèi)核做過多介紹了,有興趣可以看下這篇文章。
從Android4.4系統(tǒng)開始,Chromium內(nèi)核取代了Webkit內(nèi)核,正式地接管了WebView的渲染工作。Chromium是一個(gè)開源的瀏覽器內(nèi)核項(xiàng)目,基于Chromium開源項(xiàng)目修改實(shí)現(xiàn)的瀏覽器非常多,包括最著名的Chrome瀏覽器,以及一眾國內(nèi)瀏覽器(360瀏覽器、QQ瀏覽器等)。其中Chromium在Android上面的實(shí)現(xiàn)是Android System WebView^1。
從Android5.0系統(tǒng)開始,WebView移植成了一個(gè)獨(dú)立的apk,可以不依賴系統(tǒng)而獨(dú)立存在和更新,我們可以在系統(tǒng)->設(shè)置->Android System WebView看到WebView的當(dāng)前版本。
從Android7.0系統(tǒng)開始,如果系統(tǒng)安裝了Chrome (version>51),那么Chrome將會(huì)直接為應(yīng)用的WebView提供渲染,WebView版本會(huì)隨著Chrome的更新而更新,用戶也可以選擇WebView的服務(wù)提供方(在開發(fā)者選項(xiàng)->WebView Implementation里),WebView可以脫離應(yīng)用,在一個(gè)獨(dú)立的沙盒進(jìn)程中渲染頁面(需要在開發(fā)者選項(xiàng)里打開)^2。
從Android8.0系統(tǒng)開始,默認(rèn)開啟WebView多進(jìn)程模式,即WebView運(yùn)行在獨(dú)立的沙盒進(jìn)程中^3。―― 節(jié)選自 如何設(shè)計(jì)一個(gè)優(yōu)雅健壯的Android WebView?(上)
Pakage Name
WebView 的包名在 AOSP 中的值是 com.android.webview,該值是在 AOSP 構(gòu)建過程中編譯的版本,也就是說它是和系統(tǒng)一起被編譯出來的,由于大部分的第三方手機(jī)制造商都有自己的定制 ROM,所以包名也是不盡相同,比如 MIUI ROM 中它已經(jīng)被改為 com.mi.webkit.core 。從 WebView 的版本歷史中可以看到自 Android 5.0 開始 WebView 移植成了一個(gè)獨(dú)立的 apk,可以不依賴系統(tǒng)而獨(dú)立存在和更新,這時(shí)候起 WebView 的包名就正式改為 com.google.android.webview 了。
所以這就是為什么網(wǎng)上一堆人問為啥升級(jí)了一下系統(tǒng) WebView ,App 內(nèi)使用到 WebView 的地方或者是內(nèi)置瀏覽器一碰就報(bào) PackageManager$NameNotFoundException: com.google.android.webview 或者 PackageManager$NameNotFoundException: com.android.webview 之類的錯(cuò)誤,這些問題在 Android 5.0 的機(jī)器上非常常見,因?yàn)槟闵?jí)了 WebView 之后 TMD 包名都變了??,而 ROM 定制商一般在版本銜接時(shí)都很保守,所以即使系統(tǒng)升到了 Android 5.0 ,解決方案未必就是最新的,內(nèi)置的 WebView 依然可能是硬編碼進(jìn) ROM 的,所以系統(tǒng)環(huán)境引用的包名可能依舊是 com.android.webview ,你升級(jí)到 com.google.android.webview 它當(dāng)然不認(rèn)識(shí)了??。
2、找到合適的 WebView.apk
通過上面一通廢話,你應(yīng)該知道了,替換的坑就在如果你換上去的 WebView 包名和原內(nèi)置的 WebView 包名不一致,就無法使用,所以就需要找一個(gè)包名一致的高版本 APK 了,還有一種方法是在系統(tǒng)目錄某個(gè)配置文件里改個(gè)什么值,也就是包名引用,這樣你就能換成任何包名的 APK 了,這個(gè)暫時(shí)沒仔細(xì)研究,后續(xù)有結(jié)果了再更新。
APKMirror是一個(gè) APK 鏡像站點(diǎn),在這里可以找到很多 APK 的 release 版本以及歷史版本,尤其 Google 全家桶系列的 APK 非常全,我們在這里根據(jù)需求直接搜索包名就可以了,我這里需要 com.android.webview ,檢索到如下結(jié)果,可以看到這些都是從第三方 ROM 里提取出來的。

因?yàn)?Google 官方早在 WebView 40 的時(shí)候就已經(jīng)將包名換成 com.google.android.webview了,最新的是 72.xxx ,我翻了 15 頁才找到最早改名并獨(dú)立出來的那個(gè)版本??。

3、通過 ADB 替換系統(tǒng) WebView
連接到目標(biāo)機(jī)器
adb connect 192.168.18.235
獲取 su 權(quán)限
adb shell
su
重新掛載 /system 目錄獲取寫入權(quán)限
mount -o rw,remount /system
移動(dòng)原目錄下的 webview.apk 到備份目錄

這里原目錄下的文件分別有 /webview/webview.apk和/webview/lib/arm/libwebviewchromium.so,備份原目錄:
cd /system/app
mv webview/ webview-b/
mkdir -p webview/lib/arm/
將準(zhǔn)備好的安裝包中的 .so 文件提取出來
這里很簡單,文件后綴 .apk 直接改成 .zip 然后解壓縮,復(fù)制出libwebviewchromium.so 即可

上傳文件到 /system/app/webview
先上傳文件到設(shè)備 /sdcard ,然后執(zhí)行如下命令移動(dòng)過去,和原路徑以及原文件名保持一致即可。
mv /sdcard/xxx.apk /system/app/webview/webview.apk
mv /sdcard/xxx.so /system/app/webview/lib/arm/libwebviewchromium.so
設(shè)置目錄執(zhí)行權(quán)限
cd /system/app/
chmod 777 webview/*
重啟設(shè)備
adb reboot
4、結(jié)語
如上一頓操作,其實(shí)也沒什么難度,主要的坑就是包名一致的問題,還有一些系統(tǒng)目錄訪問權(quán)限之類的問題,之前網(wǎng)上搜了好多,都說不 root 沒法換,或者換了會(huì)出問題,root 權(quán)限其實(shí)就是為了訪問和寫入系統(tǒng)目錄,通過重新掛載就解決了,換了會(huì)崩掉的問題其實(shí)就是歷史遺留問題,從 4.x 過度到 5.0 WebView 獨(dú)立了,所以包名變了,或者是 ROM 定制方不按套路來導(dǎo)致?lián)Q上去的 WebView 不被系統(tǒng)識(shí)別,只要找到合適的包就解決了。