HarmonyOS-ArkUI Web控件基础铺垫1-HTTP协议-数据包内容

HarmonyOS-ArkUI Web控件基础铺垫2-DNS解析

HarmonyOS-ArkUI Web控件基础铺垫3--TCP协议- 从规则本质到三次握手

HarmonyOS-ArkUI Web控件基础铺垫4--TCP协议- 断联-四次挥手解析

HarmonyOS-ArkUI Web控件基础铺垫5--TCP协议- 动画展示超时重传,滑动窗口,快速重传

HarmonyOS-ArkUI Web控件基础铺垫6--TCP协议- 流量控制算法与拥塞控制算法

HarmonyOS-ArkUI Web控件基础铺垫7-HTTP SSL认证图解 及 Charles抓包原理 及您为什么配置对了也抓不到数据

ArkUI的Web组件,其API体系非常壮大,Web组件API涉及100+, WebviewController接口涉及100+。 涵盖了浏览器相关的方方面面。我们之前已经用了大量的篇幅对其网络协议-HTTP 相关进行了详细的科普。现在终于到了对于 ArkWeb 本身的讲解。(ArkWeb 为真正实现 Web 组件底层能力的引擎。其能力包含:执行 前端程序代码,展示前端页面内容,导航,下载,上传等等)

下文内容无实战代码,以理论为主,帮助大家重点理解当鸿蒙的一个 Web 组件被写到界面的时候,会发生什么事情。以便于以后在工作中遇见了疑难问题,多一个解决问题的思路。

ArkWeb的进程模型

首先我们想象最简单的场景

如下方代码,假如我们的 APP 界面里写了一个 Web 组件,你的进程是什么样子的呢?

import { webview } from '@kit.ArkWeb';

@Entry
	@Component
	struct WebComponent {
		controller: webview.WebviewController = new webview.WebviewController();

		build() {
			Column() {
				Web({ src: 'www.example.com', controller: this.controller })
			}
		}
	}

在表面上看来,我们写入了一个 Web 组件,那么我们的手机就会展示了 Web 组件所设置的 Url 对应的网页的内容.一切都显得那么简单自然. 但真的那么简单吗? 实际上,我们的底层跑了很多的代码才完成了这个任务! 如果按照时间线的话,我们讲细一些, 十来个大步骤.

  • 将 Url 对应的资源下载下来: 浏览器下载资源采用的是 Http协议,所以我们之前用了很大的篇幅来讲 Http 相关的内容.现在可以串联起来了.
    • 用户输入 Url / 代码里设置的 Url 取到
    • 发起 Http 请求, 分为 DNS 解析-> TCP握手-> HTTPS 握手(加密相关) -> 服务器返回url 中指向的 html 文件字节流. 下载完的文件,放到共享内存区域. 便于后续其他进程的解析和渲染.
  • 将html 文件先根据其内容翻译成 DOM 树: 我们拿到了这个文件内容,接下来就干一个活, 将这个文件翻译成我们手机的界面. 这个工作鸿蒙默认并不是在 APP 进程中干的. 而是开了一个专门的渲染进程,做这件事情. 其环节也是比较复杂的
    • HTML 解析 → DOM 树: 收到 HTML 字节流(Bytes)→ 词法分析(Tokenizer)→ Token 流 → DOM 节点树。遇到 <link> CSS 和 <script> JS 会触发额外资源加载。注意这里的流程需要前端同学在写代码的时候注意, 有不慎可能会因加载顺序错位导致初始化数据状态不对.
    • CSS 解析 → CSSOM 树: 并行解析 CSS 文件(外部 link 和内联 style)。CSSOM 描述每个 DOM 节点的样式规则(选择器 → 属性值)。渲染阻塞资源:CSS 必须完全解析才能进入渲染树
  • 执行 JS 代码: 接下来会执行 JS 代码. 这个代码的执行位置实际上也是在这个渲染进程里完成的.其核心代码执行的是V8 引擎解释,即时编译我们的 JS 代码. 并执行这些逻辑. 如果这些逻辑又含有了改变我们 DOM 树的逻辑(前一个步骤就是搞 DOM 树的), 那么这个流程会再进到解析 DOM 这里.来改变我们的界面逻辑节点.
  • DOM + CSSOM → Render Tree(渲染树):Blink 合并 DOM 和 CSSOM,生成 Render Tree。只包含可见节点(display:none 的节点不出现在渲染树中)。每个 RenderObject 关联 DOM 节点和样式信息。
  • Layout(排版)→ 计算几何信息: 遍历 Render Tree,计算每个节点在视口中的精确位置(x, y, width, height)和堆叠顺序(z-index)。CSS 盒模型、Flexbox、Grid 的布局算法在此执行。回流(Reflow):布局改变会触发重新 Layout。 (PS: 走到这里是不是看到了 Android/HarmonyOS原生界面流程的影子呢?哈哈哈,桌面系统的布局方法论基本是一套.通用的!)
  • Paint → DisplayList(绘制指令列表):遍历 Render Tree,为每个可见像素生成绘制操作:DrawRect、DrawText、DrawImage、DrawLine... 按堆叠顺序(paint order)排列,存入 DisplayList。这个列表就是 GPU 的"食谱"。
  • Commit → 提交给 Compositor 线程: Blink 主线程将 Layer Tree(分层信息)和 DisplayList 通过 IPC Commit 到 Compositor 线程。主线程空闲,可以立即响应用户交互,不需要等待合成完成。
  • Compositor:分层 → 切 Tile: Compositor 线程分析页面,识别可以独立的图层(video、canvas、fixed 定位元素各自独立)。每个图层被切分成 256×256 或 512×512 的Tile(图块),以便并行 GPU 光栅化。
  • Raster Worker 线程池:矢量 → 位图(GPU Texture):多个 Raster Worker 线程并行处理不同 Tile。CPU/GPU 根据 DisplayList 绘制指令,把矢量图形渲染成 RGBA 位图(像素),然后通过 glTexImage2D / vkUpdateImage 上传到GPU 显存成为 Texture。
  • Compositor:合成最终帧:Compositor 线程把所有 Tile Texture 按正确的 z-order 叠加,生成最终帧的 GPU 绘制指令。通过共享内存零拷贝传递给 GPU 进程,不走 IPC 管道。

