react-native-update 10.59.1 → 10.60.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.
Files changed (125) hide show
  1. package/README-CN.md +7 -7
  2. package/README.md +7 -6
  3. package/android/build.gradle +25 -33
  4. package/android/jni/Android.mk +16 -24
  5. package/android/lib/arm64-v8a/librnpushy.so +0 -0
  6. package/android/lib/armeabi-v7a/librnpushy.so +0 -0
  7. package/android/lib/x86/librnpushy.so +0 -0
  8. package/android/lib/x86_64/librnpushy.so +0 -0
  9. package/android/proguard.pro +9 -7
  10. package/android/src/main/java/cn/reactnative/modules/update/ApkInstaller.java +11 -12
  11. package/android/src/main/java/cn/reactnative/modules/update/ArchiveLimits.java +23 -6
  12. package/android/src/main/java/cn/reactnative/modules/update/BundledResourceCopier.java +50 -51
  13. package/android/src/main/java/cn/reactnative/modules/update/CleanupKeepNames.java +12 -13
  14. package/android/src/main/java/cn/reactnative/modules/update/CopyGroupResult.java +3 -0
  15. package/android/src/main/java/cn/reactnative/modules/update/CrashHold.java +22 -30
  16. package/android/src/main/java/cn/reactnative/modules/update/DownloadTask.java +181 -332
  17. package/android/src/main/java/cn/reactnative/modules/update/DownloadTaskParams.java +3 -1
  18. package/android/src/main/java/cn/reactnative/modules/update/ErrorCodes.java +27 -0
  19. package/android/src/main/java/cn/reactnative/modules/update/FileOperationException.java +1 -1
  20. package/android/src/main/java/cn/reactnative/modules/update/FlowBridge.java +32 -8
  21. package/android/src/main/java/cn/reactnative/modules/update/HttpClients.java +63 -0
  22. package/android/src/main/java/cn/reactnative/modules/update/HttpUtils.java +0 -11
  23. package/android/src/main/java/cn/reactnative/modules/update/InstallRecord.java +66 -116
  24. package/android/src/main/java/cn/reactnative/modules/update/NativeCore.java +9 -1
  25. package/android/src/main/java/cn/reactnative/modules/update/PatchFailedException.java +1 -1
  26. package/android/src/main/java/cn/reactnative/modules/update/PushyRuntime.java +32 -60
  27. package/android/src/main/java/cn/reactnative/modules/update/ReactReloadManager.java +8 -23
  28. package/android/src/main/java/cn/reactnative/modules/update/SafeZipFile.java +42 -80
  29. package/android/src/main/java/cn/reactnative/modules/update/StateSerialRunner.java +22 -39
  30. package/android/src/main/java/cn/reactnative/modules/update/SyncCoordinator.java +176 -299
  31. package/android/src/main/java/cn/reactnative/modules/update/Threads.java +35 -0
  32. package/android/src/main/java/cn/reactnative/modules/update/UpdateContext.java +242 -174
  33. package/android/src/main/java/cn/reactnative/modules/update/UpdateEventEmitter.java +1 -1
  34. package/android/src/main/java/cn/reactnative/modules/update/UpdateFileUtils.java +75 -17
  35. package/android/src/main/java/cn/reactnative/modules/update/{UpdateModuleImpl.java → UpdateModule.java} +113 -95
  36. package/android/src/main/java/cn/reactnative/modules/update/UpdatePackage.java +16 -19
  37. package/android/src/oldarch/cn/reactnative/modules/update/NativePushySpec.java +69 -0
  38. package/cpp/android_jni/archive_limits_jni.cpp +83 -0
  39. package/cpp/android_jni/install_record_jni.cpp +89 -0
  40. package/cpp/android_jni/jni_log.h +31 -0
  41. package/cpp/android_jni/jni_natives.h +40 -0
  42. package/cpp/android_jni/jni_registration.cpp +133 -0
  43. package/cpp/android_jni/jni_util.h +160 -0
  44. package/cpp/android_jni/update_core_android.cpp +450 -0
  45. package/cpp/android_jni/update_flow_jni.cpp +133 -0
  46. package/{android/jni → cpp/hpatch}/hpatch.c +5 -5
  47. package/{android/jni → cpp/hpatch}/hpatch.h +4 -1
  48. package/cpp/patch_core/archive_limits.cpp +194 -0
  49. package/cpp/patch_core/archive_limits.h +99 -10
  50. package/cpp/patch_core/archive_patch_core.cpp +96 -12
  51. package/cpp/patch_core/archive_patch_core.h +49 -0
  52. package/cpp/patch_core/digest.h +5 -4
  53. package/cpp/patch_core/error_codes.h +5 -3
  54. package/cpp/patch_core/install_record.cpp +430 -0
  55. package/cpp/patch_core/install_record.h +163 -9
  56. package/cpp/patch_core/patch_core.cpp +62 -16
  57. package/cpp/patch_core/patch_core.h +27 -7
  58. package/cpp/patch_core/patch_manifest.cpp +201 -0
  59. package/cpp/patch_core/patch_manifest.h +74 -0
  60. package/cpp/patch_core/state_ops.h +3 -3
  61. package/cpp/update_flow_core/flow_json.cpp +82 -8
  62. package/cpp/update_flow_core/flow_json.h +21 -0
  63. package/cpp/update_flow_core/native_config.cpp +456 -0
  64. package/cpp/update_flow_core/native_config.h +84 -0
  65. package/cpp/update_flow_core/native_round.cpp +326 -0
  66. package/cpp/update_flow_core/native_round.h +90 -0
  67. package/cpp/update_flow_core/update_flow_core.h +2 -2
  68. package/harmony/hvigor-plugin.ts +11 -19
  69. package/harmony/pushy/src/main/cpp/CMakeLists.txt +19 -26
  70. package/harmony/pushy/src/main/cpp/PushyPackage.h +2 -2
  71. package/harmony/pushy/src/main/cpp/PushyTurboModule.cpp +55 -94
  72. package/harmony/pushy/src/main/cpp/pushy.cpp +694 -517
  73. package/harmony/pushy/src/main/ets/ArchiveLimits.ts +48 -72
  74. package/harmony/pushy/src/main/ets/DownloadTask.ts +164 -404
  75. package/harmony/pushy/src/main/ets/DownloadTaskParams.ts +1 -3
  76. package/harmony/pushy/src/main/ets/ErrorCodes.ts +1 -14
  77. package/harmony/pushy/src/main/ets/EventHub.ts +1 -1
  78. package/harmony/pushy/src/main/ets/InstallRecord.ts +52 -151
  79. package/harmony/pushy/src/main/ets/Logger.ts +20 -34
  80. package/harmony/pushy/src/main/ets/NativePatchCore.ts +116 -42
  81. package/harmony/pushy/src/main/ets/PushyConfiguration.ts +8 -85
  82. package/harmony/pushy/src/main/ets/PushyTurboModule.ts +11 -25
  83. package/harmony/pushy/src/main/ets/SaveFile.ts +99 -18
  84. package/harmony/pushy/src/main/ets/SyncCoordinator.ts +136 -335
  85. package/harmony/pushy/src/main/ets/Texts.ts +0 -4
  86. package/harmony/pushy/src/main/ets/UpdateContext.ts +106 -119
  87. package/harmony/pushy.har +0 -0
  88. package/ios/RCTPushy/RCTPushy+Launch.mm +185 -0
  89. package/ios/RCTPushy/RCTPushy.h +12 -0
  90. package/ios/RCTPushy/RCTPushy.mm +87 -2628
  91. package/ios/RCTPushy/RCTPushyCommon.h +34 -0
  92. package/ios/RCTPushy/RCTPushyConfiguration.h +0 -8
  93. package/ios/RCTPushy/RCTPushyConfiguration.mm +40 -121
  94. package/ios/RCTPushy/RCTPushyDownloader.mm +40 -37
  95. package/ios/RCTPushy/RCTPushyInstallRecord.mm +61 -0
  96. package/ios/RCTPushy/RCTPushyInstaller.mm +689 -0
  97. package/ios/RCTPushy/RCTPushyInternal.h +144 -0
  98. package/ios/RCTPushy/RCTPushyOrchestrator.mm +1001 -0
  99. package/ios/RCTPushy/RCTPushyState.mm +314 -0
  100. package/package.json +25 -23
  101. package/react-native-update.podspec +74 -83
  102. package/src/client.ts +361 -451
  103. package/src/context.ts +1 -1
  104. package/src/core.ts +35 -8
  105. package/src/endpoint.ts +0 -2
  106. package/src/error.ts +13 -32
  107. package/src/i18n.ts +18 -83
  108. package/src/locales/en.ts +0 -4
  109. package/src/locales/zh.ts +0 -4
  110. package/src/provider.tsx +60 -53
  111. package/src/telemetry.ts +0 -13
  112. package/src/type.ts +0 -15
  113. package/src/updateFlowCore.ts +116 -10
  114. package/src/utils.ts +49 -42
  115. package/android/src/main/java/cn/reactnative/modules/update/ArchivePatchPlanResult.java +0 -6
  116. package/android/src/main/java/cn/reactnative/modules/update/PushyConfiguration.java +0 -104
  117. package/android/src/main/java/cn/reactnative/modules/update/UiThreadRunner.java +0 -37
  118. package/android/src/newarch/cn/reactnative/modules/update/UpdateModule.java +0 -121
  119. package/android/src/oldarch/cn/reactnative/modules/update/UpdateModule.java +0 -125
  120. package/cpp/patch_core/jni_natives.h +0 -27
  121. package/cpp/patch_core/jni_registration.cpp +0 -103
  122. package/cpp/patch_core/jni_util.h +0 -60
  123. package/cpp/patch_core/patch_core_android.cpp +0 -97
  124. package/cpp/patch_core/update_core_android.cpp +0 -485
  125. package/cpp/update_flow_core/update_flow_jni.cpp +0 -150
