news 2026/9/1 15:37:22

第 45 章 WebView

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第 45 章 WebView

WebView 是 Android 可嵌入的浏览器组件,允许应用直接在自身 UI 内展示网页内容。在底层,它是一套极其复杂的子系统:Android 框架仅提供一层薄薄的外观封装,将全部操作委托给可更新的、基于 Chromium 的提供方安装包,该安装包运行在独立的一组进程中。本章梳理完整调用栈:从应用开发者编写的 XML<WebView>标签,经过工厂与提供方抽象层,深入多进程 Chromium 引擎、安全沙箱,以及无需完整系统升级即可完成更新的更新机制。

45.1 WebView 架构

45.1.1 历史背景

Android 的 WebView 经历过三个主要架构时代:

WebKit 时代(Android 1.0 — 4.3):WebView 为单体式同进程组件,基于 WebKit 渲染引擎构建。它作为系统镜像的一部分发布,仅能通过完整 OTA 系统更新完成升级。

迁移至 Chromium(Android 4.4 — 6.0):从 KitKat(API 19)开始,Android 将 WebKit 后端替换为 Chromium content 层。最初 Chromium 代码依旧编译进系统镜像,但该架构引入了提供方抽象,为后续解耦打下基础。

可更新 WebView(Android 7.0 及以上):从 Nougat 版本起,WebView 变为独立可更新 APK,通过应用商店或系统更新器下发。框架层仅保留薄代理类;真正的实现逻辑存放在 WebView 提供方安装包(通常为 com.google.android.webview 或 com.android.webview)。

APEX 封装的提供方选择逻辑(Android 17):Android 17 引入正式可用的 APEX 封装包 com.android.webview.bootstrap,该包封装 WebView 提供方选择逻辑,使其可以作为 Mainline 模块发布与更新,不再依附于系统镜像。提供方 APK 本身依旧是独立可更新包;实现模块化改造的是 WebViewUpdateService 业务逻辑及其客户端封装类。45.9 节会详细讲解该变更以及 Android17 其他 WebView 更新内容。

45.1.2 高层组件关系图

下图展示应用使用 WebView 时涉及的主要组件:

45.1.3 多进程模型

现代 Android WebView 使用源自 Chromium 的多进程架构:

浏览器进程:即应用自身进程。Chromium “浏览器” 逻辑运行在应用主线程以及该进程内一组 IO / 工作线程池。负责导航决策、Cookie 管理、权限弹窗,以及与 Android 框架通信。

渲染进程:独立的沙箱进程,运行 Blink 渲染引擎与 V8 JavaScript 引擎。同一个应用内的多个 WebView 实例可以共享同一个渲染进程;渲染进程崩溃不会波及浏览器进程。渲染进程由 WebView Zygote 孵化而来,这是一个专用子 Zygote,预加载 WebView 提供方代码,实现进程快速创建。

GPU 进程:负责 GPU 加速合成与光栅化。开启硬件加速时,WebView 复用应用的 GPU 线程,通过 functor 机制和 Android RenderThread 完成绘制。

多进程模型由框架控制。WebViewDelegate.isMultiProcessEnabled()目前无条件返回 true:

Source: frameworks/base/core/java/android/webkit/WebViewDelegate.java public boolean isMultiProcessEnabled() { return true; }

45.1.4 进程隔离与 WebView Zygote

渲染进程通过专用 WebView Zygote 创建,而不是主应用 Zygote。该子 Zygote 专门为 WebView 定制:\

WebViewZygote类管理该子 Zygote 的完整生命周期:

源码位置:frameworks/base/core/java/android/webkit/WebViewZygote.java

