文档 / 架构

架构

执行边界、共用 C 核心、WebAssembly 打包与补丁兼容性。

库保留一套补丁实现,并通过三种运行时适配器暴露。

执行路径

React Native JavaScript
  -> 强类型公开 API
  -> TurboModule 或旧桥接
  -> 平台自有串行工作队列
  -> JNI / Objective-C++
  -> 共用 bsdiff + bzip2 C 源码

React Native Web
  -> 强类型公开 API
  -> 共享或取消任务专用的模块 Web Worker
  -> Emscripten MEMFS
  -> 由同一套 bsdiff + bzip2 C 源码编译的 WebAssembly

Worker 边界让高开销二进制计算离开 JavaScript / UI 线程,但不会消除算法成本。 调用方仍需设置符合产品场景的输入大小和时间限制。

未传 AbortSignal 的 Web 调用复用一个 Worker 和已缓存的 Emscripten 模块,避免 重复初始化 Worker 与 WebAssembly。带 signal 的调用使用专用 Worker,取消 signal 只会终止该 Worker。每个 Worker 在自己的队列内串行执行,并在每次操作后删除 MEMFS 临时文件。

补丁线格式

补丁以 24 字节头开始:

字节内容
0..15ASCII magic ENDSLEY/BSDIFF43
16..23该格式字节序下的有符号 64 位目标大小
24..bzip2 压缩的控制、差分和附加数据

Web 适配器进入 C patch 函数前会校验头和签名。原生与 Web 使用同一份已检入的 bsdiff 和 bzip2 源码,从而保持跨平台兼容。

格式能标识补丁实现,但不标识预期基线或发布版本。分发补丁时,应用应在可信清单中 携带基线和目标摘要。

WebAssembly 打包

scripts/build-web-wasm.sh 使用 Emscripten 生成:

  • ES module 工厂;
  • 单文件内嵌 WebAssembly payload;
  • 可增长内存;
  • MEMFS 以及 FS / ccall 运行时方法;
  • 导出的 bsDiffFilebsPatchFile 函数。

生成的 web/bsdiffpatch.mjs 随 npm 包发布,消费者无需安装 Emscripten。

兼容性验证

仓库内 golden fixture 证明 Web 实现生成的确定性补丁字节可被 Android 与 iOS 消费。设备运行时测试还会应用 Web golden patch,并验证截断补丁会被拒绝且不会 留下残缺输出。C patch 核心具有 sanitizer 支持的畸形输入 fuzz 覆盖,非法数据不会 终止宿主进程。

Web 参考基准

yarn benchmark:web 使用每 4 KiB 修改一个字节的确定性输入,并逐字节验证还原 结果。在 Apple M3 Pro、Node 26.5.0 上,仓库记录的 2026-07-19 基准如下:

输入DiffPatch补丁字节数
1 MiB158.5 ms7.7 ms110
10 MiB4,243.6 ms57.5 ms118
50 MiB30,697.5 ms285.2 ms203

这些数据是可复现的开发基线,不是设备或浏览器性能保证。输入相似度、CPU、浏览器、 内存压力和工具链版本都会显著影响结果。完整机器可读记录位于 benchmarks/web-wasm.json

内存模型

原生操作会把旧文件与目标文件读入进程内存。Web 调用先复制输入再传给 Worker, 之后从 MEMFS 复制结果,因此峰值内存可能达到输入或输出大小的数倍。

对于大更新,应在调用前执行应用级大小限制。完整文件无法安全放入内存时,应考虑 服务端或流式更新策略。

职责边界

库负责补丁计算和平台调度;应用负责:

  • 文件选择、存储权限和临时文件清理;
  • 补丁传输与缓存策略;
  • 来源认证与密码学完整性校验;
  • 并发、大小和时间限制;
  • 还原结果验证和原子替换。

这些职责保留在补丁引擎外,便于应用复用已有文件系统和发布信任模型。

兼容规则

补丁兼容性由 magic 与实现共同决定,而不只是通用名称“bsdiff”。来自其他包的 BSDIFF40 补丁不是受支持输入。跨 Android、iOS 与 Web 时,应使用本库成对生成 和应用补丁。