--------------自此我们 ArkWeb 体系的流程已经跑完了------------------------

  • 最后和原生组件的渲染图层合并处理后, 得到最终的帧放置到真缓冲区中. 等待VSync 信号(60Hz=16.7ms,120Hz=8.3ms)来了后,显示控制器自然会拿到这些数据展示上

这样捋下来是不是感觉故事立马丰富起来了呢...

好, 我们对以上流程有大致印象的基础上,看看华为官方给我们的 ArkWeb 实现出来的,进程模型.

下面阐述下, 当我们在代码里加了个 Web 组件的时候, 要将 Web 内容渲染到我们的屏幕上, 程序在执行的时候是怎么开启ArkWeb 各个关联模块,以联合实现从解析到展示全链路能力的. 实际上相当于一个大型工程跑起来时,"初始化"都开启了什么.

  • 首先我们的 UI 主线程会通过Binder 进行跨进程调用,以通知 Foundation 进程去处理我们的通知. -
  • Foundation 进程是专门处理Web 进程调度的.总调度中心相当于.当它接收到一个创建请求的时候,会通知 Web 孵化进程去孵化.
  • Web 孵化进程最终会根据我们传递的信息, 去选择到底是孵化 Web GPU 进程,还是 Web 渲染进程.
  • Web 渲染进程并不一定每次都会被孵化, 这取决于我们自己设置的共享模式.通常在移动设备上默认多个 Web 组件产生出来的浏览器,是共享同一个渲染进程的.而在 2in1 设备(二合一设备, 比如平板电脑二合一)是一个 Web 对应一个渲染进程. 当我么的渲染进程明显是共享渲染进程的时候,那么就不会 fork 新的渲染进程了.
  • 对于孵化出来的 Web Gpu 进程,也是有一定条件的, 通常是一个 App 进程就对应一个 Web 渲染进程.如果之前没有 Web GPU 进程, 则会 fork 一个新的出来.
  • 对于各个进程在一个 Web 浏览器中实现的能力,我们在图中已经给出阐述了.其基本可以对上我们前文讲的关键流程

对于上图来讲,显然, 核心就是这个 Web 渲染进程.

上图所示的进程内存模型

我个人觉得,我们在关注了关于 Web 要开启的进程种类之后, 是需要关注一下进程的内存模型的. 在手机系统中, 我们常常说存在堆, 栈, 比如 Android 程序,我们常常说我们的进程中有堆, 方法栈, 静态常量区, Native 区等等.事实上,对于手机内存在的所有进程都是这个模式么?? 其实不是的. 无论什么系统的手机, Android, IOS, HarmonyOS, 其正常工作时的进程内存,绝不仅仅是我们认为的 APP 进程内存那样. APP 进程仅仅是其中一种而已.