sZygote = Process.ZYGOTE_PROCESS.startChildZygote( "com.android.internal.os.WebViewZygoteInit", "webview_zygote", Process.WEBVIEW_ZYGOTE_UID, Process.WEBVIEW_ZYGOTE_UID, sharedAppGid, runtimeFlags, "webview_zygote", // seInfo abi, TextUtils.join(",", Build.SUPPORTED_ABIS), null, Process.FIRST_ISOLATED_UID, Integer.MAX_VALUE);

关键要点:

  • Zygote 运行在专属 UID(WEBVIEW_ZYGOTE_UID)下。
  • 预加载 WebView APK,fork 出来的渲染进程启动速度更快。
  • WebView 提供方发生变更(例如版本更新)时,旧 Zygote 会被杀死,并使用更新后的安装包启动新 Zygote。

45.1.5 绘制集成

WebView 通过绘制 functor 机制接入 Android 硬件加速渲染管线。不走标准的View.onDraw()记录显示列表的路径,WebView 向 RenderThread 注册一个 native functor:

源码位置:frameworks/base/core/java/android/webkit/WebViewDelegate.java

public void drawWebViewFunctor(@NonNull Canvas canvas, int functor) { if (!(canvas instanceof RecordingCanvas)) { throw new IllegalArgumentException(canvas.getClass().getName() + " is not a RecordingCanvas canvas"); } ((RecordingCanvas) canvas).drawWebViewFunctor(functor); }

该 functor 是 native 函数指针(Chromium 代码中由 AwDrawFn_CreateFunctor 创建),RenderThread 在 GPU 合成阶段调用它。这样 WebView 内容可以和 Android 原生 UI 元素一起完成合成,避免进程之间开销巨大的像素拷贝。

45.1.6 WebView 类继承体系与包结构

android.webkit包包含全部对外暴露的 WebView 相关类。下面列出主要类及其作用:

类名作用
WebView核心视图控件;是对 WebViewProvider 的薄代理层
WebSettings单实例配置项(抽象类,实现在提供方包内)
WebViewClient导航与错误事件回调
WebChromeClient浏览器 UI 相关事件回调
WebViewFactory单例工厂;加载并缓存提供方实现
WebViewFactoryProvider顶层提供方工厂接口
WebViewProvider每个 WebView 实例对应的后端接口
WebViewDelegate桥接类,允许提供方访问框架内部 API
SelectionActionMenuClientOEM 定制 WebView 文本选择菜单的扩展钩子(Android17 新增)
WebViewLibraryLoader带 RELRO 优化的 native 库加载器
WebViewZygote管理渲染进程使用的子 Zygote
WebViewUpdateService系统更新服务旧版客户端
WebViewUpdateManager系统更新服务新版客户端
WebViewProviderInfo描述候选 WebView 提供方安装包信息
WebViewProviderResponse更新服务返回的状态响应
WebViewRenderProcess渲染进程句柄
WebViewRenderProcessClient渲染进程响应状态回调
CookieManagerCookie 管理单例
WebStorageWeb 存储(localStorage、sessionStorage)管理
GeolocationPermissions地理位置权限管理
TracingController性能跟踪对接
TracingConfig跟踪配置(分类、模式)
ServiceWorkerControllerService Worker 管理
JavascriptInterface用于暴露 Java 方法给 JS 的注解
SafeBrowsingResponse安全浏览命中后的响应动作
RenderProcessGoneDetail渲染进程崩溃详情
ConsoleMessageJavaScript 控制台消息封装
ValueCallback<T>异步操作通用回调
WebResourceRequest资源请求详情
WebResourceResponse自定义资源返回响应
WebResourceError资源加载错误详情
WebMessageWeb 消息 API 消息体
WebMessagePortWeb 消息 API 通信端口
WebBackForwardList导航历史快照
WebHistoryItem导航历史单条记录

AIDL 接口文件定义客户端与系统服务之间 Binder IPC 契约:

AIDL 文件用途
IWebViewUpdateService.aidl更新服务 Binder 接口
WebViewProviderInfo.aidlParcelable 序列化的提供方信息
WebViewProviderResponse.aidlParcelable 序列化的提供方响应

45.1.7 配置与特性开关

WebView 行为受多种开关机制控制:

flags.aconfigandroid.webkit包使用 aconfig 开关实现功能灰度发布。Android17 的开关集合(frameworks/base/core/java/android/webkit/flags.aconfig):

  • update_service_ipc_wrapper(FLAG_UPDATE_SERVICE_IPC_WRAPPER):控制 WebViewUpdateManager 封装类
  • mainline_apis:WebViewBootstrap Mainline 模块所需新增 API(见 45.9.1)
  • selection_action_menu_client:OEM 定制文本选择菜单新 API(Android17 新增 SelectionActionMenuClient)
  • file_system_access(FLAG_FILE_SYSTEM_ACCESS):开启 WebView 的文件系统访问 API
  • user_agent_reduction(FLAG_USER_AGENT_REDUCTION):启用 User‑Agent 字符串精简
  • deprecate_start_safe_browsing(FLAG_DEPRECATE_START_SAFE_BROWSING):废弃显式 startSafeBrowsing () 调用,该接口现在是空实现

服务端在 frameworks/base/services/core/java/com/android/server/webkit/flags.aconfig 中定义一个开关 update_service_v2,用于选择 WebViewUpdateServiceImpl2;Android17 该功能已全量上线,旧实现已经移除(见 45.4.1)。

@ChangeId 注解:受 targetSdkVersion 控制的兼容性变更

  • ENABLE_SIMPLIFIED_DARK_MODE (API 33+):算法深色模式
  • ENABLE_USER_AGENT_REDUCTION (Baklava 版本之后):精简 UA 字符串
  • ENABLE_FILE_SYSTEM_ACCESS (Baklava 版本之后):文件系统访问 API

Chromium 命令行开关:提供方可以接收 Chromium 风格参数用于测试调试,一般通过开发者选项或者 adb 设置:

adb shell "echo 'chrome --enable-features=SomeFeature' > \ /data/local/tmp/webview-command-line"

Android 系统属性:WebViewDelegate 通过SystemProperties.addChangeCallback()监听系统属性,用于开启性能跟踪。

45.2 WebViewFactory

WebViewFactory是创建、加载 WebView 实现的入口。它属于 @SystemApi,普通应用开发者不可见,是连接 Android 框架与 Chromium 提供方的核心协调器。

源码位置:frameworks/base/core/java/android/webkit/WebViewFactory.java

45.2.1 类概览

WebViewFactory 是 final 类,全部为静态方法。主要职责:

职责对应方法
获取 / 缓存提供方单例getProvider()
加载提供方类getProviderClass()
加载 native 库loadWebViewNativeLibraryFromPackage()
在 Zygote 预留地址空间prepareWebViewInZygote()
处理提供方变更事件onWebViewProviderChanged()
校验 WebView 是否可用isWebViewSupported()
访问更新服务getUpdateService()

45.2.2 Chromium 工厂类

工厂硬编码 Chromium 提供方实现类名称:

private static final String CHROMIUM_WEBVIEW_FACTORY = "com.android.webview.chromium.WebViewChromiumFactoryProviderForT"; private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";

类名在运行时通过 WebView 提供方 APK 的类加载器解析。后缀 “ForT” 代表该提供方必须实现的 API 兼容等级(Tiramisu / API33+),不是操作系统版本。Android17 依旧加载 WebViewChromiumFactoryProviderForT;只有当框架新增强制的提供方入口点时后缀才会更新,Tiramisu 之后没有改动。Android17 上运行的新版提供方 APK 同样实现create(WebViewDelegate)这套契约。

源码位置:frameworks/base/core/java/android/webkit/WebViewFactory.java(57‑60 行)

45.2.3 提供方初始化流程

应用第一次创建 WebView 时,完整初始化流程包含多个协同步骤:

45.2.4 安全防护:拒绝特权进程

WebView 明确拒绝在特权系统进程加载。getProvider()校验调用方 UID(Android17 沿用相同的 5 个 UID 黑名单):

源码位置:frameworks/base/core/java/android/webkit/WebViewFactory.java(342‑346 行)

final int appId = UserHandle.getAppId(android.os.Process.myUid()); if (appId == android.os.Process.ROOT_UID || appId == android.os.Process.SYSTEM_UID || appId == android.os.Process.PHONE_UID || appId == android.os.Process.NFC_UID || appId == android.os.Process.BLUETOOTH_UID) { throw new UnsupportedOperationException( "For security reasons, WebView is not allowed in privileged processes"); }

这是关键安全措施。WebView 会加载并执行包含 JavaScript 在内的任意网页内容。如果运行在特权进程(system_server、电话、蓝牙、NFC),网页侧漏洞就可以获取系统级权限。

45.2.5 安装包校验

加载提供方之前,WebViewFactory 对 WebView 安装包执行严格校验:

  1. 包名校验:更新服务返回的包名必须和 PackageManager 查询结果一致。
  2. 版本号校验:实际安装版本必须大于等于更新服务上报版本,防止版本降级攻击。
  3. 签名校验:已安装包签名必须和选中包签名匹配;使用 ArraySet 做无序比对。
  4. 库标识校验:安装包必须声明com.android.webview.WebViewLibrarymeta‑data,指向 native so 库。
private static void verifyPackageInfo(PackageInfo chosen, PackageInfo toUse) throws MissingWebViewPackageException { if (!chosen.packageName.equals(toUse.packageName)) { ... } if (chosen.getLongVersionCode() > toUse.getLongVersionCode()) { ... } if (getWebViewLibrary(toUse.applicationInfo) == null) { ... } if (!signaturesEquals(chosen.signatures, toUse.signatures)) { ... } }

45.2.6 启动时间戳

WebViewFactory 通过内部类StartupTimestamps记录 WebView 加载各个阶段的详细耗时。时间戳通过WebViewDelegate.getStartupTimestamps()暴露给提供方,用于性能监控。

时间戳字段阶段
mWebViewLoadStart整体加载开始
mCreateContextStart/End创建 WebView APK 上下文
mAddAssetsStart/End注册资源路径
mGetClassLoaderStart/End获取 APK 类加载器
mNativeLoadStart/End带 RELRO 的 native so 库加载
mProviderClassForNameStart/End解析工厂类

45.2.7 RELRO 共享

WebView 加载的重要优化是 RELRO(Relocation Read‑Only)共享。Chromium 原生库(libwebviewchromium.so)体积很大,通常 50‑100MB。加载该库时动态链接器需要处理重定位,修正共享库内绝对地址。由于库被加载到预先预留的固定地址,所有进程处理完重定位结果完全一致。

WebViewLibraryLoader负责该优化:

源码位置:frameworks/base/core/java/android/webkit/WebViewLibraryLoader.java

Zygote 在 fork 任何应用之前完成地址空间预留:

static void reserveAddressSpaceInZygote() { System.loadLibrary("webviewchromium_loader"); long addressSpaceToReserve; if (VMRuntime.getRuntime().is64Bit()) { addressSpaceToReserve = 1 * 1024 * 1024 * 1024; // 64位:1 GB } else if (VMRuntime.getRuntime().vmInstructionSet().equals("arm")) { addressSpaceToReserve = 130 * 1024 * 1024; // ARM32:130 MB } else { addressSpaceToReserve = 190 * 1024 * 1024; // x86模拟器:190 MB } sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve); }

RELRO 文件由独立进程 RelroFileCreator 生成:加载库、处理重定位,将结果写入共享文件。

  • 32 位:/data/misc/shared_relro/libwebviewchromium32.relro
  • 64 位:/data/misc/shared_relro/libwebviewchromium64.relro

RELRO 文件使用:应用加载 WebView 时,直接映射已经预计算完成的 RELRO 文件,不再重复处理重定位,节省时间与内存(RELRO 页面对所有使用 WebView 的进程只读共享)。

45.3 WebView 提供方

45.3.1 提供方抽象模式

Android WebView 架构使用提供方模式,将公开 API 和实现解耦。三份接口定义该契约:

WebViewFactoryProvider是顶层工厂,每个进程单例,通过反射调用WebViewChromiumFactoryProviderForT.create()静态方法创建。提供:

  • 工厂方法,创建 WebViewProvider 实例(一个 WebView 控件对应一个实例)
  • CookieManager、WebStorage、GeolocationPermissions 等单例获取器
  • Statics 子接口,封装静态工具方法

WebViewProvider是实例级后端。android.webkit.WebView的每一个公开方法都会委托到此接口对应方法。包含两个子接口:

  • ViewDelegate:处理 View 层回调(绘制、触摸、按键、无障碍)
  • ScrollDelegate:滚动计算处理

45.3.2 WebView 的委托模式

android.webkit.WebView只是一层薄代理。它的构造函数调用ensureProviderCreated(),触发 45.2 描述的完整工厂加载流程:

private void ensureProviderCreated() { checkThread(); if (mProvider == null) { mProvider = getFactory().createWebView(this, new PrivateAccess()); } }

所有公开方法直接委托给提供方:

public void loadUrl(@NonNull String url) { checkThread(); mProvider.loadUrl(url); } public void evaluateJavascript(@NonNull String script, @Nullable ValueCallback<String> resultCallback) { checkThread(); mProvider.evaluateJavaScript(script, resultCallback); }

checkThread()强制 WebView 仅能在创建它的线程调用(一般为主 UI 线程)。Android17 该校验无条件生效:错误线程调用直接抛出 RuntimeException,不再依赖应用 targetSdkVersion。旧版本由sEnforceThreadChecking

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 15:37:09

fio-3.8.zip 安装实战:磁盘性能压测与IOPS/带宽解读

简介&#xff1a;fio-3.8.zip 是一份开源I/O性能测试工具FIO 3.8版本的源码压缩包&#xff0c;适合存储工程师、运维人员及性能调优开发者用于评估SSD、HDD、RAID等设备的读写吞吐、延迟与稳定性。压缩包共433个文件&#xff0c;以C语言源码&#xff08;148个.c&#xff09;、头…

作者头像 李华
网站建设 2026/9/1 15:35:34

基于向量数据库与SillyTavern的AI对话长期记忆系统实现

和AI聊天&#xff0c;最让人出戏的瞬间是什么&#xff1f;不是它偶尔的“一本正经胡说八道”&#xff0c;也不是它有时答非所问。而是当你聊得正酣&#xff0c;突然抛出一个半小时前提到的细节&#xff0c;它却一脸茫然地问你&#xff1a;“你刚才说的是什么&#xff1f;” 这种…

作者头像 李华
网站建设 2026/9/1 15:32:55

计算机毕业设计之基于Java Web的校园外卖系统的设计与实现

随着网络科学技术不断的发展和普及化&#xff0c;用户在寻找适合自己的信息管理系统时面临着越来越大的挑战。因此&#xff0c;本文介绍了一套校园外卖系统管理&#xff0c;在技术实现方面&#xff0c;本系统采用JAVA、HTML、CSS、JS以及MySQL数据库编程&#xff0c;使用spring…

作者头像 李华
网站建设 2026/9/1 15:25:40

Python数据分析实战:从零构建足球赛事数据模型与可视化

在数据分析领域&#xff0c;体育赛事&#xff0c;尤其是足球&#xff0c;是一个充满魅力的应用场景。通过公开的比赛数据&#xff0c;我们可以回溯历史&#xff0c;量化球队表现&#xff0c;甚至尝试理解那些决定冠军归属的微妙因素。2008-2009赛季的欧洲足坛&#xff0c;巴塞罗…

作者头像 李华
网站建设 2026/9/1 15:24:59

腾讯音乐数据科学秋招笔试复盘:统计、SQL与业务分析全解析

2023年腾讯音乐秋招数据科学岗的笔试&#xff0c;我是在线上完成的。整个笔试120分钟&#xff0c;题量不算少&#xff0c;题型分三大块&#xff1a;统计与机器学习客观题、SQL编程题、业务案例分析题。说实话&#xff0c;这套题的风格和我之前刷过的互联网大厂数据岗笔试差别挺…

作者头像 李华
网站建设 2026/9/1 15:24:58

2026答辩自述稿写作:AI工具避坑指南与实用建议

答辩季又到了&#xff0c;自述稿怎么写才稳妥 每年三四月&#xff0c;答辩季的焦虑感几乎笼罩着每一个毕业生。导师催着交终稿&#xff0c;查重报告刚过线&#xff0c;转头又要准备答辩自述稿。时间紧、任务重&#xff0c;不少人把目光投向AI工具&#xff0c;指望几分钟生成一…

作者头像 李华