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
@@ -118,6 +118,117 @@ export const dedupeEndpoints = (
118
118
  return result;
119
119
  };
120
120
 
121
+ // Values the natives assume for keys a persisted native check config omits.
122
+ const NATIVE_CONFIG_DEFAULTS: Record<string, unknown> = {
123
+ disabled: false,
124
+ queryUrls: [],
125
+ rnu: '',
126
+ rn: '',
127
+ afterDownload: 'none',
128
+ };
129
+
130
+ /**
131
+ * Deep equality of JSON values, key order ignored. Object members whose value
132
+ * is undefined count as absent, matching JSON.stringify (they do not exist on
133
+ * the wire).
134
+ */
135
+ export const jsonDeepEqual = (a: unknown, b: unknown): boolean => {
136
+ if (a === b) {
137
+ return true;
138
+ }
139
+ if (Array.isArray(a) || Array.isArray(b)) {
140
+ return (
141
+ Array.isArray(a) &&
142
+ Array.isArray(b) &&
143
+ a.length === b.length &&
144
+ a.every((value, index) => jsonDeepEqual(value, b[index]))
145
+ );
146
+ }
147
+ if (!a || !b || typeof a !== 'object' || typeof b !== 'object') {
148
+ return false;
149
+ }
150
+ const left = a as Record<string, unknown>;
151
+ const right = b as Record<string, unknown>;
152
+ const definedKeys = (object: Record<string, unknown>) =>
153
+ Object.keys(object).filter((key) => object[key] !== undefined);
154
+ const leftKeys = definedKeys(left);
155
+ return (
156
+ leftKeys.length === definedKeys(right).length &&
157
+ leftKeys.every(
158
+ (key) =>
159
+ // biome-ignore lint/suspicious/noPrototypeBuiltins: Object.hasOwn is missing from JSC before iOS 15.4
160
+ Object.prototype.hasOwnProperty.call(right, key) &&
161
+ jsonDeepEqual(left[key], right[key])
162
+ )
163
+ );
164
+ };
165
+
166
+ // Each string loses every trailing '/', then entries (strings or not) are
167
+ // deduplicated by JSON value, keeping the first occurrence.
168
+ const canonicalUrlList = (value: unknown): unknown => {
169
+ if (!Array.isArray(value)) {
170
+ return value;
171
+ }
172
+ const result: unknown[] = [];
173
+ const visited = new Set<string>();
174
+ for (const item of value) {
175
+ if (typeof item === 'string') {
176
+ const url = item.replace(/\/+$/, '');
177
+ if (!visited.has(url)) {
178
+ visited.add(url);
179
+ result.push(url);
180
+ }
181
+ } else if (!result.some((existing) => jsonDeepEqual(existing, item))) {
182
+ result.push(item);
183
+ }
184
+ }
185
+ return result;
186
+ };
187
+
188
+ /**
189
+ * Canonical form of a persisted native check config (shared contract C1 with
190
+ * the Android/iOS/Harmony natives): absent keys take their native defaults,
191
+ * `endpoints`/`queryUrls` lose trailing '/' and duplicates (first occurrence
192
+ * kept). Undefined when the JSON is unparseable or not an object.
193
+ */
194
+ export function canonicalizeNativeConfig(
195
+ configJson: string
196
+ ): Record<string, unknown> | undefined {
197
+ let parsed: unknown;
198
+ try {
199
+ parsed = JSON.parse(configJson);
200
+ } catch {
201
+ return undefined;
202
+ }
203
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
204
+ return undefined;
205
+ }
206
+ const canonical: Record<string, unknown> = {
207
+ ...NATIVE_CONFIG_DEFAULTS,
208
+ ...(parsed as Record<string, unknown>),
209
+ };
210
+ for (const key of ['endpoints', 'queryUrls']) {
211
+ if (key in canonical) {
212
+ canonical[key] = canonicalUrlList(canonical[key]);
213
+ }
214
+ }
215
+ return canonical;
216
+ }
217
+
218
+ /**
219
+ * Whether two native check config JSON strings describe the same config
220
+ * (contract C1): their canonical forms are deep-equal, key order ignored.
221
+ * Anything unparseable is never equivalent.
222
+ */
223
+ export function nativeConfigsEquivalent(
224
+ leftJson: string,
225
+ rightJson: string
226
+ ): boolean {
227
+ const left = canonicalizeNativeConfig(leftJson);
228
+ const right = canonicalizeNativeConfig(rightJson);
229
+ return !!left && !!right && jsonDeepEqual(left, right);
230
+ }
231
+
121
232
  /**
122
233
  * The endpoint plan: dedupe, then move the sampled pick to the front (load
123
234
  * spreading), keeping the rest in configured order as the fallback sequence.
@@ -223,8 +334,10 @@ export interface CheckFingerprintInput {
223
334
  appKey?: string;
224
335
  endpoints?: string[];
225
336
  queryUrls?: string[];
226
- uuid?: string;
227
- /** The exact serialized request body (identity fields + extra). */
337
+ /**
338
+ * The exact serialized request body (identity fields + extra; the client
339
+ * uuid travels inside its cInfo).
340
+ */
228
341
  body: string;