下图为 ArkUI 在执行 ArkWeb 事涉及到的进程模型. 我们关注这个至少应该懂得的是, 什么环节崩溃, 不会影响自己 App崩溃. 并且在崩溃的时候手机界面应该是什么样的表现.

在我们开启一个 Web 的时候, 如果这个 Web 对应的渲染进程发生了崩溃, 比如 JavaScript 本身崩溃了, 或者内存吃紧被系统回收了(Web渲染进程的优先级是低于App 进程的), 因其与 App 进程是两个完全独立的进程,原则上 Web渲染进程的崩溃并不会引发 App 进程的崩溃. 但是您应用程序的表现为: Web 里面的内容一动不动, 且里面的按钮.即使点击了,也没有任何响应.看着像是要 ANR 的样子. 但是,手机就是不报ANR 错误. 如果是做 H5 类互动游戏需求的需要格外注意这种问题, 选择在合适的实际进程刷新界面, 并同步最新的数据.

在 ArkWeb 中,如果底层的渲染进程发生崩溃实际上我们是可以接到回调的.

onRenderExited()

如以下代码:

// xxx.ets
import { webview } from '@kit.ArkWeb';

@Entry
  @Component
  struct WebComponent {
    controller: webview.WebviewController = new webview.WebviewController();

    build() {
      Column() {
        Web({ src: 'chrome://crash/', controller: this.controller })
          .onRenderExited((event) => { // 渲染进程崩溃回调
            if (event) {
              console.log('reason:' + event.renderExitReason);
            }
          })
      }
    }
  }

Web 渲染进程

渲染进程是 ArkWeb 的心脏.其中它在运行的时候也会实现几条线程.其中有个比较著名的线程(业界基本是这个名字)--Blink主线程,是负责 HTML→DOM→RenderTree→Layout→Paint 核心能力的线程.

具体如下图所示:

  • Blink 主线程典型任务序列(Chrome DevTools Performance 可视化)
    • HTMLParser: 解析 HTML 字节 → Token → DOM 节点
    • UpdateLayoutTree: CSS 计算 + 样式匹配
    • Layout: 计算几何位置 (x, y, width, height)
    • Paint: 生成绘制记录列表 DrawOps[]
    • Commit: 将 PaintOp[] 提交给 Compositor 线程
  • Compositor 线程(主线程提交后立即执行,不等待)
    • 分层(TransformLayer, PictureLayer...)
    • 切 Tile(256×256px)
    • 调度 Raster 任务到 Worker 线程池
  • Raster Worker 线程池(CPU 多核并行)
    • 接收:PaintOp[](矢量绘制指令)
    • 输出:RGBA 位图(像素数据)
    • 上传:glTexImage2D → GPU Texture

上述基本是渲染进程的职责, 但是如果您仔细观察的话, 不难看出,这个渲染进程里面竟然没有关于下载(HTML

资源下载)的功能。那么这个资源是谁下载的呢? 答案是您的 APP 进程负责下载, 我们看之前的图中被忽视的一部分:

在我们的应用App进程里面,会同时开一些 Web 相关的线程,这个线程中负责下载资源。我们在开发实践中, 往往会遇到网络资源下载太慢引发的,Web与原生的桥接方法不被调用, 或者白屏等问题, 针对这个问题,我们会采用首先在本地工程预置一些网页资源, 然后等到运行的时候,download 执行的时候可以进行拦截, 返回我们本地的预置资源。与此同时进行正常的网页资源下载。这些逻辑均是在我们APP 进程执行的, 我们实现下载逻辑的时候也不必考虑跨进程这些操作。如果允许的话,我们甚至可以完全实现一套自己的下载套件。

有关于 App 此时的线程模型(了解)

常见问题及解决思路