@@ -1,11 +1,14 @@
1
1
  package cn.reactnative.modules.update;
2
2
 
3
- import java.io.BufferedInputStream;
4
- import java.io.BufferedOutputStream;
5
3
  import java.io.File;
6
4
  import java.io.FileOutputStream;
7
5
  import java.io.IOException;
8
6
  import java.io.InputStream;
7
+ import java.io.OutputStream;
8
+ import java.security.DigestOutputStream;
9
+ import java.security.MessageDigest;
10
+ import java.util.ArrayList;
11
+ import java.util.Collections;
9
12
  import java.util.Enumeration;
10
13
  import java.util.zip.ZipEntry;
11
14
  import java.util.zip.ZipFile;
@@ -17,73 +20,30 @@ public class SafeZipFile extends ZipFile {
17
20
  super(file);
18
21
  }
19
22
 
20
- private static final int BUFFER_SIZE = 8192;
21
-
22
- // Bytes written by unzipToFile across the archive: the sum of the central
23
- // directory's declared sizes is checked up front (inspect), the actual
23
+ // Bytes written by unzipToFile across the archive: the central
24
+ // directory's declared sizes are checked up front (inspect), the actual
24
25
  // stream is re-checked here — headers can lie.
25
26
  private long totalWritten = 0;
26
27
 
