react-native-update 10.37.19 → 10.38.0-beta.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 +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 +136 -136
- 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/android/src/main/java/cn/reactnative/modules/update/UpdateModuleImpl.java +88 -40
- 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-02-38-0668.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,43 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
163
191
|
return fout.toByteArray();
|
|
164
192
|
}
|
|
165
193
|
|
|
166
|
-
private
|
|
167
|
-
InputStream in;
|
|
168
|
-
|
|
169
|
-
in = context.getAssets().open("index.android.bundle");
|
|
170
|
-
} catch (Exception e) {
|
|
171
|
-
return new byte[0];
|
|
172
|
-
}
|
|
194
|
+
private void copyBundledAssetToFile(String assetName, File destination) throws IOException {
|
|
195
|
+
InputStream in = context.getAssets().open(assetName);
|
|
196
|
+
FileOutputStream fout = new FileOutputStream(destination);
|
|
173
197
|
int count;
|
|
174
|
-
|
|
175
|
-
ByteArrayOutputStream fout = new ByteArrayOutputStream();
|
|
176
|
-
while ((count = in.read(buffer)) != -1)
|
|
177
|
-
{
|
|
198
|
+
while ((count = in.read(buffer)) != -1) {
|
|
178
199
|
fout.write(buffer, 0, count);
|
|
179
200
|
}
|
|
180
|
-
|
|
181
201
|
fout.close();
|
|
182
202
|
in.close();
|
|
183
|
-
return fout.toByteArray();
|
|
184
203
|
}
|
|
185
204
|
|
|
186
|
-
private
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
fout.write(buffer, 0, count);
|
|
205
|
+
private HashMap<String, ArrayList<File>> buildCopyList(
|
|
206
|
+
File unzipDirectory,
|
|
207
|
+
CopyGroupResult[] groups
|
|
208
|
+
) throws IOException {
|
|
209
|
+
HashMap<String, ArrayList<File>> copyList = new HashMap<String, ArrayList<File>>();
|
|
210
|
+
if (groups == null) {
|
|
211
|
+
return copyList;
|
|
194
212
|
}
|
|
195
213
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
continue;
|
|
208
|
-
}
|
|
209
|
-
File toFile = new File(to, file.getName());
|
|
210
|
-
if (!toFile.exists()) {
|
|
211
|
-
toFile.mkdir();
|
|
212
|
-
}
|
|
213
|
-
copyFilesWithBlacklist(subName, file, toFile, blackList);
|
|
214
|
-
} else if (!blackList.has(current + file.getName())) {
|
|
215
|
-
// Copy file.
|
|
216
|
-
File toFile = new File(to, file.getName());
|
|
217
|
-
if (!toFile.exists()) {
|
|
218
|
-
copyFile(file, toFile);
|
|
214
|
+
String rootPath = unzipDirectory.getCanonicalPath() + File.separator;
|
|
215
|
+
for (CopyGroupResult group : groups) {
|
|
216
|
+
ArrayList<File> targets = new ArrayList<File>();
|
|
217
|
+
if (group.toPaths != null) {
|
|
218
|
+
for (String to : group.toPaths) {
|
|
219
|
+
File toFile = new File(unzipDirectory, to);
|
|
220
|
+
String canonicalPath = toFile.getCanonicalPath();
|
|
221
|
+
if (!canonicalPath.startsWith(rootPath)) {
|
|
222
|
+
throw new SecurityException("Illegal name: " + to);
|
|
223
|
+
}
|
|
224
|
+
targets.add(toFile);
|
|
219
225
|
}
|
|
220
226
|
}
|
|
227
|
+
copyList.put(group.from, targets);
|
|
221
228
|
}
|
|
222
|
-
}
|
|
223
229
|
|
|
224
|
-
|
|
225
|
-
copyFilesWithBlacklist("", from, to, blackList);
|
|
230
|
+
return copyList;
|
|
226
231
|
}
|
|
227
232
|
|
|
228
233
|
private void doFullPatch(DownloadTaskParams param) throws IOException {
|
|
@@ -457,20 +462,20 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
457
462
|
|
|
458
463
|
removeDirectory(param.unzipDirectory);
|
|
459
464
|
param.unzipDirectory.mkdirs();
|
|
460
|
-
HashMap<String, ArrayList<File>> copyList = new HashMap<String, ArrayList<File>>();
|
|
461
465
|
HashMap<String, String> copiesMap = new HashMap<String, String>(); // to -> from 映射
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
466
|
+
ArrayList<String> entryNames = new ArrayList<String>();
|
|
467
|
+
ArrayList<String> copyFroms = new ArrayList<String>();
|
|
468
|
+
ArrayList<String> copyTos = new ArrayList<String>();
|
|
469
|
+
ArrayList<String> deletes = new ArrayList<String>();
|
|
465
470
|
|
|
466
471
|
SafeZipFile zipFile = new SafeZipFile(param.targetFile);
|
|
467
472
|
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
|
468
473
|
while (entries.hasMoreElements()) {
|
|
469
474
|
ZipEntry ze = entries.nextElement();
|
|
470
475
|
String fn = ze.getName();
|
|
476
|
+
entryNames.add(fn);
|
|
471
477
|
|
|
472
478
|
if (fn.equals("__diff.json")) {
|
|
473
|
-
foundDiff = true;
|
|
474
479
|
// copy files from assets
|
|
475
480
|
byte[] bytes = readBytes(zipFile.getInputStream(ze));
|
|
476
481
|
String json = new String(bytes, "UTF-8");
|
|
@@ -484,51 +489,55 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
484
489
|
if (from.isEmpty()) {
|
|
485
490
|
from = to;
|
|
486
491
|
}
|
|
492
|
+
copyFroms.add(from);
|
|
493
|
+
copyTos.add(to);
|
|
487
494
|
// 保存 copies 映射关系(to -> from)
|
|
488
495
|
copiesMap.put(to, from);
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
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);
|
|
496
|
+
}
|
|
497
|
+
JSONObject blackList = obj.getJSONObject("deletes");
|
|
498
|
+
Iterator<?> deleteKeys = blackList.keys();
|
|
499
|
+
while (deleteKeys.hasNext()) {
|
|
500
|
+
deletes.add((String)deleteKeys.next());
|
|
506
501
|
}
|
|
507
502
|
continue;
|
|
508
503
|
}
|
|
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();
|
|
517
|
-
continue;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
|
|
521
504
|
zipFile.unzipToPath(ze, param.unzipDirectory);
|
|
522
505
|
}
|
|
523
506
|
|
|
524
507
|
zipFile.close();
|
|
525
508
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
509
|
+
buildArchivePatchPlan(
|
|
510
|
+
DownloadTaskParams.TASK_TYPE_PATCH_FROM_APK,
|
|
511
|
+
entryNames.toArray(new String[0]),
|
|
512
|
+
copyFroms.toArray(new String[0]),
|
|
513
|
+
copyTos.toArray(new String[0]),
|
|
514
|
+
deletes.toArray(new String[0])
|
|
515
|
+
);
|
|
516
|
+
HashMap<String, ArrayList<File>> copyList = buildCopyList(
|
|
517
|
+
param.unzipDirectory,
|
|
518
|
+
buildCopyGroups(
|
|
519
|
+
copyFroms.toArray(new String[0]),
|
|
520
|
+
copyTos.toArray(new String[0])
|
|
521
|
+
)
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
File originBundleFile = new File(param.unzipDirectory, ".origin.bundle");
|
|
525
|
+
copyBundledAssetToFile("index.android.bundle", originBundleFile);
|
|
526
|
+
try {
|
|
527
|
+
applyPatchFromFileSource(
|
|
528
|
+
param.unzipDirectory.getAbsolutePath(),
|
|
529
|
+
param.unzipDirectory.getAbsolutePath(),
|
|
530
|
+
originBundleFile.getAbsolutePath(),
|
|
531
|
+
new File(param.unzipDirectory, "index.bundlejs.patch").getAbsolutePath(),
|
|
532
|
+
new File(param.unzipDirectory, "index.bundlejs").getAbsolutePath(),
|
|
533
|
+
"",
|
|
534
|
+
false,
|
|
535
|
+
new String[0],
|
|
536
|
+
new String[0],
|
|
537
|
+
new String[0]
|
|
538
|
+
);
|
|
539
|
+
} finally {
|
|
540
|
+
originBundleFile.delete();
|
|
532
541
|
}
|
|
533
542
|
|
|
534
543
|
if (UpdateContext.DEBUG) {
|
|
@@ -552,10 +561,10 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
552
561
|
removeDirectory(param.unzipDirectory);
|
|
553
562
|
param.unzipDirectory.mkdirs();
|
|
554
563
|
|
|
555
|
-
|
|
556
|
-
String
|
|
557
|
-
|
|
558
|
-
|
|
564
|
+
ArrayList<String> entryNames = new ArrayList<String>();
|
|
565
|
+
ArrayList<String> copyFroms = new ArrayList<String>();
|
|
566
|
+
ArrayList<String> copyTos = new ArrayList<String>();
|
|
567
|
+
ArrayList<String> deletes = new ArrayList<String>();
|
|
559
568
|
|
|
560
569
|
|
|
561
570
|
SafeZipFile zipFile = new SafeZipFile(param.targetFile);
|
|
@@ -563,9 +572,9 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
563
572
|
while (entries.hasMoreElements()) {
|
|
564
573
|
ZipEntry ze = entries.nextElement();
|
|
565
574
|
String fn = ze.getName();
|
|
575
|
+
entryNames.add(fn);
|
|
566
576
|
|
|
567
577
|
if (fn.equals("__diff.json")) {
|
|
568
|
-
foundDiff = true;
|
|
569
578
|
// copy files from assets
|
|
570
579
|
byte[] bytes = readBytes(zipFile.getInputStream(ze));
|
|
571
580
|
String json = new String(bytes, "UTF-8");
|
|
@@ -579,33 +588,42 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
579
588
|
if (from.isEmpty()) {
|
|
580
589
|
from = to;
|
|
581
590
|
}
|
|
582
|
-
|
|
591
|
+
copyFroms.add(from);
|
|
592
|
+
copyTos.add(to);
|
|
583
593
|
}
|
|
584
594
|
JSONObject blackList = obj.getJSONObject("deletes");
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
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
|
+
Iterator<?> deleteKeys = blackList.keys();
|
|
596
|
+
while (deleteKeys.hasNext()) {
|
|
597
|
+
deletes.add((String)deleteKeys.next());
|
|
598
|
+
}
|
|
595
599
|
continue;
|
|
596
600
|
}
|
|
597
|
-
|
|
598
601
|
zipFile.unzipToPath(ze, param.unzipDirectory);
|
|
599
602
|
}
|
|
600
603
|
|
|
601
604
|
zipFile.close();
|
|
602
605
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
606
|
+
ArchivePatchPlanResult plan = buildArchivePatchPlan(
|
|
607
|
+
DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK,
|
|
608
|
+
entryNames.toArray(new String[0]),
|
|
609
|
+
copyFroms.toArray(new String[0]),
|
|
610
|
+
copyTos.toArray(new String[0]),
|
|
611
|
+
deletes.toArray(new String[0])
|
|
612
|
+
);
|
|
613
|
+
|
|
614
|
+
applyPatchFromFileSource(
|
|
615
|
+
param.originDirectory.getAbsolutePath(),
|
|
616
|
+
param.unzipDirectory.getAbsolutePath(),
|
|
617
|
+
new File(param.originDirectory, "index.bundlejs").getAbsolutePath(),
|
|
618
|
+
new File(param.unzipDirectory, "index.bundlejs.patch").getAbsolutePath(),
|
|
619
|
+
new File(param.unzipDirectory, "index.bundlejs").getAbsolutePath(),
|
|
620
|
+
plan.mergeSourceSubdir,
|
|
621
|
+
plan.enableMerge,
|
|
622
|
+
copyFroms.toArray(new String[0]),
|
|
623
|
+
copyTos.toArray(new String[0]),
|
|
624
|
+
deletes.toArray(new String[0])
|
|
625
|
+
);
|
|
626
|
+
|
|
609
627
|
if (UpdateContext.DEBUG) {
|
|
610
628
|
Log.d("react-native-update", "Unzip finished");
|
|
611
629
|
}
|
|
@@ -614,30 +632,12 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
|
|
614
632
|
if (UpdateContext.DEBUG) {
|
|
615
633
|
Log.d("react-native-update", "Start cleaning up");
|
|
616
634
|
}
|
|
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;
|
|
635
|
+
cleanupOldEntries(
|
|
636
|
+
param.unzipDirectory.getAbsolutePath(),
|
|
637
|
+
param.hash,
|
|
638
|
+
param.originHash,
|
|
639
|
+
7
|
|
640
|
+
);
|
|
641
641
|
}
|
|
642
642
|
|
|
643
643
|
@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
|
+
}
|