229
342
  }
230
343
 
@@ -236,16 +349,9 @@ export function buildCheckFingerprint({
236
349
  appKey,
237
350
  endpoints,
238
351
  queryUrls,
239
- uuid,
240
352
  body,
241
353
  }: CheckFingerprintInput): string {
242
- return JSON.stringify([
243
- appKey ?? '',
244
- endpoints ?? [],
245
- queryUrls ?? [],
246
- uuid ?? '',
247
- body,
248
- ]);
354
+ return JSON.stringify([appKey ?? '', endpoints ?? [], queryUrls ?? [], body]);
249
355
  }
250
356
 
251
357
  /**
package/src/utils.ts CHANGED
@@ -57,6 +57,23 @@ export function promiseAny<T>(promises: Promise<T>[]) {
57
57
  });
58
58
  }
59
59
 
60
+ // Same alphabet and length as nanoid's default (URL-safe, 21 chars), so ids
61
+ // stay format-compatible with the ones nanoid/non-secure used to generate.
62
+ const ID_ALPHABET =
63
+ 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict';
64
+
65
+ /**
66
+ * Non-cryptographic random id (installation uuid). Math.random is enough: it
67
+ * only buckets gray releases, it is not a secret.
68
+ */
69
+ export const createNonSecureId = (size = 21): string => {
70
+ let id = '';
71
+ for (let i = 0; i < size; i++) {
72
+ id += ID_ALPHABET[Math.floor(Math.random() * 64)];
73
+ }
74
+ return id;
75
+ };
76
+
60
77
  export const noop = () => {};
61
78
  const emptyModuleTarget: Record<string, typeof noop> = {};
