react-native-update 10.42.7 → 10.42.9

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.
@@ -12,7 +12,7 @@ export class PushyFileJSBundleProvider extends JSBundleProvider {
12
12
 
13
13
  constructor(context: common.UIAbilityContext) {
14
14
  super();
15
- this.updateContext = new UpdateContext(context);
15
+ this.updateContext = UpdateContext.getInstance(context);
16
16
  }
17
17
 
18
18
  getURL(): string {
@@ -38,7 +38,7 @@ export class PushyTurboModule extends UITurboModule {
38
38
  super(ctx);
39
39
  logger.debug(TAG, ',PushyTurboModule constructor');
40
40
  this.mUiCtx = ctx.uiAbilityContext;
41
- this.context = new UpdateContext(this.mUiCtx);
41
+ this.context = UpdateContext.getInstance(this.mUiCtx);
42
42
  EventHub.getInstance().setRNInstance(ctx.rnInstance);
43
43
  }
44
44
 
@@ -78,6 +78,7 @@ export class PushyTurboModule extends UITurboModule {
78
78
 
79
79
  getConstants(): Object {
80
80
  logger.debug(TAG, ',call getConstants');
81
+ this.context.logStateSnapshot('getConstants:enter');
81
82
  const packageVersion = this.context.getPackageVersion();
82
83
  const buildTime = this.context.getBuildTime();
83
84
  this.context.syncStateWithBinaryVersion(packageVersion, buildTime);
@@ -95,7 +96,7 @@ export class PushyTurboModule extends UITurboModule {
95
96
  this.context.clearRollbackMark();
96
97
  }
97
98
 
98
- return {
99
+ const result = {
99
100
  downloadRootDir: `${this.mUiCtx.filesDir}/_update`,
100
101
  currentVersionInfo,
101
102
  packageVersion,
@@ -106,6 +107,19 @@ export class PushyTurboModule extends UITurboModule {
106
107
  rolledBackVersion,
107
108
  uuid,
108
109
  };
110
+ const logResult = {
111
+ downloadRootDir: result.downloadRootDir,
112
+ currentVersionInfo: result.currentVersionInfo,
113
+ packageVersion: result.packageVersion,
114
+ currentVersion: result.currentVersion,
115
+ buildTime: result.buildTime,
116
+ isUsingBundleUrl: result.isUsingBundleUrl,
117
+ isFirstTime: result.isFirstTime,
118
+ rolledBackVersion: result.rolledBackVersion,
119
+ uuidSet: !!result.uuid,
120
+ };
121
+ logger.info(TAG, `,getConstants result: ${JSON.stringify(logResult)}`);
122
+ return result;
109
123
  }
110
124
 
111
125
  setLocalHashInfo(hash: string, info: string): boolean {
@@ -5,6 +5,7 @@ import common from '@ohos.app.ability.common';
5
5
  import { DownloadTaskParams } from './DownloadTaskParams';
6
6
  import { bundleManager } from '@kit.AbilityKit';
7
7
  import { util } from '@kit.ArkTS';
8
+ import logger from './Logger';
8
9
  import NativePatchCore, {
9
10
  STATE_OP_CLEAR_FIRST_TIME,
10
11
  STATE_OP_CLEAR_ROLLBACK_MARK,
@@ -28,10 +29,23 @@ export class UpdateContext {
28
29
  private static ignoreRollback: boolean = false;
29
30
  private static cachedPackageVersion: string = '';
30
31
  private static cachedBuildTime: string = '';
32
+ // 单例:确保 bundle provider 与 TurboModule 共用同一份 preferences 内存状态,
33
+ // 避免 RNOH RN 实例重建后两处 UpdateContext 各自持有 preferences 缓存导致读写分裂。
34
+ private static instance: UpdateContext | null = null;
35
+ private static instanceCounter: number = 0;
36
+ private readonly instanceId: string;
37
+
38
+ public static getInstance(context: common.UIAbilityContext): UpdateContext {
39
+ if (!UpdateContext.instance) {
40
+ UpdateContext.instance = new UpdateContext(context);
41
+ }
42
+ return UpdateContext.instance;
43
+ }
31
44
 
32
- constructor(context: common.UIAbilityContext) {
45
+ private constructor(context: common.UIAbilityContext) {
33
46
  this.context = context;
34
47
  this.rootDir = context.filesDir + '/_update';
48
+ this.instanceId = `uc#${++UpdateContext.instanceCounter}`;
35
49
 
36
50
  try {
37
51
  if (!fileIo.accessSync(this.rootDir)) {
@@ -41,12 +55,36 @@ export class UpdateContext {
41
55
  console.error('Failed to create root directory:', e);
42
56
  }
43
57
  this.initPreferences();
58
+ this.trace('ctor');
44
59
  this.syncStateWithBinaryVersion(
45
60
  this.getPackageVersion(),
46
61
  this.getBuildTime(),
47
62
  );
48
63
  }
49
64
 
65
+ /**
66
+ * 诊断日志:打印本实例 id 与关键状态,用于定位 preferences 多实例 / 状态分裂问题。
67
+ * 通过 hilog 输出,prefix=pushy,可在 hilog 中按 "UpdateContext" 过滤。
68
+ */
69
+ private trace(point: string): void {
70
+ const snap = this.getStateSnapshot();
71
+ logger.info(
72
+ 'UpdateContext',
73
+ `trace id=${this.instanceId} ${point}` +
74
+ ` pkg=${snap.packageVersion} bt=${snap.buildTime}` +
75
+ ` cv=${snap.currentVersion} lv=${snap.lastVersion}` +
76
+ ` ft=${snap.firstTime} fto=${snap.firstTimeOk}` +
77
+ ` rb=${snap.rolledBackVersion}` +
78
+ ` flm=${this.readString('firstLoadMarked')}` +
79
+ ` uuidSet=${!!this.readString('uuid')}`,
80
+ );
81
+ }
82
+
83
+ /** 对外诊断入口,供 TurboModule 在 getConstants 等关键节点打印状态。 */
84
+ public logStateSnapshot(point: string): void {
85
+ this.trace(point);
86
+ }
87
+
50
88
  private initPreferences() {
51
89
  try {
52
90
  this.preferences = preferences.getPreferencesSync(this.context, {
@@ -269,9 +307,17 @@ export class UpdateContext {
269
307
  return;
270
308
  }
271
309
 
310
+ logger.info(
311
+ 'UpdateContext',
312
+ `binary version changed, resetting update state id=${this.instanceId}`,
313
+ );
272
314
  UpdateContext.ignoreRollback = false;
273
315
  this.cleanUp();
274
- this.persistState(nextState, { clearExisting: true });
316
+ // 仅重置状态机字段(currentVersion / lastVersion / firstTime / firstTimeOk /
317
+ // rolledBackVersion)。不再 clearExisting,避免连带清除 uuid / firstLoadMarked /
318
+ // hash_* 等与 binary 版本无关的 KV —— 它们在多实例场景下本就脆弱,连带清除会
319
+ // 让 getConstants() 永远读到空,从而 isFirstTime=false、markSuccess 永不执行。
320
+ this.persistState(nextState);
275
321
  }
276
322
 
277
323
  public setKv(key: string, value: string): void {
@@ -388,8 +434,10 @@ export class UpdateContext {
388
434
  throw Error(`Bundle version ${hash} not found.`);
389
435
  }
390
436
 
437
+ this.trace(`switchVersion:before ${hash}`);
391
438
  this.runStateOperation(STATE_OP_SWITCH_VERSION, hash);
392
439
  UpdateContext.ignoreRollback = false;
440
+ this.trace(`switchVersion:after ${hash}`);
393
441
  } catch (e) {
394
442
  console.error('Failed to switch version:', e);
395
443
  throw e;
@@ -398,6 +446,7 @@ export class UpdateContext {
398
446
 
399
447
  public consumeFirstLoadMarker(): boolean {
400
448
  const marked = this.readString('firstLoadMarked') === 'true';
449
+ this.trace(`consumeFirstLoadMarker:marked=${marked}`);
401
450
  if (marked) {
402
451
  this.preferences.deleteSync('firstLoadMarked');
403
452
  this.flushPreferences('clear first load marker');
@@ -407,6 +456,7 @@ export class UpdateContext {
407
456
 
408
457
  public getBundleUrl() {
409
458
  UpdateContext.isUsingBundleUrl = true;
459
+ this.trace('getBundleUrl:enter');
410
460
  const launchState = NativePatchCore.runStateCore(
411
461
  STATE_OP_RESOLVE_LAUNCH,
412
462
  this.getStateSnapshot(),
@@ -422,6 +472,11 @@ export class UpdateContext {
422
472
  if (launchState.consumedFirstTime) {
423
473
  UpdateContext.ignoreRollback = true;
424
474
  }
475
+ this.trace(
476
+ `getBundleUrl:load=${launchState.loadVersion}` +
477
+ ` consumed=${launchState.consumedFirstTime}` +
478
+ ` rollback=${launchState.didRollback}`,
479
+ );
425
480
 
426
481
  let version = launchState.loadVersion || '';
427
482
  while (version) {
@@ -442,7 +497,9 @@ export class UpdateContext {
442
497
  }
443
498
 
444
499
  public getCurrentVersion(): string {
445
- return this.getStateSnapshot().currentVersion || '';
500
+ const cv = this.getStateSnapshot().currentVersion || '';
501
+ this.trace(`getCurrentVersion:${cv}`);
502
+ return cv;
446
503
  }
447
504
 
448
505
  private rollBack(): string {
package/harmony/pushy.har CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-update",
3
- "version": "10.42.7",
3
+ "version": "10.42.9",
4
4
  "description": "react-native hot update",
5
5
  "main": "src/index",
6
6
  "scripts": {