27
- static final class Inspection {
28
- long entries;
29
- long totalUncompressed;
30
- }
31
-
32
28
  /**
33
- * Walks the central directory once, enforcing the archive_limits caps
34
- * (entry count, per-entry size, total size, compression ratio) and the
35
- * reserved-name / traversal rules, before a single byte is extracted.
29
+ * Walks the central directory once and hands it to the shared accounting
30
+ * (ArchiveLimits.checkEntries: entry count, per-entry and total size,
31
+ * compression ratios, reserved `.pushy-` names) before a single byte is
32
+ * extracted. Returns the total uncompressed size.
36
33
  */
37
- Inspection inspect() throws IOException {
38
- Inspection result = new Inspection();
39
- Enumeration<? extends ZipEntry> entries = entries();
40
- while (entries.hasMoreElements()) {
41
- ZipEntry entry = entries.nextElement();
42
- result.entries++;
43
- if (result.entries > ArchiveLimits.MAX_ENTRIES) {
44
- throw new IOException(
45
- "archive has too many entries (> " + ArchiveLimits.MAX_ENTRIES + ")");
46
- }
47
- long size = entry.getSize();
48
- long compressed = entry.getCompressedSize();
49
- if (size > ArchiveLimits.MAX_ENTRY_BYTES) {
50
- throw new IOException(
51
- "archive entry too large: " + entry.getName() + " (" + size + " bytes)");
52
- }
53
- if (size > 0) {
54
- result.totalUncompressed += size;
55
- if (result.totalUncompressed > ArchiveLimits.MAX_TOTAL_UNCOMPRESSED_BYTES) {
56
- throw new IOException("archive expands beyond "
57
- + ArchiveLimits.MAX_TOTAL_UNCOMPRESSED_BYTES + " bytes");
58
- }
59
- if (compressed > 0 && size > ArchiveLimits.RATIO_CHECK_MIN_BYTES
60
- && size / compressed > ArchiveLimits.MAX_COMPRESSION_RATIO) {
61
- throw new IOException(
62
- "archive entry compression ratio too high: " + entry.getName());
63
- }
64
- }
34
+ long inspect(long archiveBytes) throws IOException {
35
+ ArrayList<? extends ZipEntry> entries = Collections.list(entries());
36
+ int count = entries.size();
37
+ String[] names = new String[count];
38
+ long[] sizes = new long[count];
39
+ long[] compressedSizes = new long[count];
40
+ for (int i = 0; i < count; i++) {
41
+ ZipEntry entry = entries.get(i);
42
+ names[i] = entry.getName();
43
+ sizes[i] = entry.getSize();
44
+ compressedSizes[i] = entry.getCompressedSize();
65
45
  }
66
- return result;
67
- }
68
-
69
- // Files the SDK itself writes into a version directory to record its own
70
- // decisions (the ".pushy-complete" install marker today). An archive
71
- // must never be able to ship one: a package that unzips its own marker
72
- // next to a bundle would be trusted as a finished install even when the
73
- // patch step that follows fails.
74
- static final String RESERVED_ENTRY_PREFIX = ".pushy-";
75
-
76
- static boolean isReservedEntryName(String name) {
77
- if (name == null) {
78
- return false;
79
- }
80
- String normalized = name.replace('\\', '/');
81
- while (normalized.endsWith("/")) {
82
- normalized = normalized.substring(0, normalized.length() - 1);
83
- }
84
- int slash = normalized.lastIndexOf('/');
85
- String baseName = slash >= 0 ? normalized.substring(slash + 1) : normalized;
86
- return baseName.startsWith(RESERVED_ENTRY_PREFIX);
46
+ return ArchiveLimits.checkEntries(archiveBytes, names, sizes, compressedSizes);
87
47
  }
88
48
 
89
49
  @Override
@@ -115,15 +75,17 @@ public class SafeZipFile extends ZipFile {
115
75
  if (null != name && (name.contains("../") || name.contains("..\\"))) {
116
76
  throw new SecurityException("illegal entry: " + name);
117
77
  }
118
- if (isReservedEntryName(name)) {
119
- throw new SecurityException("reserved entry: " + name);
120
- }
121
78
  }
122
79
  return entry;
123
80
  }
124
81
  }