上述文章已经大致讲完了从输入一个 Url 到页面呈现在屏幕上的所有环节,下面讲一下这些环节中经常会出现的问题。

  • 下载前环节
    • 首次打开 Web直接全白屏, 重试正常
      • 部分机型会出现Web 进程 Fork 超时的问题,或者 IPC 通信阻塞, 很少见。
        • 解: 可以提前预热渲染进程,关键业务提前创建不可见的 Web 组件。不过鸿蒙的 Web 组件visiable不可设置为None,这样底层是不加载的。可考虑设置 invisiable
  • 下载资源环节
    • JS 资源下载阻塞→H5 无法调用原生 JSBridge(高频问题):HTML 在资源下载的时候,HTML 资源或者其标签内引用的 JS 资源并没有下载下来。具体表现为:如果您的代码里涉及到 H5 调用原生或者原生调用H5,尤其是首次交互是从 H5 调用到原生的。可能会出现原生代码不被调用的问题。(因 JS 没有下载下来)解决方法有很多种:
      • 解:将目标 JS 的引入标签适当前置。有时候这种标签会因写的过于靠后,前面的资源下载卡住了,它的下载也不会开启。这个可以和前端同学配合来考虑如何调整。采用什么样的下载模式。
      • 解:App 内置一些关键的资源。这样就不会涉及到远程下载问题。
      • 解:监听onPageFinish页面加载完成回调后再执行 JS 注入 / 调用。
    • 页面切换后回退 Web 空白(页面优先级导致下载降级):鸿蒙Web所处的页面位置,导致下载线程优先级降级的问题。 当 A 与 B 界面同时存在一个 WebA, WebB 的时候。如果 A 界面刚开开,然后跳转到 B 界面。此时 ArkUI 会根据页面的优先级,将 B 页面 WebB 的资源下载的优先级设置为高, 而原先的A 界面的 WebA 的资源下载优先级会被降低。如果您的 WebA 资源非常重要,是需要考虑这些问题的。有可能会出现 B 退到 A 的时候,A 界面仍旧没有加载好。如果您发现 JSBridge 没有按照预期调用,这是一个参考维度。
      • 解:对关键页面 Web 设置webCache强制缓存 HTML/JS 资源
    • HTTPS 证书异常导致资源下载失败、整页白屏:下载环节隐性问题,SSL 证书过期 / 自签证书,HTTPS 握手失败,所有资源无法下载。
      • 解:开发环境通过 Web 配置忽略证书校验,生产环境使用合法 CA 证书。
  • 下载后的环节
    • 跨域问题, 详见我之前写的内容: Web跨域资源共享-CORS 是什么-CSDN博客
    • 渲染线程崩溃问题。当渲染线程崩溃的时候,我们的 APP 并不会因此崩溃。渲染线程崩溃的原因有很多,最常见的有以下
      • 前端代码崩溃,JS 代码书写不当导致
      • 手机内存吃紧需要释放资源,也会将 Web 进程给杀掉
      • 当我们采用非共享渲染进程的模式来开发时,如果不断开新的 web,到达一定数量(查资料是 10 个),但是我实测并非如此,可能和设备有关,但是的确存在开太多, 之前的渲染引擎被销毁的情况 (代码设置监听,可以捕获到渲染进程销毁的事件。)
        • 对于这个环节我们最好监听一下销毁事件,并收集被销毁的原因。这个原因往往反馈着一些不合理的细节。是值得参考。
        • 对于渲染进程崩溃,存在一些不可控制的因素,我们可以在监听到进程销毁的时候,reload 一下以恢复。
        • 对于规避渲染进程开太多的问题, 可以按需即时关闭不需要运行的 web 页面。
    • 页面卡顿,滚动掉帧:这个一般是 HTML 内部代码实现的时候 DOM修改频繁,大量回流所致。
      • 这个主力在于前端同学进行优化。
      • 客户端开启 ArkWeb 硬件加速。
    • 页面样式错乱、元素位置异常:CSS 资源下载失败、CSSOM 生成不全、DOM 加载完成后异步 CSS 再次修改样式触发多次回流
      • 解:关键 CSS 内联到 HTML,减少外链 CSS 阻塞。
      • 关于优化

        上述图中的每个环节都有可优化的地方。每一种优化又是一个非常大的话题。例如

      • 客户端 ArkWeb内核参数调优
      • 下载优化
        • 关联到网络优化大课题
          • 网络优化做到极致,从协议选择,传输数据选择,传输数据压缩,协议本身调参与测试,全局的数据上报,后台的数据分析, 后台的智能路线选择,端上的 DNS 维护等等,是一个和庞大的话题。
        • 图片优化
      • 缓存优化
        • 离线优化
      • 捕获优化点
        • 全局架构异常捕获与上报分析系统
      • 等等
      • 这里面的每一个环节,如果深入研究均会涉及到很庞大的知识体系。用到时需要根据各个环节来考虑优化的点,以及采取的技术手段。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