前言
Android 的系统碎片化问题可以说是 Android 系统最大的硬伤了,自这个系统诞生以来十几年过去了,依然没能很好的解决,碎片化问题也是每个 Android 开发工程师心中的隐痛?,每次处理系统碎片化带来的问题时,血压也能分分钟飙升到 200 ,为了减轻其他同仁的痛苦以及此后再遇到类似问题能少踩几个坑,就之前的爬坑经历做个记录吧。
WebView
有关 WebieView 的重要性和其使用不是本文的重点,但是有几个相关的属性我们必须了解:
- WebView 迭代历史
在Android4.4(API level 19)系统以前,Android使用了原生自带的Android Webkit内核,这个内核对HTML5的支持不是很好,现在使用4.4以下机子的也不多了,就不对这个内核做过多介绍了,有兴趣可以看下这篇文章。
从Android4.4系统开始,Chromium内核取代了Webkit内核,正式地接管了WebView的渲染工作。Chromium是一个开源的浏览器内核项目,基于Chromium开源项目修改实现的浏览器非常多,包括最著名的Chrome浏览器,以及一众国内浏览器(360浏览器、QQ浏览器等)。其中Chromium在Android上面的实现是
Android System WebView^1。 从Android5.0系统开始,WebView移植成了一个独立的apk,可以不依赖系统而独立存在和更新,我们可以在系统->设置->Android System WebView看到WebView的当前版本。 从Android7.0系统开始,如果系统安装了Chrome (version>51),那么Chrome将会直接为应用的WebView提供渲染,WebView版本会随着Chrome的更新而更新,用户也可以选择WebView的服务提供方(在开发者选项->WebView Implementation里),WebView可以脱离应用,在一个独立的沙盒进程中渲染页面(需要在开发者选项里打开)^2。 从Android8.0系统开始,默认开启WebView多进程模式,即WebView运行在独立的沙盒进程中^3。―― 节选自 如何设计一个优雅健壮的Android WebView?(上) - Pakage Name
WebView 的包名在 AOSP 中的值是
com.android.webview,该值是在 AOSP 构建过程中编译的版本,也就是说它是和系统一起被编译出来的,由于大部分的第三方手机制造商都有自己的定制 ROM,所以包名也是不尽相同,比如 MIUI ROM 中它已经被改为com.mi.webkit.core。从 WebView 的版本历史中可以看到自 Android 5.0 开始 WebView 移植成了一个独立的 apk,可以不依赖系统而独立存在和更新,这时候起 WebView 的包名就正式改为com.google.android.webview了。 所以这就是为什么网上一堆人问为啥升级了一下系统 WebView ,App 内使用到 WebView 的地方或者是内置浏览器一碰就报PackageManager$NameNotFoundException: com.google.android.webview或者PackageManager$NameNotFoundException: com.android.webview之类的错误,这些问题在 Android 5.0 的机器上非常常见,因为你升级了 WebView 之后 TMD 包名都变了?,而 ROM 定制商一般在版本衔接时都很保守,所以即使系统升到了 Android 5.0 ,解决方案未必就是最新的,内置的 WebView 依然可能是硬编码进 ROM 的,所以系统环境引用的包名可能依旧是com.android.webview,你升级到com.google.android.webview它当然不认识了?。
找到合适的 WebView.apk
通过上面一通废话,你应该知道了,替换的坑就在如果你换上去的 WebView 包名和原内置的 WebView 包名不一致,就无法使用,所以就需要找一个包名一致的高版本 APK 了,还有一种方法是在系统目录某个配置文件里改个什么值,也就是包名引用,这样你就能换成任何包名的 APK 了,这个暂时没仔细研究,后续有结果了再更新。
APKMirror是一个 APK 镜像站点,在这里可以找到很多 APK 的 release 版本以及历史版本,尤其 Google 全家桶系列的 APK 非常全,我们在这里根据需求直接搜索包名就可以了,我这里需要 com.android.webview ,检索到如下结果,可以看到这些都是从第三方 ROM 里提取出来的。

image-20190122132105477.png
因为 Google 官方早在 WebView 40 的时候就已经将包名换成 com.google.android.webview了,最新的是 72.xxx ,我翻了 15 页才找到最早改名并独立出来的那个版本?。

image-20190122131942432.png
通过 ADB 替换系统 WebView
连接到目标机器
adb connect 192.168.18.235
获取 su 权限
adb shell
su
重新挂载 /system 目录获取写入权限
mount -o rw,remount /system
移动原目录下的 webview.apk 到备份目录

image-20190122162147718.png
这里原目录下的文件分别有 /webview/webview.apk和/webview/lib/arm/libwebviewchromium.so,直接移动 webview 目录下所有文件到 /sdcard/backup/ 下:
mv /system/app/webview/* /sdcard/backup/
将准备好的安装包中的 .so 文件提取出来
这里很简单,文件后缀 .apk 直接改成 .zip 然后解压缩,复制出libwebviewchromium.so 即可

image-20190122165310736.png
上传文件到 /system/app/webview
先上传文件到设备 /sdcard ,然后执行如下命令移动过去,和原路径以及原文件名保持一致即可。
mv /sdcard/xxx.apk /system/app/webview/webview.apk
mv /sdcard/xxx.so /system/app/webview/lib/arm/libwebviewchromium.so
重启设备
adb reboot
结语
如上一顿操作,其实也没什么难度,主要的坑就是包名一致的问题,还有一些系统目录访问权限之类的问题,之前网上搜了好多,都说不 root 没法换,或者换了会出问题,root 权限其实就是为了访问和写入系统目录,通过重新挂载就解决了,换了会崩掉的问题其实就是历史遗留问题,从 4.x 过度到 5.0 WebView 独立了,所以包名变了,或者是 ROM 定制方不按套路来导致换上去的 WebView 不被系统识别,只要找到合适的包就解决了。


