react-native-update 10.59.0 → 10.59.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.
Files changed (68) hide show
  1. package/android/build.gradle +46 -14
  2. package/android/jni/Android.mk +2 -1
  3. package/android/lib/arm64-v8a/librnpushy.so +0 -0
  4. package/android/lib/armeabi-v7a/librnpushy.so +0 -0
  5. package/android/lib/x86/librnpushy.so +0 -0
  6. package/android/lib/x86_64/librnpushy.so +0 -0
  7. package/android/src/main/java/cn/reactnative/modules/update/ApkInstaller.java +6 -6
  8. package/android/src/main/java/cn/reactnative/modules/update/BundledResourceCopier.java +4 -4
  9. package/android/src/main/java/cn/reactnative/modules/update/{CrashRescue.java → CrashHold.java} +12 -12
  10. package/android/src/main/java/cn/reactnative/modules/update/DownloadTask.java +28 -24
  11. package/android/src/main/java/cn/reactnative/modules/update/ErrorCodes.java +2 -1
  12. package/android/src/main/java/cn/reactnative/modules/update/{NativeUpdateFlow.java → FlowBridge.java} +6 -6
  13. package/android/src/main/java/cn/reactnative/modules/update/HttpUtils.java +6 -3
  14. package/android/src/main/java/cn/reactnative/modules/update/{NativeUpdateCore.java → NativeCore.java} +4 -4
  15. package/android/src/main/java/cn/reactnative/modules/update/PushyConfiguration.java +10 -5
  16. package/android/src/main/java/cn/reactnative/modules/update/PushyRuntime.java +4 -4
  17. package/android/src/main/java/cn/reactnative/modules/update/ReactReloadManager.java +7 -7
  18. package/android/src/main/java/cn/reactnative/modules/update/StateSerialRunner.java +1 -1
  19. package/android/src/main/java/cn/reactnative/modules/update/{NativeCheckOrchestrator.java → SyncCoordinator.java} +79 -75
  20. package/android/src/main/java/cn/reactnative/modules/update/Texts.java +28 -0
  21. package/android/src/main/java/cn/reactnative/modules/update/UiThreadRunner.java +1 -1
  22. package/android/src/main/java/cn/reactnative/modules/update/UpdateContext.java +28 -28
  23. package/android/src/main/java/cn/reactnative/modules/update/UpdateModuleImpl.java +12 -9
  24. package/cpp/patch_core/archive_limits.h +5 -0
  25. package/cpp/patch_core/archive_patch_core.cpp +26 -19
  26. package/cpp/patch_core/archive_patch_core.h +17 -8
  27. package/cpp/patch_core/digest.h +6 -1
  28. package/cpp/patch_core/error_codes.h +8 -1
  29. package/cpp/patch_core/hbc_transform.h +5 -0
  30. package/cpp/patch_core/hbc_transform_wire.h +5 -0
  31. package/cpp/patch_core/install_record.h +5 -0
  32. package/cpp/patch_core/jni_natives.h +27 -0
  33. package/cpp/patch_core/jni_registration.cpp +103 -0
  34. package/cpp/patch_core/obscured_text.h +44 -0
  35. package/cpp/patch_core/patch_core.cpp +13 -13
  36. package/cpp/patch_core/patch_core.h +11 -6
  37. package/cpp/patch_core/patch_core_android.cpp +10 -10
  38. package/cpp/patch_core/state_core.h +5 -0
  39. package/cpp/patch_core/state_ops.h +5 -0
  40. package/cpp/patch_core/update_core_android.cpp +23 -22
  41. package/cpp/update_flow_core/flow_json.h +6 -1
  42. package/cpp/update_flow_core/update_flow_core.cpp +35 -18
  43. package/cpp/update_flow_core/update_flow_core.h +13 -8
  44. package/cpp/update_flow_core/update_flow_jni.cpp +11 -13
  45. package/harmony/pushy/src/main/cpp/CMakeLists.txt +8 -8
  46. package/harmony/pushy/src/main/cpp/pushy.cpp +33 -33
  47. package/harmony/pushy/src/main/ets/ArchiveLimits.ts +15 -15
  48. package/harmony/pushy/src/main/ets/DownloadTask.ts +60 -60
  49. package/harmony/pushy/src/main/ets/ErrorCodes.ts +13 -11
  50. package/harmony/pushy/src/main/ets/InstallRecord.ts +4 -4
  51. package/harmony/pushy/src/main/ets/NativePatchCore.ts +9 -9
  52. package/harmony/pushy/src/main/ets/PathUtils.ts +2 -2
  53. package/harmony/pushy/src/main/ets/PushyConfiguration.ts +8 -6
  54. package/harmony/pushy/src/main/ets/PushyFileJSBundleProvider.ets +1 -1
  55. package/harmony/pushy/src/main/ets/PushyTurboModule.ts +42 -41
  56. package/harmony/pushy/src/main/ets/{NativeCheckOrchestrator.ts → SyncCoordinator.ts} +33 -32
  57. package/harmony/pushy/src/main/ets/Texts.ts +28 -0
  58. package/harmony/pushy/src/main/ets/UpdateContext.ts +31 -30
  59. package/harmony/pushy.har +0 -0
  60. package/ios/RCTPushy/RCTPushy.mm +148 -140
  61. package/ios/RCTPushy/RCTPushyConfiguration.h +8 -0
  62. package/ios/RCTPushy/RCTPushyConfiguration.mm +32 -5
  63. package/package.json +1 -1
  64. package/react-native-update.podspec +15 -3
  65. package/android/lib/arm64-v8a/librnupdate.so +0 -0
  66. package/android/lib/armeabi-v7a/librnupdate.so +0 -0
  67. package/android/lib/x86/librnupdate.so +0 -0
  68. package/android/lib/x86_64/librnupdate.so +0 -0
