react-native-update 10.37.20 → 10.38.0-beta.1
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 +4 -4
- package/README.md +2 -12
- package/android/bin/.settings/org.eclipse.buildship.core.prefs +13 -0
- package/android/build.gradle +4 -0
- package/android/jni/Android.mk +14 -1
- package/android/jni/Application.mk +5 -2
- 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/ArchivePatchPlanResult.java +6 -0
- package/android/src/main/java/cn/reactnative/modules/update/CopyGroupResult.java +6 -0
- package/android/src/main/java/cn/reactnative/modules/update/DownloadTask.java +155 -156
- package/android/src/main/java/cn/reactnative/modules/update/NativeUpdateCore.java +34 -0
- package/android/src/main/java/cn/reactnative/modules/update/StateCoreResult.java +16 -0
- package/android/src/main/java/cn/reactnative/modules/update/UpdateContext.java +131 -48
- package/cpp/patch_core/archive_patch_core.cpp +125 -0
- package/cpp/patch_core/archive_patch_core.h +59 -0
- package/cpp/patch_core/patch_core.cpp +533 -0
- package/cpp/patch_core/patch_core.h +68 -0
- package/cpp/patch_core/patch_core_android.cpp +112 -0
- package/cpp/patch_core/state_core.cpp +110 -0
- package/cpp/patch_core/state_core.h +58 -0
- package/cpp/patch_core/tests/patch_core_test.cpp +473 -0
- package/cpp/patch_core/update_core_android.cpp +469 -0
- package/harmony/pushy.har +0 -0
- package/ios/RCTPushy/RCTPushy.mm +233 -143
- package/package.json +17 -15
- package/react-native-update.podspec +3 -0
- package/scripts/build-harmony-har.js +12 -0
- package/scripts/prepublish.ts +49 -3
- package/scripts/prune-host-stl.sh +6 -0
- package/scripts/test-patch-core.sh +39 -0
- package/src/client.ts +129 -76
- package/src/core.ts +2 -1
- package/src/endpoint.ts +171 -0
- package/src/utils.ts +40 -27
- package/android/jni/lzma/DOC/7zC.txt +0 -187
- package/android/jni/lzma/DOC/7zFormat.txt +0 -469
- package/android/jni/lzma/DOC/Methods.txt +0 -173
- package/android/jni/lzma/DOC/installer.txt +0 -166
- package/android/jni/lzma/DOC/lzma-history.txt +0 -446
- package/android/jni/lzma/DOC/lzma-sdk.txt +0 -357
- package/android/jni/lzma/DOC/lzma-specification.txt +0 -1176
- package/android/jni/lzma/DOC/lzma.txt +0 -328
- 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 +0 -5
- package/android/jni/lzma/bin/installer/cr.bat +0 -5
- package/android/jni/lzma/bin/lzma.exe +0 -0
- package/android/jni/lzma/bin/x64/7zr.exe +0 -0
- package/error.js +0 -1609
- package/harmony/har-wrapper/AppScope/app.json5 +0 -8
- package/harmony/har-wrapper/build-profile.json5 +0 -35
- package/harmony/har-wrapper/hvigor/hvigor-config.json5 +0 -5
- package/harmony/har-wrapper/hvigorfile.ts +0 -6
- package/harmony/har-wrapper/oh-package.json5 +0 -4
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/.cmake/api/v1/reply/cache-v2-77b153ce45aba0ed28ef.json +0 -1415
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/.cmake/api/v1/reply/cmakeFiles-v1-b65a07793384e0ce3e08.json +0 -809
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/.cmake/api/v1/reply/codemodel-v2-ce0e89410afd8bf3a057.json +0 -60
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/.cmake/api/v1/reply/directory-.-Release-f5ebdc15457944623624.json +0 -14
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/.cmake/api/v1/reply/index-2026-03-18T12-50-36-0050.json +0 -89
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/.cmake/api/v1/reply/target-rnupdate-Release-267153624504c9c3ffdd.json +0 -222
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/.ninja_deps +0 -0
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/.ninja_log +0 -8
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeCache.txt +0 -415
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/3.28.2/CMakeCCompiler.cmake +0 -74
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/3.28.2/CMakeCXXCompiler.cmake +0 -85
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/3.28.2/CMakeDetermineCompilerABI_C.bin +0 -0
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/3.28.2/CMakeDetermineCompilerABI_CXX.bin +0 -0
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/3.28.2/CMakeSystem.cmake +0 -15
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/3.28.2/CompilerIdC/CMakeCCompilerId.c +0 -880
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/3.28.2/CompilerIdC/CMakeCCompilerId.o +0 -0
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/3.28.2/CompilerIdCXX/CMakeCXXCompilerId.cpp +0 -869
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/3.28.2/CompilerIdCXX/CMakeCXXCompilerId.o +0 -0
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/CMakeConfigureLog.yaml +0 -388
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/TargetDirectories.txt +0 -3
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/cmake.check_cache +0 -1
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/rnupdate.dir/__w/react-native-update/react-native-update/android/jni/HDiffPatch/file_for_patch.c.o +0 -0
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/rnupdate.dir/__w/react-native-update/react-native-update/android/jni/HDiffPatch/libHDiffPatch/HPatch/patch.c.o +0 -0
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/rnupdate.dir/__w/react-native-update/react-native-update/android/jni/hpatch.c.o +0 -0
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/rnupdate.dir/__w/react-native-update/react-native-update/android/jni/lzma/C/Lzma2Dec.c.o +0 -0
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/rnupdate.dir/__w/react-native-update/react-native-update/android/jni/lzma/C/LzmaDec.c.o +0 -0
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/rnupdate.dir/pushy.c.o +0 -0
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/CMakeFiles/rules.ninja +0 -64
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/additional_project_files.txt +0 -0
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/build.ninja +0 -206
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/build_file_index.txt +0 -1
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/cmake_install.cmake +0 -54
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/compile_commands.json +0 -38
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/configure_fingerprint.json +0 -1
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/hvigor_native_config.json +0 -1
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/metadata_generation_command.txt +0 -17
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/native_work_dir.txt +0 -1
- package/harmony/pushy/.cxx/default/default/release/arm64-v8a/output.log +0 -14
- package/harmony/pushy/.cxx/default/default/release/hvigor/arm64-v8a/summary.cmake +0 -0
- package/harmony/pushy/BuildProfile.ets +0 -17
- package/harmony/pushy/OAT.xml +0 -38
- package/harmony/pushy/README.md +0 -0
- package/harmony/pushy/build-profile.json5 +0 -15
- package/harmony/pushy/hvigor-plugin.ts +0 -34
- package/harmony/pushy/hvigorfile.ts +0 -1
- package/harmony/pushy/index.ets +0 -2
- package/harmony/pushy/oh-package-lock.json5 +0 -20
- package/harmony/pushy/oh-package.json5 +0 -13
- package/harmony/pushy/src/main/cpp/CMakeLists.txt +0 -51
- package/harmony/pushy/src/main/cpp/PushyPackage.h +0 -55
- package/harmony/pushy/src/main/cpp/PushyTurboModule.cpp +0 -142
- package/harmony/pushy/src/main/cpp/PushyTurboModule.h +0 -38
- package/harmony/pushy/src/main/cpp/pushy.c +0 -117
- package/harmony/pushy/src/main/cpp/pushy.h +0 -8
- package/harmony/pushy/src/main/ets/DownloadTask.ts +0 -570
- package/harmony/pushy/src/main/ets/DownloadTaskParams.ts +0 -19
- package/harmony/pushy/src/main/ets/EventHub.ts +0 -39
- package/harmony/pushy/src/main/ets/Logger.ts +0 -52
- package/harmony/pushy/src/main/ets/PushyFileJSBundleProvider.ets +0 -50
- package/harmony/pushy/src/main/ets/PushyPackage.ts +0 -22
- package/harmony/pushy/src/main/ets/PushyTurboModule.ts +0 -171
- package/harmony/pushy/src/main/ets/SaveFile.ts +0 -34
- package/harmony/pushy/src/main/ets/UpdateContext.ts +0 -262
- package/harmony/pushy/src/main/ets/UpdateModuleImpl.ts +0 -123
- package/harmony/pushy/src/main/module.json5 +0 -7
- package/harmony/pushy/src/main/resources/base/element/string.json +0 -8
- package/harmony/pushy/src/main/resources/en_US/element/string.json +0 -8
- package/harmony/pushy/src/main/resources/zh_CN/element/string.json +0 -8
- package/harmony/pushy/ts.ts +0 -3
- package/src/__tests__/core.test.ts +0 -103
- package/src/__tests__/utils.test.ts +0 -36
package/README-CN.md
CHANGED
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
### 区域服务说明
|
|
8
8
|
|
|
9
|
-
- 中国区服务使用 **Pushy**(<https://pushy.reactnative.cn
|
|
10
|
-
- 全球区服务使用 **Cresc**(<https://cresc.dev>),由 **CHARMLOT PTE. LTD.**
|
|
11
|
-
-
|
|
9
|
+
- 中国区服务使用 **Pushy**(<https://pushy.reactnative.cn>),由**武汉青罗网络科技有限公司**运营,服务器与用户数据存放于中国境内,也通过 cloudflare 智能分流,完全支持海外用户高速访问。**使用人民币支付订阅**。
|
|
10
|
+
- 全球区服务使用 **Cresc**(<https://cresc.dev>),由 **CHARMLOT PTE. LTD.** 运营,服务器与用户数据存放于新加坡。**使用美元支付订阅**。
|
|
11
|
+
- 中国区与全球区服务由不同公司实体独立运营,服务器、数据存放位置及控制台系统彼此隔离。如果可以使用网银和支付宝结算,建议使用 Pushy,否则建议使用 Cresc。
|
|
12
12
|
|
|
13
13
|
**现已支持鸿蒙以及新架构**
|
|
14
14
|
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
### 优势
|
|
20
20
|
|
|
21
|
-
1. 对中国用户使用阿里云高速 CDN
|
|
21
|
+
1. 对中国用户使用阿里云高速 CDN 分发,对比其他服务器在国外的热更新服务,分发更稳定,更新成功率极高。海外用户智能分流至 cloudflare,同样提供稳定高速的分发体验。
|
|
22
22
|
2. 基于 bsdiff/hdiff 算法创建的**超小更新包**,通常版本迭代后在几十至几百 KB 级别(其他全量热更新服务所需流量通常在几十 MB 级别)。
|
|
23
23
|
3. 始终跟进 RN 最新正式版本,第一时间提供支持。支持 hermes 字节码格式。支持新架构(注:安卓 0.73.0 ~ 0.76.0 的新架构因官方 bug 不支持,0.73 以下或 0.76.1 以上的新架构可用)。
|
|
24
24
|
4. 跨越多个版本进行更新时,只需要下载**一个更新包**,不需要逐版本依次更新。
|
package/README.md
CHANGED
|
@@ -4,27 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
`react-native-update` provides over-the-air update capabilities for React Native apps. For full documentation, visit:
|
|
6
6
|
|
|
7
|
-
- China service: <https://pushy.reactnative.cn>
|
|
8
7
|
- Global service: <https://cresc.dev>
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
- **Pushy** (<https://pushy.reactnative.cn>) is the China service, operated by **Wuhan Qingluo Network Technology Co., Ltd.**, with servers and user data hosted in mainland China.
|
|
13
|
-
- **Cresc** (<https://cresc.dev>) is the global service, operated by **CHARMLOT PTE. LTD.**, with servers and user data hosted in Singapore.
|
|
14
|
-
- Pushy and Cresc are operated by different legal entities with separate infrastructure, data storage, and admin systems. Developers outside mainland China should use Cresc directly.
|
|
15
|
-
|
|
16
|
-
**HarmonyOS and React Native New Architecture are supported.**
|
|
9
|
+
**React Native New Architecture is supported.**
|
|
17
10
|
|
|
18
11
|
## Quick Start
|
|
19
12
|
|
|
20
13
|
See the docs:
|
|
21
14
|
|
|
22
|
-
- Chinese docs: <https://pushy.reactnative.cn/docs/getting-started.html>
|
|
23
15
|
- English docs: <https://cresc.dev/docs/getting-started>
|
|
24
16
|
|
|
25
17
|
## Advantages
|
|
26
18
|
|
|
27
|
-
1.
|
|
19
|
+
1. react-native-update provides a dedicated global service with fast and reliable worldwide delivery.
|
|
28
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.
|
|
29
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.
|
|
30
22
|
4. When updating across multiple versions, clients only need to download **one update package** instead of applying every intermediate version in sequence.
|
|
@@ -39,7 +31,6 @@ See the docs:
|
|
|
39
31
|
|---------|---------------------|-------------|------------------------|
|
|
40
32
|
| **Price / Cost** | Free tier with multiple paid plans (starting at about CNY 66/month), bandwidth included | Free tier with multiple paid plans (starting at about CNY 136/month), extra bandwidth charges apply | ❌ **Discontinued** (Microsoft App Center shut down on March 31, 2025) |
|
|
41
33
|
| **Package Size** | ⭐⭐⭐⭐⭐ Tens to hundreds of KB (incremental) | ⭐⭐⭐ Full bundle updates (usually tens of MB) | ❌ **Discontinued** |
|
|
42
|
-
| **China Access Speed** | ⭐⭐⭐⭐⭐ Alibaba Cloud CDN, very fast | ⭐⭐ Overseas servers, may be slower | ❌ **Discontinued** |
|
|
43
34
|
| **iOS Support** | ✅ Supported | ✅ Supported | ❌ **Discontinued** |
|
|
44
35
|
| **Android Support** | ✅ Supported | ✅ Supported | ❌ **Discontinued** |
|
|
45
36
|
| **HarmonyOS Support** | ✅ Supported | ❌ Not supported | ❌ **Discontinued** |
|
|
@@ -56,7 +47,6 @@ See the docs:
|
|
|
56
47
|
| **Server Deployment** | ✅ Hosted service or paid private deployment | ✅ Hosted by Expo (EAS Update) | ❌ **Discontinued** |
|
|
57
48
|
| **Update Strategy** | Flexible configuration (silent / prompted / immediate / delayed) | More fixed workflow | ❌ **Discontinued** |
|
|
58
49
|
| **Bandwidth Usage** | ⭐⭐⭐⭐⭐ Very low (incremental) | ⭐⭐⭐ Higher (full bundle) | ❌ **Discontinued** |
|
|
59
|
-
| **Update Success Rate** | ⭐⭐⭐⭐⭐ Excellent, especially in China | ⭐⭐⭐ Moderate | ❌ **Discontinued** |
|
|
60
50
|
|
|
61
51
|
## Local Development
|
|
62
52
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
arguments=--init-script /var/folders/l6/0fn3x28s5s585ld3p04gsy1h0000gn/T/db3b08fc4a9ef609cb16b96b200fa13e563f396e9bb1ed0905fdab7bc3bc513b.gradle --init-script /var/folders/l6/0fn3x28s5s585ld3p04gsy1h0000gn/T/52cde0cfcf3e28b8b7510e992210d9614505e0911af0c190bd590d7158574963.gradle
|
|
2
|
+
auto.sync=false
|
|
3
|
+
build.scans.enabled=false
|
|
4
|
+
connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(8.9))
|
|
5
|
+
connection.project.dir=
|
|
6
|
+
eclipse.preferences.version=1
|
|
7
|
+
gradle.user.home=
|
|
8
|
+
java.home=/Users/sunny/.sdkman/candidates/java/17.0.9-zulu/zulu-17.jdk/Contents/Home
|
|
9
|
+
jvm.arguments=
|
|
10
|
+
offline.mode=false
|
|
11
|
+
override.workspace.settings=true
|
|
12
|
+
show.console.view=true
|
|
13
|
+
show.executions.view=true
|
package/android/build.gradle
CHANGED
package/android/jni/Android.mk
CHANGED
|
@@ -3,6 +3,14 @@ LOCAL_PATH := $(call my-dir)
|
|
|
3
3
|
include $(CLEAR_VARS)
|
|
4
4
|
|
|
5
5
|
LOCAL_MODULE := rnupdate
|
|
6
|
+
LOCAL_CPPFLAGS += -std=c++17
|
|
7
|
+
LOCAL_LDFLAGS += -Wl,--exclude-libs,ALL
|
|
8
|
+
LOCAL_C_INCLUDES := \
|
|
9
|
+
$(LOCAL_PATH) \
|
|
10
|
+
$(LOCAL_PATH)/HDiffPatch \
|
|
11
|
+
$(LOCAL_PATH)/HDiffPatch/libHDiffPatch/HPatch \
|
|
12
|
+
$(LOCAL_PATH)/lzma/C \
|
|
13
|
+
$(LOCAL_PATH)/../../cpp/patch_core
|
|
6
14
|
|
|
7
15
|
Hdp_Files := \
|
|
8
16
|
hpatch.c \
|
|
@@ -13,6 +21,11 @@ Hdp_Files := \
|
|
|
13
21
|
|
|
14
22
|
LOCAL_SRC_FILES := \
|
|
15
23
|
DownloadTask.c \
|
|
24
|
+
../../cpp/patch_core/archive_patch_core.cpp \
|
|
25
|
+
../../cpp/patch_core/patch_core.cpp \
|
|
26
|
+
../../cpp/patch_core/patch_core_android.cpp \
|
|
27
|
+
../../cpp/patch_core/state_core.cpp \
|
|
28
|
+
../../cpp/patch_core/update_core_android.cpp \
|
|
16
29
|
$(Hdp_Files)
|
|
17
30
|
|
|
18
|
-
include $(BUILD_SHARED_LIBRARY)
|
|
31
|
+
include $(BUILD_SHARED_LIBRARY)
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
APP_PLATFORM := android-
|
|
1
|
+
APP_PLATFORM := android-21
|
|
2
2
|
APP_CFLAGS += -Wno-error=format-security
|
|
3
3
|
APP_CFLAGS += -fvisibility=hidden -fvisibility-inlines-hidden
|
|
4
4
|
APP_CFLAGS += -ffunction-sections -fdata-sections
|
|
5
|
-
|
|
5
|
+
APP_CFLAGS += -Oz -fno-unwind-tables -fno-asynchronous-unwind-tables
|
|
6
|
+
APP_CPPFLAGS += -std=c++17 -Oz -fno-exceptions -fno-rtti -fno-unwind-tables -fno-asynchronous-unwind-tables
|
|
7
|
+
APP_LDFLAGS += -Wl,--gc-sections -Wl,--exclude-libs,ALL
|
|
6
8
|
APP_BUILD_SCRIPT := Android.mk
|
|
7
9
|
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
|
|
10
|
+
APP_STL := c++_shared
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -47,7 +47,7 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
static {
|
|
50
|
-
|
|
50
|
+
NativeUpdateCore.ensureLoaded();
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
private void removeDirectory(File file) throws IOException {
|
|
@@ -131,7 +131,35 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
131
131
|
|
|
132
132
|
byte[] buffer = new byte[1024*4];
|
|
133
133
|
|
|
134
|
-
private static native
|
|
134
|
+
private static native void applyPatchFromFileSource(
|
|
135
|
+
String sourceRoot,
|
|
136
|
+
String targetRoot,
|
|
137
|
+
String originBundlePath,
|
|
138
|
+
String bundlePatchPath,
|
|
139
|
+
String bundleOutputPath,
|
|
140
|
+
String mergeSourceSubdir,
|
|
141
|
+
boolean enableMerge,
|
|
142
|
+
String[] copyFroms,
|
|
143
|
+
String[] copyTos,
|
|
144
|
+
String[] deletes
|
|
145
|
+
);
|
|
146
|
+
private static native void cleanupOldEntries(
|
|
147
|
+
String rootDir,
|
|
148
|
+
String keepCurrent,
|
|
149
|
+
String keepPrevious,
|
|
150
|
+
int maxAgeDays
|
|
151
|
+
);
|
|
152
|
+
private static native ArchivePatchPlanResult buildArchivePatchPlan(
|
|
153
|
+
int patchType,
|
|
154
|
+
String[] entryNames,
|
|
155
|
+
String[] copyFroms,
|
|
156
|
+
String[] copyTos,
|
|
157
|
+
String[] deletes
|
|
158
|
+
);
|
|
159
|
+
private static native CopyGroupResult[] buildCopyGroups(
|
|
160
|
+
String[] copyFroms,
|
|
161
|
+
String[] copyTos
|
|
162
|
+
);
|
|
135
163
|
|
|
136
164
|
|
|
137
165
|
private void copyFile(File from, File fmd) throws IOException {
|
|
@@ -163,66 +191,76 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
163
191
|
return fout.toByteArray();
|
|
164
192
|
}
|
|
165
193
|
|
|
166
|
-
private
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
194
|
+
private void appendManifestEntries(
|
|
195
|
+
JSONObject manifest,
|
|
196
|
+
ArrayList<String> copyFroms,
|
|
197
|
+
ArrayList<String> copyTos,
|
|
198
|
+
ArrayList<String> deletes,
|
|
199
|
+
HashMap<String, String> copiesMap
|
|
200
|
+
) throws JSONException {
|
|
201
|
+
JSONObject copies = manifest.optJSONObject("copies");
|
|
202
|
+
if (copies != null) {
|
|
203
|
+
Iterator<?> keys = copies.keys();
|
|
204
|
+
while (keys.hasNext()) {
|
|
205
|
+
String to = (String) keys.next();
|
|
206
|
+
String from = copies.getString(to);
|
|
207
|
+
if (from.isEmpty()) {
|
|
208
|
+
from = to;
|
|
209
|
+
}
|
|
210
|
+
copyFroms.add(from);
|
|
211
|
+
copyTos.add(to);
|
|
212
|
+
if (copiesMap != null) {
|
|
213
|
+
copiesMap.put(to, from);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
172
216
|
}
|
|
173
|
-
int count;
|
|
174
217
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
218
|
+
JSONObject deleteMap = manifest.optJSONObject("deletes");
|
|
219
|
+
if (deleteMap != null) {
|
|
220
|
+
Iterator<?> deleteKeys = deleteMap.keys();
|
|
221
|
+
while (deleteKeys.hasNext()) {
|
|
222
|
+
deletes.add((String) deleteKeys.next());
|
|
223
|
+
}
|
|
179
224
|
}
|
|
180
|
-
|
|
181
|
-
fout.close();
|
|
182
|
-
in.close();
|
|
183
|
-
return fout.toByteArray();
|
|
184
225
|
}
|
|
185
226
|
|
|
186
|
-
private
|
|
187
|
-
InputStream in =
|
|
227
|
+
private void copyBundledAssetToFile(String assetName, File destination) throws IOException {
|
|
228
|
+
InputStream in = context.getAssets().open(assetName);
|
|
229
|
+
FileOutputStream fout = new FileOutputStream(destination);
|
|
188
230
|
int count;
|
|
189
|
-
|
|
190
|
-
ByteArrayOutputStream fout = new ByteArrayOutputStream();
|
|
191
|
-
while ((count = in.read(buffer)) != -1)
|
|
192
|
-
{
|
|
231
|
+
while ((count = in.read(buffer)) != -1) {
|
|
193
232
|
fout.write(buffer, 0, count);
|
|
194
233
|
}
|
|
195
|
-
|
|
196
234
|
fout.close();
|
|
197
235
|
in.close();
|
|
198
|
-
return fout.toByteArray();
|
|
199
236
|
}
|
|
200
237
|
|
|
201
|
-
private
|
|
202
|
-
File
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
238
|
+
private HashMap<String, ArrayList<File>> buildCopyList(
|
|
239
|
+
File unzipDirectory,
|
|
240
|
+
CopyGroupResult[] groups
|
|
241
|
+
) throws IOException {
|
|
242
|
+
HashMap<String, ArrayList<File>> copyList = new HashMap<String, ArrayList<File>>();
|
|
243
|
+
if (groups == null) {
|
|
244
|
+
return copyList;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
String rootPath = unzipDirectory.getCanonicalPath() + File.separator;
|
|
248
|
+
for (CopyGroupResult group : groups) {
|
|
249
|
+
ArrayList<File> targets = new ArrayList<File>();
|
|
250
|
+
if (group.toPaths != null) {
|
|
251
|
+
for (String to : group.toPaths) {
|
|
252
|
+
File toFile = new File(unzipDirectory, to);
|
|
253
|
+
String canonicalPath = toFile.getCanonicalPath();
|
|
254
|
+
if (!canonicalPath.startsWith(rootPath)) {
|
|
255
|
+
throw new SecurityException("Illegal name: " + to);
|
|
256
|
+
}
|
|
257
|
+
targets.add(toFile);
|
|
219
258
|
}
|
|
220
259
|
}
|
|
260
|
+
copyList.put(group.from, targets);
|
|
221
261
|
}
|
|
222
|
-
}
|
|
223
262
|
|
|
224
|
-
|
|
225
|
-
copyFilesWithBlacklist("", from, to, blackList);
|
|
263
|
+
return copyList;
|
|
226
264
|
}
|
|
227
265
|
|
|
228
266
|
private void doFullPatch(DownloadTaskParams param) throws IOException {
|
|
@@ -457,78 +495,64 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
457
495
|
|
|
458
496
|
removeDirectory(param.unzipDirectory);
|
|
459
497
|
param.unzipDirectory.mkdirs();
|
|
460
|
-
HashMap<String, ArrayList<File>> copyList = new HashMap<String, ArrayList<File>>();
|
|
461
498
|
HashMap<String, String> copiesMap = new HashMap<String, String>(); // to -> from 映射
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
499
|
+
ArrayList<String> entryNames = new ArrayList<String>();
|
|
500
|
+
ArrayList<String> copyFroms = new ArrayList<String>();
|
|
501
|
+
ArrayList<String> copyTos = new ArrayList<String>();
|
|
502
|
+
ArrayList<String> deletes = new ArrayList<String>();
|
|
465
503
|
|
|
466
504
|
SafeZipFile zipFile = new SafeZipFile(param.targetFile);
|
|
467
505
|
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
|
468
506
|
while (entries.hasMoreElements()) {
|
|
469
507
|
ZipEntry ze = entries.nextElement();
|
|
470
508
|
String fn = ze.getName();
|
|
509
|
+
entryNames.add(fn);
|
|
471
510
|
|
|
472
511
|
if (fn.equals("__diff.json")) {
|
|
473
|
-
foundDiff = true;
|
|
474
512
|
// copy files from assets
|
|
475
513
|
byte[] bytes = readBytes(zipFile.getInputStream(ze));
|
|
476
514
|
String json = new String(bytes, "UTF-8");
|
|
477
515
|
JSONObject obj = (JSONObject)new JSONTokener(json).nextValue();
|
|
478
|
-
|
|
479
|
-
JSONObject copies = obj.getJSONObject("copies");
|
|
480
|
-
Iterator<?> keys = copies.keys();
|
|
481
|
-
while( keys.hasNext() ) {
|
|
482
|
-
String to = (String)keys.next();
|
|
483
|
-
String from = copies.getString(to);
|
|
484
|
-
if (from.isEmpty()) {
|
|
485
|
-
from = to;
|
|
486
|
-
}
|
|
487
|
-
// 保存 copies 映射关系(to -> from)
|
|
488
|
-
copiesMap.put(to, from);
|
|
489
|
-
|
|
490
|
-
ArrayList<File> target = null;
|
|
491
|
-
if (!copyList.containsKey(from)) {
|
|
492
|
-
target = new ArrayList<File>();
|
|
493
|
-
copyList.put(from, target);
|
|
494
|
-
} else {
|
|
495
|
-
target = copyList.get((from));
|
|
496
|
-
}
|
|
497
|
-
File toFile = new File(param.unzipDirectory, to);
|
|
498
|
-
|
|
499
|
-
// Fixing a Zip Path Traversal Vulnerability
|
|
500
|
-
// https://support.google.com/faqs/answer/9294009
|
|
501
|
-
String canonicalPath = toFile.getCanonicalPath();
|
|
502
|
-
if (!canonicalPath.startsWith(param.unzipDirectory.getCanonicalPath() + File.separator)) {
|
|
503
|
-
throw new SecurityException("Illegal name: " + to);
|
|
504
|
-
}
|
|
505
|
-
target.add(toFile);
|
|
506
|
-
}
|
|
507
|
-
continue;
|
|
508
|
-
}
|
|
509
|
-
if (fn.equals("index.bundlejs.patch")) {
|
|
510
|
-
foundBundlePatch = true;
|
|
511
|
-
|
|
512
|
-
byte[] patched = hdiffPatch(readOriginBundle(), readBytes(zipFile.getInputStream(ze)));
|
|
513
|
-
|
|
514
|
-
FileOutputStream fout = new FileOutputStream(new File(param.unzipDirectory, "index.bundlejs"));
|
|
515
|
-
fout.write(patched);
|
|
516
|
-
fout.close();
|
|
516
|
+
appendManifestEntries(obj, copyFroms, copyTos, deletes, copiesMap);
|
|
517
517
|
continue;
|
|
518
518
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
519
|
zipFile.unzipToPath(ze, param.unzipDirectory);
|
|
522
520
|
}
|
|
523
521
|
|
|
524
522
|
zipFile.close();
|
|
525
523
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
524
|
+
buildArchivePatchPlan(
|
|
525
|
+
DownloadTaskParams.TASK_TYPE_PATCH_FROM_APK,
|
|
526
|
+
entryNames.toArray(new String[0]),
|
|
527
|
+
copyFroms.toArray(new String[0]),
|
|
528
|
+
copyTos.toArray(new String[0]),
|
|
529
|
+
deletes.toArray(new String[0])
|
|
530
|
+
);
|
|
531
|
+
HashMap<String, ArrayList<File>> copyList = buildCopyList(
|
|
532
|
+
param.unzipDirectory,
|
|
533
|
+
buildCopyGroups(
|
|
534
|
+
copyFroms.toArray(new String[0]),
|
|
535
|
+
copyTos.toArray(new String[0])
|
|
536
|
+
)
|
|
537
|
+
);
|
|
538
|
+
|
|
539
|
+
File originBundleFile = new File(param.unzipDirectory, ".origin.bundle");
|
|
540
|
+
copyBundledAssetToFile("index.android.bundle", originBundleFile);
|
|
541
|
+
try {
|
|
542
|
+
applyPatchFromFileSource(
|
|
543
|
+
param.unzipDirectory.getAbsolutePath(),
|
|
544
|
+
param.unzipDirectory.getAbsolutePath(),
|
|
545
|
+
originBundleFile.getAbsolutePath(),
|
|
546
|
+
new File(param.unzipDirectory, "index.bundlejs.patch").getAbsolutePath(),
|
|
547
|
+
new File(param.unzipDirectory, "index.bundlejs").getAbsolutePath(),
|
|
548
|
+
"",
|
|
549
|
+
false,
|
|
550
|
+
new String[0],
|
|
551
|
+
new String[0],
|
|
552
|
+
new String[0]
|
|
553
|
+
);
|
|
554
|
+
} finally {
|
|
555
|
+
originBundleFile.delete();
|
|
532
556
|
}
|
|
533
557
|
|
|
534
558
|
if (UpdateContext.DEBUG) {
|
|
@@ -552,10 +576,10 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
552
576
|
removeDirectory(param.unzipDirectory);
|
|
553
577
|
param.unzipDirectory.mkdirs();
|
|
554
578
|
|
|
555
|
-
|
|
556
|
-
String
|
|
557
|
-
|
|
558
|
-
|
|
579
|
+
ArrayList<String> entryNames = new ArrayList<String>();
|
|
580
|
+
ArrayList<String> copyFroms = new ArrayList<String>();
|
|
581
|
+
ArrayList<String> copyTos = new ArrayList<String>();
|
|
582
|
+
ArrayList<String> deletes = new ArrayList<String>();
|
|
559
583
|
|
|
560
584
|
|
|
561
585
|
SafeZipFile zipFile = new SafeZipFile(param.targetFile);
|
|
@@ -563,49 +587,42 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
563
587
|
while (entries.hasMoreElements()) {
|
|
564
588
|
ZipEntry ze = entries.nextElement();
|
|
565
589
|
String fn = ze.getName();
|
|
590
|
+
entryNames.add(fn);
|
|
566
591
|
|
|
567
592
|
if (fn.equals("__diff.json")) {
|
|
568
|
-
foundDiff = true;
|
|
569
593
|
// copy files from assets
|
|
570
594
|
byte[] bytes = readBytes(zipFile.getInputStream(ze));
|
|
571
595
|
String json = new String(bytes, "UTF-8");
|
|
572
596
|
JSONObject obj = (JSONObject)new JSONTokener(json).nextValue();
|
|
573
|
-
|
|
574
|
-
JSONObject copies = obj.getJSONObject("copies");
|
|
575
|
-
Iterator<?> keys = copies.keys();
|
|
576
|
-
while( keys.hasNext() ) {
|
|
577
|
-
String to = (String)keys.next();
|
|
578
|
-
String from = copies.getString(to);
|
|
579
|
-
if (from.isEmpty()) {
|
|
580
|
-
from = to;
|
|
581
|
-
}
|
|
582
|
-
copyFile(new File(param.originDirectory, from), new File(param.unzipDirectory, to));
|
|
583
|
-
}
|
|
584
|
-
JSONObject blackList = obj.getJSONObject("deletes");
|
|
585
|
-
copyFilesWithBlacklist(param.originDirectory, param.unzipDirectory, blackList);
|
|
597
|
+
appendManifestEntries(obj, copyFroms, copyTos, deletes, null);
|
|
586
598
|
continue;
|
|
587
599
|
}
|
|
588
|
-
if (fn.equals("index.bundlejs.patch")) {
|
|
589
|
-
foundBundlePatch = true;
|
|
590
|
-
byte[] patched = hdiffPatch(readFile(new File(param.originDirectory, "index.bundlejs")), readBytes(zipFile.getInputStream(ze)));
|
|
591
|
-
|
|
592
|
-
FileOutputStream fout = new FileOutputStream(new File(param.unzipDirectory, "index.bundlejs"));
|
|
593
|
-
fout.write(patched);
|
|
594
|
-
fout.close();
|
|
595
|
-
continue;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
600
|
zipFile.unzipToPath(ze, param.unzipDirectory);
|
|
599
601
|
}
|
|
600
602
|
|
|
601
603
|
zipFile.close();
|
|
602
604
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
605
|
+
ArchivePatchPlanResult plan = buildArchivePatchPlan(
|
|
606
|
+
DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK,
|
|
607
|
+
entryNames.toArray(new String[0]),
|
|
608
|
+
copyFroms.toArray(new String[0]),
|
|
609
|
+
copyTos.toArray(new String[0]),
|
|
610
|
+
deletes.toArray(new String[0])
|
|
611
|
+
);
|
|
612
|
+
|
|
613
|
+
applyPatchFromFileSource(
|
|
614
|
+
param.originDirectory.getAbsolutePath(),
|
|
615
|
+
param.unzipDirectory.getAbsolutePath(),
|
|
616
|
+
new File(param.originDirectory, "index.bundlejs").getAbsolutePath(),
|
|
617
|
+
new File(param.unzipDirectory, "index.bundlejs.patch").getAbsolutePath(),
|
|
618
|
+
new File(param.unzipDirectory, "index.bundlejs").getAbsolutePath(),
|
|
619
|
+
plan.mergeSourceSubdir,
|
|
620
|
+
plan.enableMerge,
|
|
621
|
+
copyFroms.toArray(new String[0]),
|
|
622
|
+
copyTos.toArray(new String[0]),
|
|
623
|
+
deletes.toArray(new String[0])
|
|
624
|
+
);
|
|
625
|
+
|
|
609
626
|
if (UpdateContext.DEBUG) {
|
|
610
627
|
Log.d("react-native-update", "Unzip finished");
|
|
611
628
|
}
|
|
@@ -614,30 +631,12 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
614
631
|
if (UpdateContext.DEBUG) {
|
|
615
632
|
Log.d("react-native-update", "Start cleaning up");
|
|
616
633
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
continue;
|
|
624
|
-
}
|
|
625
|
-
if (sub.isFile()) {
|
|
626
|
-
sub.delete();
|
|
627
|
-
} else {
|
|
628
|
-
if (sub.getName().equals(param.hash) || sub.getName().equals(param.originHash)) {
|
|
629
|
-
continue;
|
|
630
|
-
}
|
|
631
|
-
removeDirectory(sub);
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
private boolean isFileUpdatedWithinDays(File file, int days) {
|
|
637
|
-
long currentTime = System.currentTimeMillis();
|
|
638
|
-
long lastModified = file.lastModified();
|
|
639
|
-
long daysInMillis = days * 24 * 60 * 60 * 1000L;
|
|
640
|
-
return (currentTime - lastModified) < daysInMillis;
|
|
634
|
+
cleanupOldEntries(
|
|
635
|
+
param.unzipDirectory.getAbsolutePath(),
|
|
636
|
+
param.hash,
|
|
637
|
+
param.originHash,
|
|
638
|
+
7
|
|
639
|
+
);
|
|
641
640
|
}
|
|
642
641
|
|
|
643
642
|
@Override
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
package cn.reactnative.modules.update;
|
|
2
|
+
|
|
3
|
+
final class NativeUpdateCore {
|
|
4
|
+
private static boolean loaded = false;
|
|
5
|
+
|
|
6
|
+
private NativeUpdateCore() {
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
static synchronized void ensureLoaded() {
|
|
10
|
+
if (loaded) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
System.loadLibrary("c++_shared");
|
|
16
|
+
} catch (UnsatisfiedLinkError ignored) {
|
|
17
|
+
// Fall back to the transitive dependency load path when the host app already
|
|
18
|
+
// packages libc++_shared.so but the linker has not loaded it yet.
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
System.loadLibrary("rnupdate");
|
|
23
|
+
} catch (UnsatisfiedLinkError error) {
|
|
24
|
+
UnsatisfiedLinkError wrapped = new UnsatisfiedLinkError(
|
|
25
|
+
"Failed to load rnupdate. Ensure the host app packages libc++_shared.so "
|
|
26
|
+
+ "when using the shared C++ runtime. Original error: "
|
|
27
|
+
+ error.getMessage());
|
|
28
|
+
wrapped.initCause(error);
|
|
29
|
+
throw wrapped;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
loaded = true;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package cn.reactnative.modules.update;
|
|
2
|
+
|
|
3
|
+
class StateCoreResult {
|
|
4
|
+
String packageVersion;
|
|
5
|
+
String buildTime;
|
|
6
|
+
String currentVersion;
|
|
7
|
+
String lastVersion;
|
|
8
|
+
boolean firstTime;
|
|
9
|
+
boolean firstTimeOk;
|
|
10
|
+
String rolledBackVersion;
|
|
11
|
+
boolean changed;
|
|
12
|
+
String staleVersionToDelete;
|
|
13
|
+
String loadVersion;
|
|
14
|
+
boolean didRollback;
|
|
15
|
+
boolean consumedFirstTime;
|
|
16
|
+
}
|