前言
Android 的系统碎片化问题可以说是 Android 系统最大的硬伤了,自这个系统诞生以来十几年过去了,依然没能很好的解决,碎片化问题也是每个 Android 开发工程师心中的隐痛😂,每次处理系统碎片化带来的问题时,血压也能分分钟飙升到 200+,为了减轻其他同仁的痛苦以及此后再遇到类似问题能少踩几个坑,就之前的爬坑经历做个记录吧。
1、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
它当然不认识了😂。
2、找到合适的 WebView.apk
通过上面一通废话,你应该知道了,替换的坑就在如果你换上去的 WebView 包名和原内置的 WebView 包名不一致,就无法使用,所以就需要找一个包名一致的高版本 APK 了,还有一种方法是在系统目录某个配置文件里改个什么值,也就是包名引用,这样你就能换成任何包名的 APK 了,这个暂时没仔细研究,后续有结果了再更新。
APKMirror是一个 APK 镜像站点,在这里可以找到很多 APK 的 release 版本以及历史版本,尤其 Google 全家桶系列的 APK 非常全,我们在这里根据需求直接搜索包名就可以了,我这里需要 com.android.webview
,检索到如下结果,可以看到这些都是从第三方 ROM 里提取出来的。
因为 Google 官方早在 WebView 40 的时候就已经将包名换成 com.google.android.webview
了,最新的是 72.xxx ,我翻了 15 页才找到最早改名并独立出来的那个版本😂。
3、通过 ADB 替换系统 WebView
连接到目标机器
adb connect 192.168.18.235
获取 su 权限
adb shell
su
重新挂载 /system 目录获取写入权限
mount -o rw,remount /system
移动原目录下的 webview.apk 到备份目录
这里原目录下的文件分别有 /webview/webview.apk
和/webview/lib/arm/libwebviewchromium.so
,备份原目录:
cd /system/app
mv webview/ webview-b/
mkdir -p webview/lib/arm/
将准备好的安装包中的 .so 文件提取出来
这里很简单,文件后缀 .apk
直接改成 .zip
然后解压缩,复制出libwebviewchromium.so
即可
上传文件到 /system/app/webview
先上传文件到设备 /sdcard
,然后执行如下命令移动过去,和原路径以及原文件名保持一致即可。
mv /sdcard/xxx.apk /system/app/webview/webview.apk
mv /sdcard/xxx.so /system/app/webview/lib/arm/libwebviewchromium.so
设置目录执行权限
cd /system/app/
chmod 777 webview/*
重启设备
adb reboot
4、结语
如上一顿操作,其实也没什么难度,主要的坑就是包名一致的问题,还有一些系统目录访问权限之类的问题,之前网上搜了好多,都说不 root 没法换,或者换了会出问题,root 权限其实就是为了访问和写入系统目录,通过重新挂载就解决了,换了会崩掉的问题其实就是历史遗留问题,从 4.x 过度到 5.0 WebView 独立了,所以包名变了,或者是 ROM 定制方不按套路来导致换上去的 WebView 不被系统识别,只要找到合适的包就解决了。