@@ -55,8 +55,8 @@ final class ReactReloadManager {
55
55
  reloadReactHost(reactHost, createBundleLoader(application, updateBundlePath, true));
56
56
  return;
57
57
  } catch (Throwable err) {
58
- Log.e(UpdateContext.TAG,
59
- "Failed to reload via ReactHost, trying ReactInstanceManager", err);
58
+ Log.e(Texts.LOG_TAG,
59
+ "Failed to restart via ReactHost, trying ReactInstanceManager", err);
60
60
  }
61
61
  }
62
62
 
@@ -123,7 +123,7 @@ final class ReactReloadManager {
123
123
  return (String) resolvedBundleAssetName;
124
124
  }
125
125
  } catch (Exception e) {
126
- Log.e(UpdateContext.TAG, "Failed to get default asset name from ReactNativeHost", e);
126
+ Log.e(Texts.LOG_TAG, "Failed to get default asset name from ReactNativeHost", e);
127
127
  }
128
128
 
129
129
  return bundleAssetName;
@@ -170,7 +170,7 @@ final class ReactReloadManager {
170
170
  }
171
171
  }
172
172
  } catch (Throwable ignored) {
173
- Log.w(UpdateContext.TAG, "getReactHost via ReactDelegate reflection failed", ignored);
173
+ Log.w(Texts.LOG_TAG, "getReactHost via ReactDelegate reflection failed", ignored);
174
174
  }
175
175
  }
176
176
 
@@ -178,7 +178,7 @@ final class ReactReloadManager {
178
178
  Method getReactHostMethod = application.getClass().getMethod("getReactHost");
179
179
  return getReactHostMethod.invoke(application);
180
180
  } catch (Throwable ignored) {
181
- Log.w(UpdateContext.TAG, "getReactHost via Application.getReactHost() failed", ignored);
181
+ Log.w(Texts.LOG_TAG, "getReactHost via Application.getReactHost() failed", ignored);
182
182
  }
183
183
 
184
184
  return null;
@@ -252,8 +252,8 @@ final class ReactReloadManager {
252
252
  jsBundleLoaderField.setAccessible(true);
253
253
  jsBundleLoaderField.set(reactHostDelegate, loader);
254
254
 
255
- Method reloadMethod = reactHost.getClass().getMethod("reload", String.class);
256
- reloadMethod.invoke(reactHost, "react-native-update");
255
+ Method reloadMethod = reactHost.getClass().getMethod(Texts.reveal("2812f8deaf8f"), String.class);
256
+ reloadMethod.invoke(reactHost, Texts.LOG_TAG);
257
257
  }
258
258
 
259
259
  private static ReactInstanceManager resolveReactInstanceManager(
@@ -56,7 +56,7 @@ final class StateSerialRunner {
56
56
  if (promise != null) {
57
57
  promise.reject(errorCode, operationName + " failed", error);
58
58
  } else {
59
- Log.e(UpdateContext.TAG, operationName + " failed", error);
59
+ Log.e(Texts.LOG_TAG, operationName + " failed", error);
60
60
  }
61
61
  }
62
62
  }
