react-native-update 10.53.1 → 10.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-CN.md +31 -31
- package/README.md +31 -31
- package/android/jni/HDiffPatch/.travis.yml +33 -0
- package/android/jni/HDiffPatch/builds/xcode/bestParams.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/android/jni/HDiffPatch/builds/xcode/hdiffz.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/android/jni/HDiffPatch/builds/xcode/hdiffz.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/android/jni/HDiffPatch/builds/xcode/hpatchz.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/android/jni/HDiffPatch/builds/xcode/lz4.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/android/jni/HDiffPatch/builds/xcode/lzma.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/android/jni/HDiffPatch/builds/xcode/testHashClash.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/android/jni/HDiffPatch/builds/xcode/testHashClash.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/android/jni/HDiffPatch/builds/xcode/unitTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/android/jni/HDiffPatch/builds/xcode/zstd.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/android/jni/lzma/DOC/7zC.txt +187 -0
- package/android/jni/lzma/DOC/7zFormat.txt +469 -0
- package/android/jni/lzma/DOC/Methods.txt +173 -0
- package/android/jni/lzma/DOC/installer.txt +166 -0
- package/android/jni/lzma/DOC/lzma-history.txt +446 -0
- package/android/jni/lzma/DOC/lzma-sdk.txt +357 -0
- package/android/jni/lzma/DOC/lzma-specification.txt +1176 -0
- package/android/jni/lzma/DOC/lzma.txt +328 -0
- package/android/jni/lzma/bin/7zS2.sfx +0 -0
- package/android/jni/lzma/bin/7zS2con.sfx +0 -0
- package/android/jni/lzma/bin/7zSD.sfx +0 -0
- package/android/jni/lzma/bin/7zdec.exe +0 -0
- package/android/jni/lzma/bin/7zr.exe +0 -0
- package/android/jni/lzma/bin/installer/config.txt +5 -0
- package/android/jni/lzma/bin/installer/cr.bat +5 -0
- package/android/jni/lzma/bin/lzma.exe +0 -0
- package/android/jni/lzma/bin/x64/7zr.exe +0 -0
- package/android/lib/arm64-v8a/librnupdate.so +0 -0
- package/android/lib/armeabi-v7a/librnupdate.so +0 -0
- package/android/lib/x86/librnupdate.so +0 -0
- package/android/lib/x86_64/librnupdate.so +0 -0
- package/android/src/main/java/cn/reactnative/modules/update/ArchiveLimits.java +44 -0
- package/android/src/main/java/cn/reactnative/modules/update/DownloadTask.java +124 -40
- package/android/src/main/java/cn/reactnative/modules/update/InstallRecord.java +125 -0
- package/android/src/main/java/cn/reactnative/modules/update/NativeCheckOrchestrator.java +43 -11
- package/android/src/main/java/cn/reactnative/modules/update/NativeUpdateFlow.java +2 -0
- package/android/src/main/java/cn/reactnative/modules/update/SafeZipFile.java +90 -0
- package/android/src/main/java/cn/reactnative/modules/update/UpdateContext.java +79 -19
- package/android/src/main/java/cn/reactnative/modules/update/UpdateFileUtils.java +21 -0
- package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleImpl.java +33 -2
- package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleSupport.java +1 -0
- package/android/src/newarch/cn/reactnative/modules/update/UpdateModule.java +5 -0
- package/android/src/oldarch/cn/reactnative/modules/update/UpdateModule.java +5 -0
- package/cpp/patch_core/archive_limits.h +38 -0
- package/cpp/patch_core/install_record.h +36 -0
- package/cpp/update_flow_core/flow_json.h +1 -0
- package/cpp/update_flow_core/update_flow_core.cpp +41 -7
- package/cpp/update_flow_core/update_flow_core.h +9 -0
- package/cpp/update_flow_core/update_flow_jni.cpp +12 -0
- package/harmony/pushy/src/main/cpp/PushyTurboModule.cpp +2 -0
- package/harmony/pushy/src/main/cpp/pushy.cpp +37 -0
- package/harmony/pushy/src/main/ets/ArchiveLimits.ts +83 -0
- package/harmony/pushy/src/main/ets/DownloadTask.ts +126 -30
- package/harmony/pushy/src/main/ets/InstallRecord.ts +129 -0
- package/harmony/pushy/src/main/ets/NativeCheckOrchestrator.ts +24 -2
- package/harmony/pushy/src/main/ets/NativePatchCore.ts +5 -0
- package/harmony/pushy/src/main/ets/PushyTurboModule.ts +12 -0
- package/harmony/pushy/src/main/ets/UpdateContext.ts +78 -15
- package/harmony/pushy.har +0 -0
- package/ios/RCTPushy/RCTPushy.mm +384 -25
- package/ios/RCTPushy/RCTPushyDownloader.mm +32 -0
- package/package.json +25 -2
- package/src/NativePushy.ts +13 -0
- package/src/client.ts +160 -43
- package/src/core.ts +17 -3
- package/src/error.ts +3 -0
- package/src/index.ts +8 -0
- package/src/locales/en.ts +3 -0
- package/src/locales/zh.ts +2 -0
- package/src/metadata.ts +166 -0
- package/src/provider.tsx +52 -17
- package/src/type.ts +22 -0
- package/src/updateFlowCore.ts +95 -4
- package/src/utils.ts +31 -19
- package/.gitmodules +0 -6
- package/BUNDLEHASH_MIGRATION.md +0 -355
- package/NATIVE_CHECKUPDATE_DESIGN.md +0 -539
- package/NATIVE_CHECK_FOLLOWUPS.md +0 -514
- package/android/jni/HDiffPatch/test/_private_searchBestParams.cpp +0 -301
- package/android/jni/HDiffPatch/test/hpatchz_test.cpp +0 -292
- package/android/jni/HDiffPatch/test/testHashClash.cpp +0 -436
- package/android/jni/HDiffPatch/test/unit_test.cpp +0 -417
- package/biome.json +0 -59
- package/cpp/patch_core/tests/fixtures/rawstored.lzma2label.patch.bin +0 -0
- package/cpp/patch_core/tests/fixtures/rawstored.new.bin +0 -0
- package/cpp/patch_core/tests/fixtures/rawstored.old.bin +0 -0
- package/cpp/patch_core/tests/fixtures/v96.hbc +0 -0
- package/cpp/patch_core/tests/fixtures/v96.meta.json +0 -1
- package/cpp/patch_core/tests/fixtures/v96.streampatch.bin +0 -0
- package/cpp/patch_core/tests/fixtures/v96.t.hbc +0 -0
- package/cpp/patch_core/tests/fixtures/v96.tpatch.bin +0 -0
- package/cpp/patch_core/tests/fixtures/v96.tstreampatch.bin +0 -0
- package/cpp/patch_core/tests/fixtures/v96b.hbc +0 -0
- package/cpp/patch_core/tests/fixtures/v98.hbc +0 -0
- package/cpp/patch_core/tests/fixtures/v98.t.hbc +0 -0
- package/cpp/patch_core/tests/fixtures/v98b.hbc +0 -0
- package/cpp/patch_core/tests/fixtures/v98b.t.hbc +0 -0
- package/cpp/patch_core/tests/hbc_transform_test.cpp +0 -384
- package/cpp/patch_core/tests/patch_core_test.cpp +0 -970
- package/cpp/update_flow_core/tests/flow_vectors.json +0 -1401
- package/cpp/update_flow_core/tests/update_flow_core_test.cpp +0 -317
- package/scripts/check-expo-version.js +0 -92
package/README-CN.md
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
### 优势
|
|
20
20
|
|
|
21
21
|
1. 对中国用户使用阿里云高速 CDN 分发,对比其他服务器在国外的热更新服务,分发更稳定,更新成功率极高。海外用户智能分流至 cloudflare,同样提供稳定高速的分发体验。
|
|
22
|
-
2. 基于 bsdiff/hdiff 算法创建的**超小更新包**,通常版本迭代后在几十至几百 KB 级别(其他全量热更新服务所需流量通常在几十 MB
|
|
22
|
+
2. 基于 bsdiff/hdiff 算法创建的**超小更新包**,通常版本迭代后在几十至几百 KB 级别(其他全量热更新服务所需流量通常在几十 MB 级别)。整条链路更是**针对 Hermes 字节码做了专门优化**——单行改动只需下发 **3.4 KB**(详见下方[算法对比](#diff-算法对比));最新的优化都发生在构建期,**已上架的应用只需重新构建一次发版即可受益**。
|
|
23
23
|
3. 始终跟进 RN 最新正式版本,第一时间提供支持。支持 hermes 字节码格式。支持新架构(注:安卓 0.73.0 ~ 0.76.0 的新架构因官方 bug 不支持,0.73 以下或 0.76.1 以上的新架构可用)。
|
|
24
24
|
4. 跨越多个版本进行更新时,只需要下载**一个更新包**,不需要逐版本依次更新。
|
|
25
25
|
5. 命令行工具 & 网页双端管理,版本发布过程简单便捷,完全可以集成 CI。
|
|
@@ -30,49 +30,49 @@
|
|
|
30
30
|
10. **原生冷启动自愈**:即使热更版本坏到 JS 完全跑不起来(白屏、启动即崩),设备也能在下次启动时由原生侧自动拉到修复版——不需要用户重装,也不需要你发新的应用商店版本(详见下方[原生冷启动检测](#原生冷启动检测))。
|
|
31
31
|
11. 提供付费的专人技术支持。
|
|
32
32
|
|
|
33
|
-
###
|
|
34
|
-
|
|
35
|
-
自 10.52.1 起,每次冷启动后数秒会在后台线程执行一次**不依赖 app bundle** 的更新检查(下载、打补丁与状态切换全部在原生侧完成)。它的存在只为一件事:**当前热更版本坏到 JS 起不来时,仍有一条能把修复版拉下来的通路**——常规更新流程仍由应用内的 JS 负责,检查结果会被 JS 侧复用,不会重复请求。
|
|
36
|
-
|
|
37
|
-
几个需要知道的点:
|
|
33
|
+
### Diff 算法对比
|
|
38
34
|
|
|
39
|
-
|
|
40
|
-
- **是否自动激活取决于你的配置**:`updateStrategy` 为 `silentAndNow` / `silentAndLater` 且未关闭自动检查(`checkStrategy` 不为 `null`)时,原生侧才会把下载好的版本设为下次启动生效;其余情况只下载,激活权仍在 JS。
|
|
41
|
-
- **救砖指令**:控制台可按版本标记「强制启动」,被标记的版本无视上述策略直接在下次启动生效——这是把已被坏版本卡死的设备捞回来的手段。设备本地的崩溃回滚保护仍然优先,已回滚过的版本不会被再装回去。
|
|
42
|
-
- **崩溃时刻救援**(Android 与 iOS):应用在启动阶段死于未捕获的 JS 错误时,SDK 会短暂扣住垂死的进程(数秒、有硬上限),把检查与下载做完——即使版本每次启动零点几秒就崩,也能被换掉。该窗口内下载到的修复版一律设为下次启动生效(JS 已经没有机会做决策了)。崩溃上报不受影响:SDK 以链式方式保存并在结束后调用原有的崩溃处理器。不覆盖:原生(非 JS)崩溃、ANR、OOM 击杀,以及 iOS 上安装了自定义 `RCTSetFatalHandler` 的应用(那时 React Native 不再抛出本机制拦截的异常)。
|
|
43
|
-
- **断点续传**:更新下载在进程死亡后保留进度、下次以 HTTP Range 续传,反复的短命启动也能单调累积进度;紧随中断轮次的下一次启动会跳过延迟立即续传。鸿蒙不需要崩溃时刻扣留:RNOH 下未捕获的 JS 错误不会杀死进程,JS 启动即崩时原生检测照常完成。
|
|
44
|
-
- **可以关闭**:`disableNativeCheck: true`。关闭后每次冷启动少一次后台请求,代价是**放弃上述自愈能力**——被坏热更卡死的设备将无法自动恢复。仅在这次请求本身构成问题时(流量/耗电预算、隐私清单申报、需用户同意后才可联网)才建议关闭。
|
|
35
|
+
Hermes 字节码对通用二进制 diff 极不友好,我们在两个环节同时下手,且收益叠加:
|
|
45
36
|
|
|
46
|
-
|
|
37
|
+
- **delta 模式编译**。Hermes **每次**编译都会重排字符串表,JS 改一行就会让大部分字符串 ID 重新编号,两份几乎相同的字节码于是处处不同。`bundle` 会以同一应用更早的一份字节码为基准编译(`hermesc -base-bytecode=…`),把这些 ID 钉死在原位,只有真正的改动才会进入 diff。
|
|
38
|
+
- **HBC 感知的可逆变换**。Hermes 字节码中还有大量"偏移量表",中间插入几个字节就会令其后所有偏移整体位移。我们在 hdiff 之前引入一层 **delta-friendly 可逆变换**,对偏移位域做前项差分,把整体位移退化为单点变化。布局描述表随补丁下发,Hermes 版本演进时**客户端零升级**。
|
|
47
39
|
|
|
48
|
-
|
|
40
|
+
此外字节码在产出时就不含 debug info 段(实测小 **21%**,与 React Native 自身 release 构建一致),全量包和由它派生的每一个补丁都随之变小。
|
|
49
41
|
|
|
50
|
-
以下数据在真实 RN 0.86 应用的 release 产物上实测(Hermes HBC v98,字节码约 4.4 MB
|
|
42
|
+
以下数据在真实 RN 0.86 应用的 release 产物上实测(Hermes HBC v98,字节码约 4.4 MB)。每个补丁都先通过完整往返校验再记录体积,每个 delta 模式产物都通过与普通编译的等价性校验。完整的评测方法、测试数据与可复现代码见 **[hbc-diff-benchmark](https://github.com/sunnylqm/hbc-diff-benchmark)**。
|
|
51
43
|
|
|
52
44
|
**Hermes 字节码(.hbc)——生产环境 Hermes 应用的实际发包格式:**
|
|
53
45
|
|
|
54
|
-
| 迭代场景 | 全量 OTA(gzip) | bsdiff |
|
|
55
|
-
|
|
56
|
-
| 单行文案修改 | 1901.5 KB | 93.7 KB |
|
|
57
|
-
| 小功能(约 60 行) | 1913.9 KB | 411.6 KB |
|
|
58
|
-
| 中等功能(约 300 行) | 1973.7 KB | 551.6 KB |
|
|
46
|
+
| 迭代场景 | 全量 OTA(gzip) | bsdiff | **react-native-update** | 对比 bsdiff |
|
|
47
|
+
|---|---|---|---|---|
|
|
48
|
+
| 单行文案修改 | 1901.5 KB | 93.7 KB | **3.4 KB** | **小 28 倍** |
|
|
49
|
+
| 小功能(约 60 行) | 1913.9 KB | 411.6 KB | **50.2 KB** | **小 8.2 倍** |
|
|
50
|
+
| 中等功能(约 300 行) | 1973.7 KB | 551.6 KB | **97.8 KB** | **小 5.6 倍** |
|
|
59
51
|
|
|
60
52
|
**文本 JS bundle——非 Hermes 应用(同一应用、同样三个场景):**
|
|
61
53
|
|
|
62
|
-
| 迭代场景 | 全量 OTA(gzip) | bsdiff |
|
|
63
|
-
|
|
64
|
-
| 单行文案修改 | 807.2 KB | 0.3 KB |
|
|
65
|
-
| 小功能(约 60 行) | 813.1 KB | 7.4 KB |
|
|
66
|
-
| 中等功能(约 300 行) | 837.7 KB | 38.4 KB |
|
|
54
|
+
| 迭代场景 | 全量 OTA(gzip) | bsdiff | **react-native-update** |
|
|
55
|
+
|---|---|---|---|
|
|
56
|
+
| 单行文案修改 | 807.2 KB | 0.3 KB | **0.1 KB** |
|
|
57
|
+
| 小功能(约 60 行) | 813.1 KB | 7.4 KB | **5.8 KB** |
|
|
58
|
+
| 中等功能(约 300 行) | 837.7 KB | 38.4 KB | **28.7 KB** |
|
|
67
59
|
|
|
68
|
-
文本 bundle
|
|
60
|
+
文本 bundle 既没有偏移量表也没有字符串表重排,diff 天然干净——补丁只有几百字节到几十 KB。上述两项优化所消除的放大效应是 Hermes 字节码特有的问题,这正是它们存在的意义。
|
|
69
61
|
|
|
70
62
|
要点:
|
|
71
63
|
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
-
|
|
64
|
+
- 单行修复——也是最常见的热更类型——只需下发 **3.4 KB**,比全量 OTA 少 559 倍。
|
|
65
|
+
- 生成补丁比 bsdiff 快 **2~4 倍**,变换本身开销仅个位数毫秒。
|
|
66
|
+
- 每一环都有安全兜底:改写任何字节前先做全量校验,delta 模式产物要与普通编译结果比对,任一环节不匹配都自动回退到原有行为。
|
|
67
|
+
|
|
68
|
+
### 原生冷启动检测
|
|
69
|
+
|
|
70
|
+
自 10.52.1 起,每次冷启动后数秒会在后台线程执行一次**不依赖 app bundle** 的更新检查(下载、打补丁与状态切换全部在原生侧完成)。它的存在只为一件事:**当前热更版本坏到 JS 起不来时,仍有一条能把修复版拉下来的通路**——常规更新流程仍由应用内的 JS 负责,检查结果会被 JS 侧复用,不会重复请求。
|
|
71
|
+
|
|
72
|
+
- **不阻塞启动**:延迟数秒、跑在后台线程,成果在**下次启动**生效。下载到的版本是否自动激活取决于你的 `updateStrategy` / `checkStrategy`;否则只下载,激活权仍在 JS。
|
|
73
|
+
- **崩溃时刻救援**(Android 与 iOS):应用在启动阶段死于未捕获的 JS 错误时,SDK 会短暂扣住垂死的进程把检查与下载做完——即使版本每次启动零点几秒就崩,也能被换掉。崩溃上报不受影响:SDK 以链式方式保存并在结束后调用原有的崩溃处理器。不覆盖:原生崩溃、ANR、OOM 击杀,以及 iOS 上安装了自定义 `RCTSetFatalHandler` 的应用。
|
|
74
|
+
- **救砖指令**:控制台可按版本标记「强制启动」,被标记的版本无视上述策略直接在下次启动生效——这是把已被坏版本卡死的设备捞回来的手段。设备本地的崩溃回滚保护仍然优先,已回滚过的版本不会被再装回去。
|
|
75
|
+
- **可以关闭**:`disableNativeCheck: true`。关闭后每次冷启动少一次后台请求,代价是**放弃上述自愈能力**——被坏热更卡死的设备将无法自动恢复。
|
|
76
76
|
|
|
77
77
|
### 与其他热更新库对比
|
|
78
78
|
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
| **灰度发布** | ✅ 后台自带,按比例逐步放量 | ✅ 支持 | ❌ **已停运** |
|
|
93
93
|
| **数据统计** | ✅ 后台自带(版本分布、更新成功率等) | ⚠️ 有限 | ❌ **已停运** |
|
|
94
94
|
| **健康度监控** | ✅ 后台自带版本健康度监控 | ❌ 不支持 | ❌ **已停运** |
|
|
95
|
-
| **Hermes 专项 diff 优化** | ✅ HBC
|
|
95
|
+
| **Hermes 专项 diff 优化** | ✅ delta 模式编译 + HBC 结构感知变换,补丁更小 | ❌ 全量更新 | ❌ **已停运** |
|
|
96
96
|
| **管理界面** | ✅ 命令行工具 + Web 管理界面 | ✅ Expo Dashboard | ❌ **已停运** |
|
|
97
97
|
| **CI/CD 集成** | ✅ 支持 | ✅ 支持 | ❌ **已停运** |
|
|
98
98
|
| **API 扩展性** | ✅ Meta 信息 + 开放 API | ⚠️ 有限 | ❌ **已停运** |
|
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ See the docs:
|
|
|
17
17
|
## Advantages
|
|
18
18
|
|
|
19
19
|
1. react-native-update provides a dedicated global service with fast and reliable worldwide delivery.
|
|
20
|
-
2. **Tiny update packages** generated with bsdiff/hdiff are typically only tens to hundreds of KB, instead of the tens of MB usually required by full-bundle update systems.
|
|
20
|
+
2. **Tiny update packages** generated with bsdiff/hdiff are typically only tens to hundreds of KB, instead of the tens of MB usually required by full-bundle update systems. The whole pipeline is **specifically optimized for Hermes bytecode** — a one-line change ships in **3.4 KB** (see the [comparison below](#diff-algorithm-comparison)), and because the newest optimizations happen at build time, **apps already in the store benefit from nothing more than a rebuild**.
|
|
21
21
|
3. The library tracks new React Native stable releases closely, supports Hermes bytecode, and supports the new architecture. Note: Android RN 0.73.0 to 0.76.0 new architecture is unavailable because of upstream issues; versions below 0.73 or above 0.76.1 are supported.
|
|
22
22
|
4. When updating across multiple versions, clients only need to download **one update package** instead of applying every intermediate version in sequence.
|
|
23
23
|
5. Command-line tools and a web dashboard are both available, making release workflows simple and CI-friendly.
|
|
@@ -28,49 +28,49 @@ See the docs:
|
|
|
28
28
|
10. **Native cold-start recovery**: even when an update is broken badly enough that JS never runs (white screen, crash on launch), the device pulls the fixed version on its next launch from the native side — no reinstall, no app-store release (see [Native cold-start check](#native-cold-start-check)).
|
|
29
29
|
11. Paid technical support is available.
|
|
30
30
|
|
|
31
|
-
##
|
|
32
|
-
|
|
33
|
-
Since 10.52.1 every cold start runs one background update check a few seconds after launch that **does not depend on the app bundle** — the request, the download, the patch and the version switch all happen natively. It exists for exactly one reason: **when the running update is broken enough that JS never starts, something still has to be able to fetch the fix.** Normal updates remain the JS flow's job; the JS check reuses this result instead of issuing its own request.
|
|
34
|
-
|
|
35
|
-
What to know:
|
|
31
|
+
## Diff Algorithm Comparison
|
|
36
32
|
|
|
37
|
-
|
|
38
|
-
- **Whether it activates depends on your configuration**: only with `updateStrategy` set to `silentAndNow` / `silentAndLater` *and* automatic checks left on (`checkStrategy` not `null`) will the native side mark a downloaded version for the next launch. Otherwise it downloads and leaves activation to JS.
|
|
39
|
-
- **Rescue directive**: the dashboard can mark a version "force boot", which activates on the next launch regardless of the strategies above — this is how a fleet stuck on a broken version is recovered. The device-local crash-rollback guard still wins: a version this device already rolled back from is never reinstalled.
|
|
40
|
-
- **Crash-moment rescue** (Android & iOS): when the app dies of an uncaught JS error during startup, the SDK briefly holds the dying process (a few seconds, bounded) to finish the check and download — so even a version that crashes a fraction of a second into every launch gets replaced. In that window the downloaded fix is always activated for the next launch, since JS is no longer around to decide. Crash reporters keep working: the SDK chains the previous crash handler and always hands the crash over afterwards. Not covered: native (non-JS) crashes, ANRs, OOM kills, and — on iOS — apps that install a custom `RCTSetFatalHandler` (React Native then no longer raises the exception this rescue intercepts).
|
|
41
|
-
- **Resumable downloads**: update downloads survive process death and resume from where they stopped (HTTP Range), so repeated short-lived launches still make monotonic progress; a launch that follows an interrupted round skips the startup delay and resumes immediately. HarmonyOS does not need the crash-moment hold: an uncaught JS error does not kill the process there, so the native check completes normally even when JS dies on launch.
|
|
42
|
-
- **It can be turned off**: `disableNativeCheck: true` removes one background request per cold start, at the cost of **giving up the recovery above** — a device bricked by a bad update can no longer heal itself. Choose it only when that request is itself the problem (traffic/battery budgets, privacy manifests, consent-gated networking).
|
|
33
|
+
Hermes bytecode is hostile to generic binary diffing, and we attack that at two points that stack:
|
|
43
34
|
|
|
44
|
-
|
|
35
|
+
- **Delta-mode compilation.** Hermes re-sorts its string table on **every** compile, so a one-line JS edit renumbers most string IDs and two nearly identical bytecode files end up differing almost everywhere. `bundle` compiles against an earlier bytecode of the same app (`hermesc -base-bytecode=…`), pinning those IDs so that only real changes ever reach the diff.
|
|
36
|
+
- **An HBC-aware transform.** Hermes bytecode is also full of offset tables, where inserting a few bytes shifts every subsequent offset. Before running hdiff we apply a **delta-friendly reversible transform** that delta-encodes those offset bitfields, so a global shift collapses into a single-point change. The layout description ships with each patch, so **clients need zero upgrades** as Hermes evolves.
|
|
45
37
|
|
|
46
|
-
|
|
38
|
+
The bytecode is also emitted without its debug-info section — a flat **21%** smaller, the same thing React Native's own release builds do — which shrinks the full package and every patch derived from it.
|
|
47
39
|
|
|
48
|
-
The numbers below are measured on real release bundles of a React Native 0.86 app (Hermes HBC v98, ~4.4 MB bytecode)
|
|
40
|
+
The numbers below are measured on real release bundles of a React Native 0.86 app (Hermes HBC v98, ~4.4 MB bytecode). Every patch is verified by an actual round-trip before its size is recorded, and every delta-mode build is verified equivalent to a plain compile. Full methodology, fixtures, and runnable code: **[hbc-diff-benchmark](https://github.com/sunnylqm/hbc-diff-benchmark)**.
|
|
49
41
|
|
|
50
42
|
**Hermes bytecode (.hbc) — what ships in production Hermes apps:**
|
|
51
43
|
|
|
52
|
-
| Scenario | Full OTA (gzip) | bsdiff |
|
|
53
|
-
|
|
54
|
-
| One-line text change | 1901.5 KB | 93.7 KB |
|
|
55
|
-
| Small feature (~60 LOC) | 1913.9 KB | 411.6 KB |
|
|
56
|
-
| Medium feature (~300 LOC) | 1973.7 KB | 551.6 KB |
|
|
44
|
+
| Scenario | Full OTA (gzip) | bsdiff | **react-native-update** | vs bsdiff |
|
|
45
|
+
|---|---|---|---|---|
|
|
46
|
+
| One-line text change | 1901.5 KB | 93.7 KB | **3.4 KB** | **28× smaller** |
|
|
47
|
+
| Small feature (~60 LOC) | 1913.9 KB | 411.6 KB | **50.2 KB** | **8.2× smaller** |
|
|
48
|
+
| Medium feature (~300 LOC) | 1973.7 KB | 551.6 KB | **97.8 KB** | **5.6× smaller** |
|
|
57
49
|
|
|
58
50
|
**Plain-text JS bundle — non-Hermes apps (same scenarios, same app):**
|
|
59
51
|
|
|
60
|
-
| Scenario | Full OTA (gzip) | bsdiff |
|
|
61
|
-
|
|
62
|
-
| One-line text change | 807.2 KB | 0.3 KB |
|
|
63
|
-
| Small feature (~60 LOC) | 813.1 KB | 7.4 KB |
|
|
64
|
-
| Medium feature (~300 LOC) | 837.7 KB | 38.4 KB |
|
|
52
|
+
| Scenario | Full OTA (gzip) | bsdiff | **react-native-update** |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| One-line text change | 807.2 KB | 0.3 KB | **0.1 KB** |
|
|
55
|
+
| Small feature (~60 LOC) | 813.1 KB | 7.4 KB | **5.8 KB** |
|
|
56
|
+
| Medium feature (~300 LOC) | 837.7 KB | 38.4 KB | **28.7 KB** |
|
|
65
57
|
|
|
66
|
-
Text bundles have no offset tables, so they diff cleanly
|
|
58
|
+
Text bundles have no offset tables and no string-table churn, so they diff cleanly on their own — patches are hundreds of bytes to tens of KB. The amplification the two optimizations above remove is a Hermes-bytecode-specific problem, which is exactly why they exist.
|
|
67
59
|
|
|
68
60
|
Highlights:
|
|
69
61
|
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
73
|
-
|
|
62
|
+
- A one-line fix — by far the most common hot update — ships in **3.4 KB**, 559× less than a full-bundle OTA.
|
|
63
|
+
- Patch generation is **2–4× faster** than bsdiff; the transform itself costs single-digit milliseconds.
|
|
64
|
+
- Every stage fails safe: bounds are validated before any byte is touched, delta-mode output is checked against a plain compile, and any mismatch falls back to the previous behaviour.
|
|
65
|
+
|
|
66
|
+
## Native cold-start check
|
|
67
|
+
|
|
68
|
+
Since 10.52.1 every cold start runs one background update check that **does not depend on the app bundle** — the request, the download, the patch and the version switch all happen natively. It exists for exactly one reason: **when the running update is broken enough that JS never starts, something still has to be able to fetch the fix.** Normal updates remain the JS flow's job, and the JS check reuses this result instead of issuing its own request.
|
|
69
|
+
|
|
70
|
+
- **It never blocks startup**: delayed by a few seconds, off the main thread, effective on the *next* launch. Whether the downloaded version is activated automatically depends on your `updateStrategy` / `checkStrategy`; otherwise it is downloaded and JS decides.
|
|
71
|
+
- **Crash-moment rescue** (Android & iOS): if the app dies of an uncaught JS error during startup, the SDK briefly holds the dying process to finish the check and download — so even a version that crashes a fraction of a second into every launch gets replaced. Crash reporters keep working: the previous handler is chained and always called afterwards. Not covered: native crashes, ANRs, OOM kills, and iOS apps that install a custom `RCTSetFatalHandler`.
|
|
72
|
+
- **Rescue directive**: marking a version "force boot" in the dashboard activates it on the next launch regardless of the strategies above — this is how a fleet stuck on a broken version is recovered. The device-local crash-rollback guard still wins: a version this device already rolled back from is never reinstalled.
|
|
73
|
+
- **It can be turned off**: `disableNativeCheck: true` removes one background request per cold start, at the cost of **giving up the recovery above** — a device bricked by a bad update can no longer heal itself.
|
|
74
74
|
|
|
75
75
|
## Comparison With Other OTA Libraries
|
|
76
76
|
|
|
@@ -78,7 +78,7 @@ Highlights:
|
|
|
78
78
|
|---------|---------------------|-------------|------------------------|
|
|
79
79
|
| **Price / Cost** | Free tier with multiple paid plans, bandwidth included | Free tier with multiple paid plans, extra bandwidth charges apply | ❌ **Discontinued** (Microsoft App Center shut down on March 31, 2025) |
|
|
80
80
|
| **Package Size** | ⭐⭐⭐⭐⭐ Tens to hundreds of KB (incremental) | ⭐⭐⭐ Full bundle updates (usually tens of MB) | ❌ **Discontinued** |
|
|
81
|
-
| **Hermes-specific diff** | ✅ HBC-aware transform, smallest patches | ❌ Full bundle | ❌ **Discontinued** |
|
|
81
|
+
| **Hermes-specific diff** | ✅ Delta-mode compile + HBC-aware transform, smallest patches | ❌ Full bundle | ❌ **Discontinued** |
|
|
82
82
|
| **Staged (gray) rollout** | ✅ Built-in, percentage-based | ✅ Supported | ❌ **Discontinued** |
|
|
83
83
|
| **Analytics** | ✅ Built-in (version distribution, success rate) | ⚠️ Limited | ❌ **Discontinued** |
|
|
84
84
|
| **Release health monitoring** | ✅ Built-in | ❌ Not available | ❌ **Discontinued** |
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
language: cpp
|
|
2
|
+
matrix:
|
|
3
|
+
include:
|
|
4
|
+
- os: linux
|
|
5
|
+
compiler: clang
|
|
6
|
+
- os: linux
|
|
7
|
+
compiler: gcc
|
|
8
|
+
- os: linux
|
|
9
|
+
compiler: arm-linux-gnueabi-gcc
|
|
10
|
+
addons:
|
|
11
|
+
apt:
|
|
12
|
+
packages:
|
|
13
|
+
- qemu
|
|
14
|
+
- gcc-arm-linux-gnueabi
|
|
15
|
+
- libc-dev-armel-cross
|
|
16
|
+
env: CHOST=arm-linux-gnueabi
|
|
17
|
+
- os: osx
|
|
18
|
+
osx_image: xcode9.4
|
|
19
|
+
script:
|
|
20
|
+
- make LZMA=0
|
|
21
|
+
- make clean
|
|
22
|
+
- git clone https://github.com/sisong/lzma.git ../lzma
|
|
23
|
+
- make DIR_DIFF=0
|
|
24
|
+
- make clean
|
|
25
|
+
- make
|
|
26
|
+
- make clean
|
|
27
|
+
- cd ../HDiffPatch
|
|
28
|
+
- git clone https://github.com/sisong/libmd5.git ../libmd5
|
|
29
|
+
- make MT=1 MD5=1
|
|
30
|
+
- if [[ $TRAVIS_OS_NAME == osx ]]; then xcodebuild -workspace builds/xcode/HDiffPatch.xcworkspace -scheme hdiffz -configuration Release OBJROOT=$PWD/bin SYMROOT=$PWD/bin; fi
|
|
31
|
+
- if [[ $TRAVIS_OS_NAME == osx ]]; then xcodebuild -workspace builds/xcode/HDiffPatch.xcworkspace -scheme hpatchz -configuration Release OBJROOT=$PWD/bin SYMROOT=$PWD/bin; fi
|
|
32
|
+
- if [[ $TRAVIS_OS_NAME == osx ]]; then xcodebuild -workspace builds/xcode/HDiffPatch.xcworkspace -scheme unitTest -configuration Release OBJROOT=$PWD/bin SYMROOT=$PWD/bin; fi
|
|
33
|
+
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
7z ANSI-C Decoder 9.35
|
|
2
|
+
----------------------
|
|
3
|
+
|
|
4
|
+
7z ANSI-C provides 7z/LZMA decoding.
|
|
5
|
+
7z ANSI-C version is simplified version ported from C++ code.
|
|
6
|
+
|
|
7
|
+
LZMA is default and general compression method of 7z format
|
|
8
|
+
in 7-Zip compression program (www.7-zip.org). LZMA provides high
|
|
9
|
+
compression ratio and very fast decompression.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
LICENSE
|
|
13
|
+
-------
|
|
14
|
+
|
|
15
|
+
7z ANSI-C Decoder is part of the LZMA SDK.
|
|
16
|
+
LZMA SDK is written and placed in the public domain by Igor Pavlov.
|
|
17
|
+
|
|
18
|
+
Files
|
|
19
|
+
---------------------
|
|
20
|
+
|
|
21
|
+
7zDecode.* - Low level 7z decoding
|
|
22
|
+
7zExtract.* - High level 7z decoding
|
|
23
|
+
7zHeader.* - .7z format constants
|
|
24
|
+
7zIn.* - .7z archive opening
|
|
25
|
+
7zItem.* - .7z structures
|
|
26
|
+
7zMain.c - Test application
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
How To Use
|
|
30
|
+
----------
|
|
31
|
+
|
|
32
|
+
You can create .7z archive with 7z.exe, 7za.exe or 7zr.exe:
|
|
33
|
+
|
|
34
|
+
7z.exe a archive.7z *.htm -r -mx -m0fb=255
|
|
35
|
+
|
|
36
|
+
If you have big number of files in archive, and you need fast extracting,
|
|
37
|
+
you can use partly-solid archives:
|
|
38
|
+
|
|
39
|
+
7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K
|
|
40
|
+
|
|
41
|
+
In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only
|
|
42
|
+
512KB for extracting one file from such archive.
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
Limitations of current version of 7z ANSI-C Decoder
|
|
46
|
+
---------------------------------------------------
|
|
47
|
+
|
|
48
|
+
- It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive.
|
|
49
|
+
- It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters.
|
|
50
|
+
- It converts original UTF-16 Unicode file names to UTF-8 Unicode file names.
|
|
51
|
+
|
|
52
|
+
These limitations will be fixed in future versions.
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
Using 7z ANSI-C Decoder Test application:
|
|
56
|
+
-----------------------------------------
|
|
57
|
+
|
|
58
|
+
Usage: 7zDec <command> <archive_name>
|
|
59
|
+
|
|
60
|
+
<Command>:
|
|
61
|
+
e: Extract files from archive
|
|
62
|
+
l: List contents of archive
|
|
63
|
+
t: Test integrity of archive
|
|
64
|
+
|
|
65
|
+
Example:
|
|
66
|
+
|
|
67
|
+
7zDec l archive.7z
|
|
68
|
+
|
|
69
|
+
lists contents of archive.7z
|
|
70
|
+
|
|
71
|
+
7zDec e archive.7z
|
|
72
|
+
|
|
73
|
+
extracts files from archive.7z to current folder.
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
How to use .7z Decoder
|
|
77
|
+
----------------------
|
|
78
|
+
|
|
79
|
+
Memory allocation
|
|
80
|
+
~~~~~~~~~~~~~~~~~
|
|
81
|
+
|
|
82
|
+
7z Decoder uses two memory pools:
|
|
83
|
+
1) Temporary pool
|
|
84
|
+
2) Main pool
|
|
85
|
+
Such scheme can allow you to avoid fragmentation of allocated blocks.
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
Steps for using 7z decoder
|
|
89
|
+
--------------------------
|
|
90
|
+
|
|
91
|
+
Use code at 7zMain.c as example.
|
|
92
|
+
|
|
93
|
+
1) Declare variables:
|
|
94
|
+
inStream /* implements ILookInStream interface */
|
|
95
|
+
CSzArEx db; /* 7z archive database structure */
|
|
96
|
+
ISzAlloc allocImp; /* memory functions for main pool */
|
|
97
|
+
ISzAlloc allocTempImp; /* memory functions for temporary pool */
|
|
98
|
+
|
|
99
|
+
2) call CrcGenerateTable(); function to initialize CRC structures.
|
|
100
|
+
|
|
101
|
+
3) call SzArEx_Init(&db); function to initialize db structures.
|
|
102
|
+
|
|
103
|
+
4) call SzArEx_Open(&db, inStream, &allocMain, &allocTemp) to open archive
|
|
104
|
+
|
|
105
|
+
This function opens archive "inStream" and reads headers to "db".
|
|
106
|
+
All items in "db" will be allocated with "allocMain" functions.
|
|
107
|
+
SzArEx_Open function allocates and frees temporary structures by "allocTemp" functions.
|
|
108
|
+
|
|
109
|
+
5) List items or Extract items
|
|
110
|
+
|
|
111
|
+
Listing code:
|
|
112
|
+
~~~~~~~~~~~~~
|
|
113
|
+
|
|
114
|
+
Use SzArEx_GetFileNameUtf16 function. Look example code in C\Util\7z\7zMain.c file.
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
Extracting code:
|
|
118
|
+
~~~~~~~~~~~~~~~~
|
|
119
|
+
|
|
120
|
+
SZ_RESULT SzAr_Extract(
|
|
121
|
+
CArchiveDatabaseEx *db,
|
|
122
|
+
ILookInStream *inStream,
|
|
123
|
+
UInt32 fileIndex, /* index of file */
|
|
124
|
+
UInt32 *blockIndex, /* index of solid block */
|
|
125
|
+
Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
|
|
126
|
+
size_t *outBufferSize, /* buffer size for output buffer */
|
|
127
|
+
size_t *offset, /* offset of stream for required file in *outBuffer */
|
|
128
|
+
size_t *outSizeProcessed, /* size of file in *outBuffer */
|
|
129
|
+
ISzAlloc *allocMain,
|
|
130
|
+
ISzAlloc *allocTemp);
|
|
131
|
+
|
|
132
|
+
If you need to decompress more than one file, you can send these values from previous call:
|
|
133
|
+
blockIndex,
|
|
134
|
+
outBuffer,
|
|
135
|
+
outBufferSize,
|
|
136
|
+
You can consider "outBuffer" as cache of solid block. If your archive is solid,
|
|
137
|
+
it will increase decompression speed.
|
|
138
|
+
|
|
139
|
+
After decompressing you must free "outBuffer":
|
|
140
|
+
allocImp.Free(outBuffer);
|
|
141
|
+
|
|
142
|
+
6) call SzArEx_Free(&db, allocImp.Free) to free allocated items in "db".
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
Memory requirements for .7z decoding
|
|
148
|
+
------------------------------------
|
|
149
|
+
|
|
150
|
+
Memory usage for Archive opening:
|
|
151
|
+
- Temporary pool:
|
|
152
|
+
- Memory for uncompressed .7z headers
|
|
153
|
+
- some other temporary blocks
|
|
154
|
+
- Main pool:
|
|
155
|
+
- Memory for database:
|
|
156
|
+
Estimated size of one file structures in solid archive:
|
|
157
|
+
- Size (4 or 8 Bytes)
|
|
158
|
+
- CRC32 (4 bytes)
|
|
159
|
+
- LastWriteTime (8 bytes)
|
|
160
|
+
- Some file information (4 bytes)
|
|
161
|
+
- File Name (variable length) + pointer + allocation structures
|
|
162
|
+
|
|
163
|
+
Memory usage for archive Decompressing:
|
|
164
|
+
- Temporary pool:
|
|
165
|
+
- Memory for LZMA decompressing structures
|
|
166
|
+
- Main pool:
|
|
167
|
+
- Memory for decompressed solid block
|
|
168
|
+
- Memory for temprorary buffers, if BCJ2 fileter is used. Usually these
|
|
169
|
+
temprorary buffers can be about 15% of solid block size.
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
7z Decoder doesn't allocate memory for compressed blocks.
|
|
173
|
+
Instead of this, you must allocate buffer with desired
|
|
174
|
+
size before calling 7z Decoder. Use 7zMain.c as example.
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
Defines
|
|
178
|
+
-------
|
|
179
|
+
|
|
180
|
+
_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr.
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
http://www.7-zip.org
|
|
186
|
+
http://www.7-zip.org/sdk.html
|
|
187
|
+
http://www.7-zip.org/support.html
|