125
82
 
126
83
  public void unzipToPath(ZipEntry ze, File targetPath) throws IOException {
84
+ unzipToPath(ze, targetPath, null);
85
+ }
86
+
87
+ /** As above; a non-null digest is fed every byte written for the entry. */
88
+ void unzipToPath(ZipEntry ze, File targetPath, MessageDigest digest) throws IOException {
127
89
  String name = ze.getName();
128
90
  File target = new File(targetPath, name);
129
91
 
@@ -133,22 +95,19 @@ public class SafeZipFile extends ZipFile {
133
95
  if (!canonicalPath.startsWith(targetPath.getCanonicalPath() + File.separator)) {
134
96
  throw new SecurityException("Illegal name: " + name);
135
97
  }
136
- if (isReservedEntryName(name)) {
137
- throw new SecurityException("reserved entry: " + name);
138
- }
139
-
140
98
  if (ze.isDirectory()) {
141
99
  target.mkdirs();
142
100
  return;
143
101
  }
144
- unzipToFile(ze, target);
102
+ unzipToFile(ze, target, digest);
145
103
  }
146
104
 
147
105
  public void unzipToFile(ZipEntry ze, File target) throws IOException {
148
- File parent = target.getParentFile();
149
- if (parent != null && !parent.exists() && !parent.mkdirs() && !parent.exists()) {
150
- throw new IOException("Failed to create parent dir for " + target);
151
- }
106
+ unzipToFile(ze, target, null);
107
+ }
108
+
109
+ private void unzipToFile(ZipEntry ze, File target, MessageDigest digest) throws IOException {
110
+ UpdateFileUtils.ensureParentDirectory(target);
152
111
 
153
112
  // The declared size is the budget when known; otherwise the global
154
113
  // per-entry cap. Either way the stream may not exceed it.
@@ -157,12 +116,15 @@ public class SafeZipFile extends ZipFile {
157
116
  ? Math.min(declared, ArchiveLimits.MAX_ENTRY_BYTES)
158
117
  : ArchiveLimits.MAX_ENTRY_BYTES;
159
118
  long written = 0;
160
- try (InputStream inputStream = getInputStream(ze)) {
161
- try (BufferedOutputStream output = new BufferedOutputStream(new FileOutputStream(target));
162
- BufferedInputStream input = new BufferedInputStream(inputStream)) {
163
- byte[] buffer = new byte[BUFFER_SIZE];
119
+ // One 64KB buffer, no extra buffered wrappers: every read/write is
120
+ // already a large block.
121
+ try (InputStream input = getInputStream(ze)) {
122
+ try (OutputStream output = digest == null
123
+ ? new FileOutputStream(target)
124
+ : new DigestOutputStream(new FileOutputStream(target), digest)) {
125
+ byte[] buffer = new byte[UpdateFileUtils.BUFFER_SIZE];
164
126
  int n;
165
- while ((n = input.read(buffer, 0, BUFFER_SIZE)) >= 0) {
127
+ while ((n = input.read(buffer, 0, buffer.length)) >= 0) {
166
128
  written += n;
167
129
  totalWritten += n;
168
130
  if (written > budget) {
@@ -1,64 +1,47 @@
1
1
  package cn.reactnative.modules.update;
2
2
 
3
- import android.util.Log;
4
- import androidx.annotation.Nullable;
5
3
  import com.facebook.react.bridge.Promise;
6
-
4
+ import com.facebook.react.bridge.UiThreadUtil;
7
5
  import java.util.concurrent.Executor;
8
- import java.util.concurrent.Executors;
9
- import java.util.concurrent.ThreadFactory;
10
6
 
11
7
  /**
12
- * Runs state-persistence operations (switchVersion / markSuccess / setUuid /
13
- * setLocalHashInfo) on a dedicated single background thread.
14
- *
15
- * These operations only read/modify SharedPreferences via a synchronous
16
- * commit(); they were previously dispatched to the UI thread purely to
17
- * serialize them. markSuccess in particular runs on every cold start, so doing
18
- * its blocking disk write on the main thread caused jank/ANR on low-end
19
- * devices. A single-thread executor preserves the same serialization guarantee
20
- * while keeping the disk I/O off the UI thread.
8
+ * Runs a module operation on a given executor and rejects its promise with
9
+ * the operation's error code when it throws; the operation resolves the
10
+ * promise itself.
21
11
  *
22
- * Note: reload/restart operations must still run on the UI thread and therefore
23
- * keep using {@link UiThreadRunner}.
12
+ * State-persistence operations (switchVersion / markSuccess / setUuid /
13
+ * setLocalHashInfo / reset / config) go to {@link #STATE_SERIAL}, a single
14
+ * background thread: they only read/modify SharedPreferences via a
15
+ * synchronous commit(), and were once dispatched to the UI thread purely to
16
+ * serialize them. markSuccess runs on every cold start, so its blocking disk
17
+ * write on the main thread caused jank/ANR on low-end devices; one worker
18
+ * keeps the serialization in submission order without that. Only the React
19
+ * reload itself still hops to {@link #UI_THREAD}.
24
20
  */
25
21
  final class StateSerialRunner {
26
22
  interface Operation {
27
23
  void run() throws Throwable;
28
24
  }
29
25
 
30
- // Single worker thread -> operations stay serialized in submission order,
31
- // matching the previous UI-thread behavior. The thread is named so it is
32
- // identifiable in thread dumps / ANR traces when diagnosing persistence.
33
- private static final Executor EXECUTOR = Executors.newSingleThreadExecutor(
34
- new ThreadFactory() {
35
- @Override
36
- public Thread newThread(Runnable r) {
37
- return new Thread(r, "pushy-state-serial");
38
- }
39
- });
26
+ // Named so it is identifiable in thread dumps / ANR traces.
27
+ static final Executor STATE_SERIAL = Threads.single("pushy-state-serial", false);
28
+ static final Executor UI_THREAD = UiThreadUtil::runOnUiThread;
40
29
 
41
30
  private StateSerialRunner() {
42
31
  }
43
32
 
44
33
  static void run(
45
- @Nullable final Promise promise,
34
+ Executor executor,
35
+ final Promise promise,
46
36
  final String errorCode,
47
37
  final String operationName,
48
38
  final Operation operation
49
39
  ) {
50
- EXECUTOR.execute(new Runnable() {
51
- @Override
52
- public void run() {
53
- try {
54
- operation.run();
55
- } catch (Throwable error) {
56
- if (promise != null) {
57
- promise.reject(errorCode, operationName + " failed", error);
58
- } else {
59
- Log.e(Texts.LOG_TAG, operationName + " failed", error);
60
- }
61
- }
40
+ executor.execute(() -> {
41
+ try {
42
+ operation.run();
43
+ } catch (Throwable error) {
44
+ promise.reject(errorCode, operationName + " failed", error);
62
45
  }
63
46
  });
64
47
  }