62
79
  export const emptyModule = new Proxy(emptyModuleTarget, {
@@ -65,40 +82,32 @@ export const emptyModule = new Proxy(emptyModuleTarget, {
65
82
  },
66
83
  });
67
84
 
68
- const ping = isWeb
69
- ? Promise.resolve
70
- : async (url: string) => {
71
- try {
72
- const {
73
- status,
74
- statusText,
75
- url: finalUrl,
76
- } = await fetchWithTimeout(
77
- url,
78
- {
79
- method: 'HEAD',
80
- },
81
- DEFAULT_FETCH_TIMEOUT_MS
82
- );
83
- if (status === 200) {
84
- if (isProtocolDowngrade(url, finalUrl)) {
85
- // The probe was redirected from https to plaintext http. Never
86
- // let a downgraded final URL win the race: the winner is what
87
- // the real artifact download uses.
88
- log('ping rejected: https redirected to http', url, finalUrl);
89
- throw Error(i18n.t('error_ping_failed'));
90
- }
91
- return finalUrl;
92
- }
93
- log('ping failed', url, status, statusText);
85
+ const ping = async (url: string) => {
86
+ try {
87
+ const {
88
+ status,
89
+ statusText,
90
+ url: finalUrl,
91
+ } = await fetchWithTimeout(url, {
92
+ method: 'HEAD',
93
+ });
94
+ if (status === 200) {
95
+ if (isProtocolDowngrade(url, finalUrl)) {
96
+ // The probe was redirected from https to plaintext http. Never let a
97
+ // downgraded final URL win the race: the winner is what the real
98
+ // artifact download uses.
99
+ log('ping rejected: https redirected to http', url, finalUrl);
94
100
  throw Error(i18n.t('error_ping_failed'));
95
- } catch (e) {
96
- log('ping error', url, e);
97
- throw e;
98
101
  }
99
- };
100
-
101
- export { joinUrls } from './updateFlowCore';
102
+ return finalUrl;
103
+ }
104
+ log('ping failed', url, status, statusText);
105
+ throw Error(i18n.t('error_ping_failed'));
106
+ } catch (e) {
107
+ log('ping error', url, e);
108
+ throw e;
109
+ }
110
+ };
102
111
 
103
112
  export const testUrls = async (urls?: string[]): Promise<string | null> => {
104
113
  if (!urls?.length) {
@@ -162,16 +171,14 @@ export const fetchWithTimeout = (
162
171
  // Promise.race the losing fetch kept running (and kept the connection busy)
163
172
  // long after the caller had already moved on.
164
173
  const controller = new AbortController();
165
- // The timeout controller replaces params.signal on the fetch call, so a
166
- // caller-provided signal (e.g. the hedged endpoint race cancelling losers)
167
- // must be chained onto it manually.
168
- const externalSignal =
169
- signal ?? ((params as any)?.signal as AbortSignal | undefined);
174
+ // The timeout controller is the fetch call's signal, so a caller-provided
175
+ // signal (e.g. the hedged endpoint race cancelling losers) must be chained
176
+ // onto it manually.
170
177
  const onExternalAbort = () => controller.abort();
171
- if (externalSignal?.aborted) {
178
+ if (signal?.aborted) {
172
179
  controller.abort();
173
- } else if (externalSignal) {
174
- externalSignal.addEventListener('abort', onExternalAbort);
180
+ } else if (signal) {
181
+ signal.addEventListener('abort', onExternalAbort);
175
182
  }
176
183
  const timeoutId = setTimeout(() => {
177
184
  log('fetch timeout', url);
@@ -180,7 +187,7 @@ export const fetchWithTimeout = (
180
187
 
181
188
  return enhancedFetch(url, { ...params, signal: controller.signal as any })
182
189
  .catch((e: any) => {
183
- if (externalSignal?.aborted) {
190
+ if (signal?.aborted) {
184
191
  // Cancelled by the caller, not timed out; keep the abort semantics.
185
192
  throw e;
186
193
  }
@@ -193,7 +200,7 @@ export const fetchWithTimeout = (
193
200
  clearTimeout(timeoutId);
194
201
  // A long-lived caller signal (one per endpoint race) would otherwise
195
202
  // keep every finished request's listener — and its controller — alive.
196
- externalSignal?.removeEventListener('abort', onExternalAbort);
203
+ signal?.removeEventListener('abort', onExternalAbort);
197
204
  });
198
205
  };
199
206
 
@@ -1,6 +0,0 @@
1
- package cn.reactnative.modules.update;
2
-
3
- class ArchivePatchPlanResult {
4
- String mergeSourceSubdir;
5
- boolean enableMerge;
6
- }
@@ -1,104 +0,0 @@
1
- package cn.reactnative.modules.update;
2
-
3
- import java.util.Arrays;
4
- import java.util.HashSet;
5
- import java.util.Iterator;
6
- import java.util.Set;
7
- import java.util.regex.Pattern;
8
- import org.json.JSONArray;
9
- import org.json.JSONException;
10
- import org.json.JSONObject;
11
-
12
- /** Internal normalizer for the JSONObject accepted by PushyRuntime.configure. */
13
- final class PushyConfiguration {
14
- private static final Set<String> KEYS = new HashSet<>(Arrays.asList(
15
- "appKey", "endpoints", "queryUrls", "afterDownload", "disabled",
16
- "packageVersion", "rnu", "rn"));
17
- private static final Pattern URL = Pattern.compile(
18
- "^https?://(\\[[0-9a-fA-F:]+\\]|[a-zA-Z0-9.-]+)(:[0-9]+)?([/?#]|$)");
19
- // Default service addresses, encoded by scripts/encode-native-text.ts.
20
- private static final String[] ENDPOINTS = {
21
- Texts.reveal("3203e0c1bdd1270a372f18f8c2b6de7f4f2607f5b3d5b9817b592947e5cdefbc8a7e"),
22
- Texts.reveal("3203e0c1bdd1270a372f18f8c2b6de7f4f2607f5f0daac9c644a620ae88ca1ad93")
23
- };
24
- private static final String[] QUERY_URLS = {
25
- Texts.reveal("3203e0c1bdd1270a253608fcd3fd9362476817f4f0d5a1996342631be3c2a3a9d779552507fdcde8928a6f512f5ce2ccbdc869404d2f1de79daa826d562c0913eec4fa9b7d4426"),
26
- Texts.reveal("3203e0c1bdd1270a213b12b7dca09468462e12f3b0d5bd813d482446f4c6a1be8e79552507fdcda68cd06e5c3710e480a4867048483e55e0c2ab8d7d43030d1ce9c3b183214e2601f2f0d5b782601e2719e8ca")
27
- };
28
-
29
- // afterDownload value that selects the bundle for the next launch, encoded.
30
- static final String POLICY_NEXT_LAUNCH = Texts.reveal("2912e0ffab8e6c70323b1dedd3");
31
-
32
- private PushyConfiguration() {}
33
-
34
- static String normalize(String json) throws JSONException {
35
- JSONObject options = new JSONObject(json);
36
- for (Iterator<String> keys = options.keys(); keys.hasNext();) {
37
- String key = keys.next();
38
- if (!KEYS.contains(key)) {
39
- throw invalid("unknown option " + key);
40
- }
41
- }
42
- String appKey = string(options.opt("appKey"), "appKey", false);
43
- boolean customEndpoints = options.has("endpoints");
44
- JSONArray endpoints = urls(customEndpoints ? options.get("endpoints")
45
- : new JSONArray(Arrays.asList(ENDPOINTS)), "endpoints", true);
46
- JSONArray queryUrls = urls(options.has("queryUrls") ? options.get("queryUrls")
47
- : new JSONArray(Arrays.asList(customEndpoints ? new String[0] : QUERY_URLS)),
48
- "queryUrls", false);
49
- String afterDownload = options.has("afterDownload")
50
- ? string(options.get("afterDownload"), "afterDownload", false) : "none";
51
- if (!"none".equals(afterDownload) && !POLICY_NEXT_LAUNCH.equals(afterDownload)) {
52
- throw invalid("afterDownload must be none or " + POLICY_NEXT_LAUNCH);
53
- }
54
- Object disabled = options.has("disabled") ? options.get("disabled") : Boolean.FALSE;
55
- if (!(disabled instanceof Boolean)) {
56
- throw invalid("disabled must be a boolean");
57
- }
58
- JSONObject result = new JSONObject();
59
- result.put("appKey", appKey);
60
- result.put("endpoints", endpoints);
61
- result.put("queryUrls", queryUrls);
62
- result.put("afterDownload", afterDownload);
63
- result.put("disabled", disabled);
64
- result.put("rnu", options.has("rnu") ? string(options.get("rnu"), "rnu", true) : "");
65
- result.put("rn", options.has("rn") ? string(options.get("rn"), "rn", true) : "");
66
- if (options.has("packageVersion")) {
67
- result.put("packageVersion", string(options.get("packageVersion"), "packageVersion", false));
68
- }
69
- return result.toString();
70
- }
71
-
72
- private static String string(Object value, String name, boolean allowEmpty) {
73
- if (!(value instanceof String) || (!allowEmpty && ((String) value).trim().isEmpty())) {
74
- throw invalid(name + " must be a string" + (allowEmpty ? "" : " and must not be blank"));
75
- }
76
- return (String) value;
77
- }
78
-
79
- private static JSONArray urls(Object value, String name, boolean base) throws JSONException {
80
- if (!(value instanceof JSONArray) || (base && ((JSONArray) value).length() == 0)) {
81
- throw invalid(name + " must be " + (base ? "a non-empty" : "an") + " array");
82
- }
83
- JSONArray values = (JSONArray) value;
84
- JSONArray result = new JSONArray();
85
- Set<String> seen = new HashSet<>();
86
- for (int i = 0; i < values.length(); i++) {
87
- String url = string(values.get(i), name, false).trim();
88
- if (!URL.matcher(url).find() || url.matches("(?s).*\\s.*") || url.contains("\\")
89
- || (base && (url.contains("?") || url.contains("#")))) {
90
- throw invalid(name + " requires absolute HTTP(S) URLs without credentials"
91
- + (base ? ", queries or fragments" : ""));
92
- }
93
- String normalized = base ? url.replaceAll("/+$", "") : url;
94
- if (seen.add(normalized)) {
95
- result.put(normalized);
96
- }
97
- }
98
- return result;
99
- }
100
-
101
- private static IllegalArgumentException invalid(String message) {
102
- return new IllegalArgumentException("Invalid native configuration: " + message);
103
- }
104
- }
@@ -1,37 +0,0 @@
1
- package cn.reactnative.modules.update;
2
-
3
- import android.util.Log;
4
- import androidx.annotation.Nullable;
5
- import com.facebook.react.bridge.Promise;
6
- import com.facebook.react.bridge.UiThreadUtil;
7
-
8
- final class UiThreadRunner {
9
- interface Operation {
10
- void run() throws Throwable;
11
- }
12
-
13
- private UiThreadRunner() {
14
- }
15
-
16
- static void run(
17
- @Nullable final Promise promise,
18
- final String errorCode,
19
- final String operationName,
20
- final Operation operation
21
- ) {
22
- UiThreadUtil.runOnUiThread(new Runnable() {
23
- @Override
24
- public void run() {
25
- try {
26
- operation.run();
27
- } catch (Throwable error) {
28
- if (promise != null) {
29
- promise.reject(errorCode, operationName + " failed", error);
30
- } else {
31
- Log.e(Texts.LOG_TAG, operationName + " failed", error);
32
- }
33
- }
34
- }
35
- });
36
- }
37
- }
@@ -1,121 +0,0 @@
1
- package cn.reactnative.modules.update;
2
-
3
- import com.facebook.react.bridge.Promise;
4
- import com.facebook.react.bridge.ReactApplicationContext;
5
- import com.facebook.react.bridge.ReadableMap;
6
- import java.util.Map;
7
-
8
- /**
9
- * New-architecture bridge: the codegen spec overrides only, every method
10
- * forwards to UpdateModuleImpl.
11
- */
12
- public class UpdateModule extends NativePushySpec {
13
- private final UpdateModuleImpl impl;
14
-
15
- public UpdateModule(ReactApplicationContext reactContext, UpdateContext updateContext) {
16
- super(reactContext);
17
- this.impl = new UpdateModuleImpl(reactContext, updateContext);
18
- }
19
-
20
- public UpdateModule(ReactApplicationContext reactContext) {
21
- this(reactContext, UpdateContext.getInstance(reactContext));
22
- }
23
-
24
- @Override
25
- protected Map<String, Object> getTypedExportedConstants() {
26
- return impl.getConstants();
27
- }
28
-
29
- @Override
30
- public String getName() {
31
- return UpdateModuleImpl.NAME;
32
- }
33
-
34
- @Override
35
- public void downloadFullUpdate(ReadableMap options, Promise promise) {
36
- impl.downloadFullUpdate(options, promise);
37
- }
38
-
39
- @Override
40
- public void downloadAndInstallApk(ReadableMap options, Promise promise) {
41
- impl.downloadAndInstallApk(options, promise);
42
- }
43
-
44
- @Override
45
- public void downloadPatchFromPackage(ReadableMap options, Promise promise) {
46
- impl.downloadPatchFromPackage(options, promise);
47
- }
48
-
49
- @Override
50
- public void downloadPatchFromPpk(ReadableMap options, Promise promise) {
51
- impl.downloadPatchFromPpk(options, promise);
52
- }
53
-
54
- @Override
55
- public void reloadUpdate(ReadableMap options, Promise promise) {
56
- impl.reloadUpdate(options, promise);
57
- }
58
-
59
- @Override
60
- public void restartApp(Promise promise) {
61
- impl.restartApp(null, promise);
62
- }
63
-
64
- @Override
65
- public void setNeedUpdate(ReadableMap options, Promise promise) {
66
- impl.setNeedUpdate(options, promise);
67
- }
68
-
69
- @Override
70
- public void markSuccess(Promise promise) {
71
- impl.markSuccess(promise);
72
- }
73
-
74
- @Override
75
- public void getBundleHash(Promise promise) {
76
- impl.getBundleHash(promise);
77
- }
78
-
79
- @Override
80
- public void resetToPackagedBundle(Promise promise) {
81
- impl.resetToPackagedBundle(promise);
82
- }
83
-
84
- @Override
85
- public void setUuid(String uuid, Promise promise) {
86
- impl.setUuid(uuid, promise);
87
- }
88
-
89
- @Override
90
- public void syncNativeConfig(String config, Promise promise) {
91
- impl.syncNativeConfig(config, promise);
92
- }
93
-
94
- @Override
95
- public void getNativeCheckCache(Promise promise) {
96
- impl.getNativeCheckCache(promise);
97
- }
98
-
99
- @Override
100
- public void markJsCheckCompleted(String config, Promise promise) {
101
- impl.markJsCheckCompleted(config, promise);
102
- }
103
-
104
- @Override
105
- public void setLocalHashInfo(String hash, String info, Promise promise) {
106
- impl.setLocalHashInfo(hash, info, promise);
107
- }
108
-
109
- @Override
110
- public void getLocalHashInfo(String hash, Promise promise) {
111
- impl.getLocalHashInfo(hash, promise);
112
- }
113
-
114
- @Override
115
- public void addListener(String eventName) {
116
- }
117
-
118
- @Override
119
- public void removeListeners(double count) {
120
- }
121
- }
@@ -1,125 +0,0 @@
1
- package cn.reactnative.modules.update;
2
-
3
- import com.facebook.react.bridge.Promise;
4
- import com.facebook.react.bridge.ReactApplicationContext;
5
- import com.facebook.react.bridge.ReactContextBaseJavaModule;
6
- import com.facebook.react.bridge.ReactMethod;
7
- import com.facebook.react.bridge.ReadableMap;
8
- import java.util.Map;
9
-
10
- /**
11
- * Old-architecture bridge: @ReactMethod declarations only, every method
12
- * forwards to UpdateModuleImpl. Each state-changing method takes a trailing
13
- * Promise, like the TurboModule spec, so a failed persistence rejects instead
14
- * of resolving early (CODE_AUDIT 2.3).
15
- */
16
- public class UpdateModule extends ReactContextBaseJavaModule {
17
- private final UpdateModuleImpl impl;
18
-
19
- public UpdateModule(ReactApplicationContext reactContext, UpdateContext updateContext) {
20
- super(reactContext);
21
- this.impl = new UpdateModuleImpl(reactContext, updateContext);
22
- }
23
-
24
- public UpdateModule(ReactApplicationContext reactContext) {
25
- this(reactContext, UpdateContext.getInstance(reactContext));
26
- }
27
-
28
- @Override
29
- public Map<String, Object> getConstants() {
30
- return impl.getConstants();
31
- }
32
-
33
- @Override
34
- public String getName() {
35
- return UpdateModuleImpl.NAME;
36
- }
37
-
38
- @ReactMethod
39
- public void downloadFullUpdate(ReadableMap options, Promise promise) {
40
- impl.downloadFullUpdate(options, promise);
41
- }
42
-
43
- @ReactMethod
44
- public void downloadAndInstallApk(ReadableMap options, Promise promise) {
45
- impl.downloadAndInstallApk(options, promise);
46
- }
47
-
48
- @ReactMethod
49
- public void downloadPatchFromPackage(ReadableMap options, Promise promise) {
50
- impl.downloadPatchFromPackage(options, promise);
51
- }
52
-
53
- @ReactMethod
54
- public void downloadPatchFromPpk(ReadableMap options, Promise promise) {
55
- impl.downloadPatchFromPpk(options, promise);
56
- }
57
-
58
- @ReactMethod
59
- public void reloadUpdate(ReadableMap options, Promise promise) {
60
- impl.reloadUpdate(options, promise);
61
- }
62
-
63
- @ReactMethod
64
- public void restartApp(Promise promise) {
65
- impl.restartApp(null, promise);
66
- }
67
-
68
- @ReactMethod
69
- public void setNeedUpdate(ReadableMap options, Promise promise) {
70
- impl.setNeedUpdate(options, promise);
71
- }
72
-
73
- @ReactMethod
74
- public void markSuccess(Promise promise) {
75
- impl.markSuccess(promise);
76
- }
77
-
78
- @ReactMethod
79
- public void getBundleHash(Promise promise) {
80
- impl.getBundleHash(promise);
81
- }
82
-
83
- @ReactMethod
84
- public void resetToPackagedBundle(Promise promise) {
85
- impl.resetToPackagedBundle(promise);
86
- }
87
-
88
- @ReactMethod
89
- public void setUuid(String uuid, Promise promise) {
90
- impl.setUuid(uuid, promise);
91
- }
92
-
93
- @ReactMethod
94
- public void syncNativeConfig(String config, Promise promise) {
95
- impl.syncNativeConfig(config, promise);
96
- }
97
-
98
- @ReactMethod
99
- public void getNativeCheckCache(Promise promise) {
100
- impl.getNativeCheckCache(promise);
101
- }
102
-
103
- @ReactMethod
104
- public void markJsCheckCompleted(String config, Promise promise) {
105
- impl.markJsCheckCompleted(config, promise);
106
- }
107
-
108
- @ReactMethod
109
- public void setLocalHashInfo(String hash, String info, Promise promise) {
110
- impl.setLocalHashInfo(hash, info, promise);
111
- }
112
-
113
- @ReactMethod
114
- public void getLocalHashInfo(String hash, Promise promise) {
115
- impl.getLocalHashInfo(hash, promise);
116
- }
117
-
118
- @ReactMethod
119
- public void addListener(String eventName) {
120
- }
121
-
122
- @ReactMethod
123
- public void removeListeners(Integer count) {
124
- }
125
- }