@@ -26,11 +26,15 @@ import org.json.JSONObject;
26
26
  * process, a few seconds after getBundleUrl, entirely independent of the app
27
27
  * bundle — this is what lets a device bricked by a bad hot update pull the
28
28
  * fixed version on the next launch. All decisions come from
29
- * cpp/update_flow_core via NativeUpdateFlow; this class is IO glue only.
29
+ * cpp/update_flow_core via FlowBridge; this class is IO glue only.
30
30
  * Failures are silent and bounded: one round per launch, no retry storms, no
31
31
  * version blacklisting.
32
32
  */
33
- final class NativeCheckOrchestrator {
33
+ final class SyncCoordinator {
34
+ // Version-info flags read by JS (metadata.ts), stored encoded.
35
+ private static final String INFO_CRASH_HOLD = Texts.reveal("3905f5c2a6b96d56212a19");
36
+ private static final String INFO_FORCE_BOOT = Texts.reveal("3c18e6d2aba9674a360d19ead5a695");
37
+
34
38
  static final String KEY_CONFIG = "nativeConfig";
35
39
  // Raw response cache for the JS side to reuse (§10.3), scoped to the
36
40
  // exact logical request and native config that produced it.
@@ -39,11 +43,11 @@ final class NativeCheckOrchestrator {
39
43
  // next launch means the previous process died mid-round (a crash rescue
40
44
  // was truncated): that launch resumes immediately instead of waiting 5s.
41
45
  static final String KEY_ROUND_INCOMPLETE = "nativeCheckIncomplete";
42
- private static final int MAX_CHECK_HTTP_ATTEMPTS = 8;
46
+ private static final int MAX_QUERY_HTTP_ATTEMPTS = 8;
43
47
  private static final long DOWNLOAD_PHASE_TIMEOUT_SECONDS = 600;
44
48
  // The check response (and a remote queryUrls list) is a small JSON
45
49
  // document; anything bigger is a broken or hijacked endpoint.
46
- private static final long MAX_CHECK_RESPONSE_BYTES = 1024 * 1024;
50
+ private static final long MAX_QUERY_RESPONSE_BYTES = 1024 * 1024;
47
51
 
48
52
  private static final AtomicBoolean scheduled = new AtomicBoolean(false);
49
53
  // One round per process, whoever starts it first — the delayed cold-start
@@ -55,7 +59,7 @@ final class NativeCheckOrchestrator {
55
59
  // Flipped the moment a crash is being held. JS is dead from that point
56
60
  // on, so there is no second decision maker: the round force-activates
57
61
  // whatever it downloads (§11.3).
58
- private static volatile boolean crashRescueActive = false;
62
+ private static volatile boolean crashHoldActive = false;
59
63
  // A version this process downloaded but left for JS to activate. If the
60
64
  // process then crashes, JS will never activate it — the crash handler
61
65
  // activates it directly (bounded local work, no network). The generation
@@ -118,7 +122,7 @@ final class NativeCheckOrchestrator {
118
122
  }
119
123
 
120
124
 
121
- static void markJsCheckCompleted(String config) {
125
+ static void recordJsRound(String config) {
122
126
  sJsCompletedConfig = config;
123
127
  }
124
128
 
@@ -128,12 +132,12 @@ final class NativeCheckOrchestrator {
128
132
  * duplicate request. Only the scheduled round consults this — the
129
133
  * crash-rescue path still runs, JS is dead by then.
130
134
  */
131
- private static boolean isJsCheckCompleted(UpdateContext context) {
135
+ private static boolean hasJsRound(UpdateContext context) {
132
136
  String jsConfig = sJsCompletedConfig;
133
137
  return jsConfig != null && jsConfig.equals(context.getKv(KEY_CONFIG));
134
138
  }
135
139
 
136
- private NativeCheckOrchestrator() {
140
+ private SyncCoordinator() {
137
141
  }
138
142
 
139
143
  static void schedule(final UpdateContext context, final String launchRolledBackVersion) {
@@ -149,7 +153,7 @@ final class NativeCheckOrchestrator {
149
153
  // The crash-hold rescue shares the orchestrator's rollout gate: no
150
154
  // persisted config, no handler (§11.3).
151
155
  if (context.getKv(KEY_CONFIG) != null) {
152
- CrashRescue.install();
156
+ CrashHold.install();
153
157
  }
154
158
  Thread thread = new Thread(new Runnable() {
155
159
  @Override
@@ -161,20 +165,20 @@ final class NativeCheckOrchestrator {
161
165
  if (context.getKv(KEY_ROUND_INCOMPLETE) == null) {
162
166
  Thread.sleep(5000);
163
167
  }
164
- if (isJsCheckCompleted(context)) {
168
+ if (hasJsRound(context)) {
165
169
  // Not consuming the round: a later crash rescue may
166
170
  // still need it.
167
- Log.i(UpdateContext.TAG,
168
- "native check skipped: JS check completed in this process");
171
+ Log.i(Texts.LOG_TAG,
172
+ "native sync skipped: JS already queried in this process");
169
173
  return;
170
174
  }
171
175
  startRound(0);
172
176
  } catch (Throwable e) {
173
177
  // The rescue path must never take the app down with it.
174
- Log.w(UpdateContext.TAG, "native check failed: " + e);
178
+ Log.w(Texts.LOG_TAG, "native sync failed: " + e);
175
179
  }
176
180
  }
177
- }, "pushy-native-check");
181
+ }, "pushy-native-sync");
178
182
  thread.setPriority(Thread.MIN_PRIORITY + 1);
179
183
  thread.setDaemon(true);
180
184
  thread.start();
@@ -209,7 +213,7 @@ final class NativeCheckOrchestrator {
209
213
 
210
214
  static void onConfigured(UpdateContext context) {
211
215
  if (nativeReady && sContext == context && hasRunnableConfig(context)) {
212
- CrashRescue.install();
216
+ CrashHold.install();
213
217
  }
214
218
  }
215
219
 
@@ -225,7 +229,7 @@ final class NativeCheckOrchestrator {
225
229
  try {
226
230
  runOnce(sContext, sLaunchRolledBackVersion, deadlineNanos);
227
231
  } catch (Throwable e) {
228
- Log.w(UpdateContext.TAG, "native check failed: " + e);
232
+ Log.w(Texts.LOG_TAG, "native sync failed: " + e);
229
233
  roundResult = BundlePreparationResult.of(BundlePreparationResult.FAILED, "internal_error");
230
234
  } finally {
231
235
  roundCompleted = true;
@@ -240,12 +244,12 @@ final class NativeCheckOrchestrator {
240
244
  * activates a downloaded-but-unactivated version if one exists — the
241
245
  * last chance before the process is gone.
242
246
  */
243
- static void runRescue(long deadlineNanos) {
247
+ static void runHoldRound(long deadlineNanos) {
244
248
  UpdateContext context = sContext;
245
249
  if (context == null) {
246
250
  return;
247
251
  }
248
- crashRescueActive = true;
252
+ crashHoldActive = true;
249
253
  startRound(deadlineNanos);
250
254
  if (roundStarted.get() && !roundCompleted) {
251
255
  long remainingNanos = deadlineNanos - System.nanoTime();
@@ -275,23 +279,23 @@ final class NativeCheckOrchestrator {
275
279
  if (existingInfo != null) {
276
280
  try {
277
281
  JSONObject info = new JSONObject(existingInfo);
278
- info.put("crashRescue", true);
282
+ info.put(INFO_CRASH_HOLD, true);
279
283
  hashInfoJson = info.toString();
280
284
  } catch (JSONException ignored) {
281
285
  }
282
286
  }
283
287
  try {
284
- if (context.commitNativeCheckResult(
288
+ if (context.commitSyncResult(
285
289
  unactivatedGeneration, hash, hashInfoJson, true, null)) {
286
290
  unactivatedHash = null;
287
- Log.i(UpdateContext.TAG,
288
- "crash rescue: activated downloaded version " + hash);
291
+ Log.i(Texts.LOG_TAG,
292
+ "crash hold: activated downloaded version " + hash);
289
293
  } else {
290
- Log.i(UpdateContext.TAG,
291
- "crash rescue: reset since download, dropping activation");
294
+ Log.i(Texts.LOG_TAG,
295
+ "crash hold: reset since download, dropping activation");
292
296
  }
293
297
  } catch (Exception e) {
294
- Log.w(UpdateContext.TAG, "crash rescue: activation failed: " + e);
298
+ Log.w(Texts.LOG_TAG, "crash hold: activation failed: " + e);
295
299
  }
296
300
  }
297
301
 
@@ -396,26 +400,26 @@ final class NativeCheckOrchestrator {
396
400
  );
397
401
  input.put("buildTime", context.getBuildTime());
398
402
  input.put("cInfo", cInfo);
399
- input.put("supportedDiffVersion", NativeUpdateCore.supportedDiffVersion());
403
+ input.put("supportedDiffVersion", NativeCore.supportedDiffVersion());
400
404
  input.put("bundleHash", context.computeBundleHash());
401
405
 
402
- String body = NativeUpdateFlow.buildCheckRequestBody(input.toString());
406
+ String body = FlowBridge.buildRequestBody(input.toString());
403
407
  if (body == null) {
404
408
  roundResult = BundlePreparationResult.of(BundlePreparationResult.FAILED, "invalid_request");
405
409
  return;
406
410
  }
407
411
 
408
- String responseText = runCheckRequest(config, appKey, body, deadlineNanos);
412
+ String responseText = runQueryRequest(config, appKey, body, deadlineNanos);
409
413
  if (responseText == null) {
410
- Log.i(UpdateContext.TAG,
411
- "native check: no endpoint reachable, giving up until next launch");
414
+ Log.i(Texts.LOG_TAG,
415
+ "native sync: no endpoint reachable, giving up until next launch");
412
416
  return;
413
417
  }
414
418
  // Cache freshness is anchored to when the server response arrived,
415
419
  // not to when a potentially long download/patch/activation finished.
416
420
  final long responseAtSeconds = System.currentTimeMillis() / 1000;
417
421
 
418
- String decisionJson = NativeUpdateFlow.handleCheckResponse(
422
+ String decisionJson = FlowBridge.handleResponse(
419
423
  responseText, identity.toString(), config.optString("afterDownload", ""));
420
424
  if (decisionJson == null) {
421
425
  roundResult = BundlePreparationResult.of(BundlePreparationResult.FAILED, "invalid_response");
@@ -423,14 +427,14 @@ final class NativeCheckOrchestrator {
423
427
  }
424
428
  JSONObject decision = new JSONObject(decisionJson);
425
429
  if (!"download".equals(decision.optString("action"))) {
426
- boolean committed = context.commitNativeCheckResult(
430
+ boolean committed = context.commitSyncResult(
427
431
  resetGeneration, null, null, false,
428
432
  buildResponseCacheJson(configJson, body, responseText, responseAtSeconds));
429
433
  roundResult = committed
430
434
  ? BundlePreparationResult.of(BundlePreparationResult.NO_UPDATE, decision.optString("reason"))
431
435
  : BundlePreparationResult.of(BundlePreparationResult.CANCELLED, "reset");
432
- Log.i(UpdateContext.TAG,
433
- "native check: nothing to do (" + decision.optString("reason") + ")");
436
+ Log.i(Texts.LOG_TAG,
437
+ "native sync: nothing to do (" + decision.optString("reason") + ")");
434
438
  return;
435
439
  }
436
440
  String hash = decision.optString("hash", "");
@@ -448,7 +452,7 @@ final class NativeCheckOrchestrator {
448
452
  if (!downloaded) {
449
453
  // The native attempt has finished, so JS may safely reuse the
450
454
  // response and retry through its own strategy chain.
451
- boolean committed = context.commitNativeCheckResult(
455
+ boolean committed = context.commitSyncResult(
452
456
  resetGeneration, null, null, false,
453
457
  buildResponseCacheJson(configJson, body, responseText, responseAtSeconds));
454
458
  roundResult = BundlePreparationResult.of(
@@ -459,7 +463,7 @@ final class NativeCheckOrchestrator {
459
463
 
460
464
  // Version info (mirroring the JS side's setLocalHashInfo), the
461
465
  // activation and the response cache all land in one atomic commit —
462
- // see UpdateContext.commitNativeCheckResult.
466
+ // see UpdateContext.commitSyncResult.
463
467
  String hashInfoJson = null;
464
468
  JSONObject info = decision.optJSONObject("info");
465
469
  if (info != null) {
@@ -476,10 +480,10 @@ final class NativeCheckOrchestrator {
476
480
  // counts — a silent-strategy activation is ordinary delivery.
477
481
  JSONObject infoConfig = info.optJSONObject("config");
478
482
  if (infoConfig != null && infoConfig.optBoolean("forceBoot", false)) {
479
- hashInfo.put("forceBootRescue", true);
483
+ hashInfo.put(INFO_FORCE_BOOT, true);
480
484
  }
481
- if (crashRescueActive) {
482
- hashInfo.put("crashRescue", true);
485
+ if (crashHoldActive) {
486
+ hashInfo.put(INFO_CRASH_HOLD, true);
483
487
  }
484
488
  hashInfoJson = hashInfo.toString();
485
489
  }
@@ -488,33 +492,33 @@ final class NativeCheckOrchestrator {
488
492
  // otherwise activation stays with the JS side. Unless a crash is
489
493
  // being held: JS is dead, deferring to it would leave the fix on
490
494
  // disk forever (§11.3).
491
- boolean activate = decision.optBoolean("activate", false) || crashRescueActive;
495
+ boolean activate = decision.optBoolean("activate", false) || crashHoldActive;
492
496
  boolean committed;
493
497
  try {
494
- committed = context.commitNativeCheckResult(
498
+ committed = context.commitSyncResult(
495
499
  resetGeneration,
496
500
  hash,
497
501
  hashInfoJson,
498
502
  activate,
499
503
  buildResponseCacheJson(configJson, body, responseText, responseAtSeconds));
500
504
  } catch (Exception e) {
501
- Log.w(UpdateContext.TAG, "native check: commit failed: " + e);
505
+ Log.w(Texts.LOG_TAG, "native sync: commit failed: " + e);
502
506
  roundResult = BundlePreparationResult.of(BundlePreparationResult.FAILED, "commit_failed");
503
507
  return;
504
508
  }
505
509
  if (!committed) {
506
- Log.i(UpdateContext.TAG, "native check: reset during round, dropping result");
510
+ Log.i(Texts.LOG_TAG, "native sync: reset during round, dropping result");
507
511
  } else if (activate) {
508
512
  unactivatedHash = null;
509
- Log.i(UpdateContext.TAG,
510
- "native check: downloaded " + hash + " and set for next launch");
513
+ Log.i(Texts.LOG_TAG,
514
+ "native sync: downloaded " + hash + " and set for next launch");
511
515
  } else {
512
516
  // Remembered so a crash later in this process can still activate
513
517
  // it (activatePendingVersion) — JS never will.
514
518
  unactivatedGeneration = resetGeneration;
515
519
  unactivatedHash = hash;
516
- Log.i(UpdateContext.TAG,
517
- "native check: downloaded " + hash + ", activation left to JS");
520
+ Log.i(Texts.LOG_TAG,
521
+ "native sync: downloaded " + hash + ", activation left to JS");
518
522
  }
519
523
  roundResult = committed
520
524
  ? BundlePreparationResult.downloaded(hash, activate)
@@ -577,7 +581,7 @@ final class NativeCheckOrchestrator {
577
581
  } catch (Exception e) {
578
582
  // One line per failed endpoint; the fallback chain is otherwise
579
583
  // invisible in the field.
580
- Log.w(UpdateContext.TAG, "native check: request failed with "
584
+ Log.w(Texts.LOG_TAG, "native sync: request failed with "
581
585
  + e.getClass().getName() + ": " + e.getMessage());
582
586
  return null;
583
587
  }
@@ -590,13 +594,13 @@ final class NativeCheckOrchestrator {
590
594
  */
591
595
  @Nullable
592
596
  private static String readBoundedBody(ResponseBody body) throws IOException {
593
- if (body.contentLength() > MAX_CHECK_RESPONSE_BYTES) {
597
+ if (body.contentLength() > MAX_QUERY_RESPONSE_BYTES) {
594
598
  return null;
595
599
  }
596
600
  BufferedSource source = body.source();
597
- if (source.request(MAX_CHECK_RESPONSE_BYTES + 1)) {
598
- Log.w(UpdateContext.TAG, "native check: response exceeds "
599
- + MAX_CHECK_RESPONSE_BYTES + " bytes, ignoring endpoint");
601
+ if (source.request(MAX_QUERY_RESPONSE_BYTES + 1)) {
602
+ Log.w(Texts.LOG_TAG, "native sync: response exceeds "
603
+ + MAX_QUERY_RESPONSE_BYTES + " bytes, ignoring endpoint");
600
604
  return null;
601
605
  }
602
606
  MediaType contentType = body.contentType();
@@ -605,11 +609,11 @@ final class NativeCheckOrchestrator {
605
609
  return source.readString(charset == null ? StandardCharsets.UTF_8 : charset);
606
610
  }
607
611
 
608
- // Shared schema rule (update_flow_core::IsValidCheckResponse): a 200 with
612
+ // Shared schema rule (update_flow_core::IsValidResponse): a 200 with
609
613
  // `{"error": ...}` is a failed endpoint, not a verdict, and must not stop
610
614
  // the endpoint fallback.
611
- private static boolean isValidCheckResponse(String responseText) {
612
- return responseText != null && NativeUpdateFlow.isValidCheckResponse(responseText);
615
+ private static boolean isValidResponse(String responseText) {
616
+ return responseText != null && FlowBridge.isValidResponse(responseText);
613
617
  }
614
618
 
615
619
  /**
@@ -619,11 +623,11 @@ final class NativeCheckOrchestrator {
619
623
  * already-tried) for one more round. No hedged race on purpose — this
620
624
  * path is latency-insensitive.
621
625
  */
622
- private static String runCheckRequest(
626
+ private static String runQueryRequest(
623
627
  JSONObject config, String appKey, String body, long deadlineNanos
624
628
  ) {
625
629
  JSONArray endpoints = config.optJSONArray("endpoints");
626
- String orderedJson = NativeUpdateFlow.orderEndpointCandidates(
630
+ String orderedJson = FlowBridge.orderEndpointCandidates(
627
631
  endpoints == null ? "[]" : endpoints.toString(), Math.random());
628
632
  JSONArray ordered;
629
633
  try {
@@ -638,12 +642,12 @@ final class NativeCheckOrchestrator {
638
642
  if (base.isEmpty() || !tried.add(base)) {
639
643
  continue;
640
644
  }
641
- if (httpAttempts++ >= MAX_CHECK_HTTP_ATTEMPTS) {
645
+ if (httpAttempts++ >= MAX_QUERY_HTTP_ATTEMPTS) {
642
646
  return null;
643
647
  }
644
648
  String response = httpRequest(
645
- base + "/checkUpdate/" + appKey, body, deadlineNanos);
646
- if (isValidCheckResponse(response)) {
649
+ base + HttpUtils.QUERY_PATH + appKey, body, deadlineNanos);
650
+ if (isValidResponse(response)) {
647
651
  return response;
648
652
  }
649
653
  }
@@ -656,7 +660,7 @@ final class NativeCheckOrchestrator {
656
660
  if (listUrl.isEmpty()) {
657
661
  continue;
658
662
  }
659
- if (httpAttempts++ >= MAX_CHECK_HTTP_ATTEMPTS) {
663
+ if (httpAttempts++ >= MAX_QUERY_HTTP_ATTEMPTS) {
660
664
  return null;
661
665
  }
662
666
  String listText = httpRequest(listUrl, null, deadlineNanos);
@@ -674,13 +678,13 @@ final class NativeCheckOrchestrator {
674
678
  if (base.isEmpty() || tried.contains(base)) {
675
679
  continue;
676
680
  }
677
- if (httpAttempts++ >= MAX_CHECK_HTTP_ATTEMPTS) {
681
+ if (httpAttempts++ >= MAX_QUERY_HTTP_ATTEMPTS) {
678
682
  return null;
679
683
  }
680
684
  tried.add(base);
681
685
  String response = httpRequest(
682
- base + "/checkUpdate/" + appKey, body, deadlineNanos);
683
- if (isValidCheckResponse(response)) {
686
+ base + HttpUtils.QUERY_PATH + appKey, body, deadlineNanos);
687
+ if (isValidResponse(response)) {
684
688
  return response;
685
689
  }
686
690
  }
@@ -690,23 +694,23 @@ final class NativeCheckOrchestrator {
690
694
  return null;
691
695
  }
692
696
 
693
- private static long capToRescueBudget(long phaseDeadlineNanos, long rescueDeadlineNanos) {
694
- if (rescueDeadlineNanos <= 0) {
697
+ private static long capToHoldBudget(long phaseDeadlineNanos, long holdDeadlineNanos) {
698
+ if (holdDeadlineNanos <= 0) {
695
699
  return phaseDeadlineNanos;
696
700
  }
697
- return Math.min(phaseDeadlineNanos, rescueDeadlineNanos);
701
+ return Math.min(phaseDeadlineNanos, holdDeadlineNanos);
698
702
  }
699
703
 
700
704
  private static boolean performAttempts(
701
705
  UpdateContext context, JSONArray attempts, String hash, String originHash,
702
- long rescueDeadlineNanos
706
+ long holdDeadlineNanos
703
707
  ) {
704
708
  if (attempts == null) {
705
709
  return false;
706
710
  }
707
- final long incrementalDeadlineNanos = capToRescueBudget(
711
+ final long incrementalDeadlineNanos = capToHoldBudget(
708
712
  System.nanoTime() + TimeUnit.SECONDS.toNanos(DOWNLOAD_PHASE_TIMEOUT_SECONDS),
709
- rescueDeadlineNanos);
713
+ holdDeadlineNanos);
710
714
  long fullDeadlineNanos = 0;
711
715
  for (int i = 0; i < attempts.length(); i++) {
712
716
  JSONObject attempt = attempts.optJSONObject(i);
@@ -722,10 +726,10 @@ final class NativeCheckOrchestrator {
722
726
  if (isFullAttempt && fullDeadlineNanos == 0) {
723
727
  // Incremental failures must not consume the last-resort full
724
728
  // download's budget. Each phase gets one bounded 10min window.
725
- fullDeadlineNanos = capToRescueBudget(
729
+ fullDeadlineNanos = capToHoldBudget(
726
730
  System.nanoTime()
727
731
  + TimeUnit.SECONDS.toNanos(DOWNLOAD_PHASE_TIMEOUT_SECONDS),
728
- rescueDeadlineNanos);
732
+ holdDeadlineNanos);
729
733
  }
730
734
  final long deadlineNanos = isFullAttempt
731
735
  ? fullDeadlineNanos : incrementalDeadlineNanos;
@@ -760,7 +764,7 @@ final class NativeCheckOrchestrator {
760
764
 
761
765
  @Override
762
766
  public void onDownloadFailed(Throwable error) {
763
- Log.i(UpdateContext.TAG, "native check: " + attemptType
767
+ Log.i(Texts.LOG_TAG, "native sync: " + attemptType
764
768
  + " attempt failed: " + error);
765
769
  latch.countDown();
766
770
  }
@@ -778,8 +782,8 @@ final class NativeCheckOrchestrator {
778
782
  }
779
783
  try {
780
784
  if (!latch.await(remainingNanos, TimeUnit.NANOSECONDS)) {
781
- Log.w(UpdateContext.TAG,
782
- "native check: download phase timed out during " + type);
785
+ Log.w(Texts.LOG_TAG,
786
+ "native sync: download phase timed out during " + type);
783
787
  // The task shares one download thread with the next
784
788
  // attempt: cancel its transfer (or keep it from
785
789
  // starting) instead of queueing behind it
@@ -0,0 +1,28 @@
1
+ package cn.reactnative.modules.update;
2
+
3
+ /**
4
+ * Encoded text helpers with no Android or native dependencies, so any class
5
+ * (and the plain-JVM unit tests) can use them without triggering
6
+ * UpdateContext's native library load.
7
+ */
8
+ final class Texts {
9
+ /** Log tag shared by the module. */
10
+ static final String LOG_TAG = reveal("2812f5d2bac6664436360afc9ba680694b3301");
11
+
12
+ private Texts() {
13
+ }
14
+
15
+ /**
16
+ * Decodes text produced by scripts/encode-native-text.ts: byte i is XORed
17
+ * with (0x5A + 0x1D * i) & 0xFF. Keeps service addresses and paths out of
18
+ * static string scans of the binary; it is not a secret.
19
+ */
20
+ static String reveal(String hex) {
21
+ char[] out = new char[hex.length() / 2];
22
+ for (int i = 0; i < out.length; i++) {
23
+ int b = Integer.parseInt(hex.substring(i * 2, i * 2 + 2), 16);
24
+ out[i] = (char) (b ^ ((0x5A + 0x1D * i) & 0xFF));
25
+ }
26
+ return new String(out);
27
+ }
28
+ }
@@ -28,7 +28,7 @@ final class UiThreadRunner {
28
28
  if (promise != null) {
29
29
  promise.reject(errorCode, operationName + " failed", error);
30
30
  } else {
31
- Log.e(UpdateContext.TAG, operationName + " failed", error);
31
+ Log.e(Texts.LOG_TAG, operationName + " failed", error);
32
32
  }
33
33
  }
34
34
  }