react-native-update 10.38.0-beta.1 → 10.38.0-beta.3

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.
@@ -26,12 +26,14 @@ public class UpdateContext {
26
26
  public static boolean DEBUG = true;
27
27
  private static ReactInstanceManager mReactInstanceManager;
28
28
  private static boolean isUsingBundleUrl = false;
29
+ private static boolean ignoreRollback = false;
29
30
  private static final int STATE_OP_SWITCH_VERSION = 1;
30
31
  private static final int STATE_OP_MARK_SUCCESS = 2;
31
32
  private static final int STATE_OP_ROLLBACK = 3;
32
33
  private static final int STATE_OP_CLEAR_FIRST_TIME = 4;
33
34
  private static final int STATE_OP_CLEAR_ROLLBACK_MARK = 5;
34
35
  private static final int STATE_OP_RESOLVE_LAUNCH = 6;
36
+ private static final String KEY_FIRST_LOAD_MARKED = "firstLoadMarked";
35
37
 
36
38
  // Singleton instance
37
39
  private static UpdateContext sInstance;
@@ -77,7 +79,7 @@ public class UpdateContext {
77
79
  SharedPreferences.Editor editor = this.sp.edit();
78
80
  editor.clear();
79
81
  applyState(editor, nextState);
80
- editor.apply();
82
+ persistEditor(editor, "sync state with binary version");
81
83
  }
82
84
  }
83
85
 
@@ -199,6 +201,12 @@ public class UpdateContext {
199
201
  putNullableString(editor, "rolledBackVersion", state.rolledBackVersion);
200
202
  }
201
203
 
204
+ private void persistEditor(SharedPreferences.Editor editor, String reason) {
205
+ if (!editor.commit() && DEBUG) {
206
+ Log.w("react-native-update", "Failed to persist update state for " + reason);
207
+ }
208
+ }
209
+
202
210
  public void switchVersion(String hash) {
203
211
  if (!new File(rootDir, hash+"/index.bundlejs").exists()) {
204
212
  throw new Error("Bundle version " + hash + " not found.");
@@ -214,13 +222,14 @@ public class UpdateContext {
214
222
  );
215
223
  SharedPreferences.Editor editor = sp.edit();
216
224
  applyState(editor, nextState);
217
- editor.apply();
225
+ persistEditor(editor, "switch version");
226
+ ignoreRollback = false;
218
227
  }
219
228
 
220
229
  public void setKv(String key, String value) {
221
230
  SharedPreferences.Editor editor = sp.edit();
222
231
  editor.putString(key, value);
223
- editor.apply();
232
+ persistEditor(editor, "set key " + key);
224
233
  }
225
234
 
226
235
  public String getKv(String key) {
@@ -235,6 +244,16 @@ public class UpdateContext {
235
244
  return sp.getBoolean("firstTime", false);
236
245
  }
237
246
 
247
+ public boolean consumeFirstLoadMarker() {
248
+ boolean isFirstLoadMarked = sp.getBoolean(KEY_FIRST_LOAD_MARKED, false);
249
+ if (isFirstLoadMarked) {
250
+ SharedPreferences.Editor editor = sp.edit();
251
+ editor.remove(KEY_FIRST_LOAD_MARKED);
252
+ persistEditor(editor, "clear first load marker");
253
+ }
254
+ return isFirstLoadMarked;
255
+ }
256
+
238
257
  public String rolledBackVersion() {
239
258
  return sp.getString("rolledBackVersion", null);
240
259
  }
@@ -254,7 +273,7 @@ public class UpdateContext {
254
273
  if (nextState.staleVersionToDelete != null) {
255
274
  editor.remove("hash_" + nextState.staleVersionToDelete);
256
275
  }
257
- editor.apply();
276
+ persistEditor(editor, "mark success");
258
277
 
259
278
  this.cleanUp();
260
279
  }
@@ -271,7 +290,8 @@ public class UpdateContext {
271
290
  );
272
291
  SharedPreferences.Editor editor = sp.edit();
273
292
  applyState(editor, nextState);
274
- editor.apply();
293
+ editor.remove(KEY_FIRST_LOAD_MARKED);
294
+ persistEditor(editor, "clear first time");
275
295
 
276
296
  this.cleanUp();
277
297
  }
@@ -287,7 +307,7 @@ public class UpdateContext {
287
307
  );
288
308
  SharedPreferences.Editor editor = sp.edit();
289
309
  applyState(editor, nextState);
290
- editor.apply();
310
+ persistEditor(editor, "clear rollback mark");
291
311
 
292
312
  this.cleanUp();
293
313
  }
@@ -334,13 +354,20 @@ public class UpdateContext {
334
354
  STATE_OP_RESOLVE_LAUNCH,
335
355
  currentState,
336
356
  null,
337
- false,
338
- false
357
+ ignoreRollback,
358
+ true
339
359
  );
340
360
  if (launchState.didRollback || launchState.consumedFirstTime) {
341
361
  SharedPreferences.Editor editor = sp.edit();
342
362
  applyState(editor, launchState);
343
- editor.apply();
363
+ if (launchState.consumedFirstTime) {
364
+ editor.putBoolean(KEY_FIRST_LOAD_MARKED, true);
365
+ }
366
+ persistEditor(editor, "resolve launch");
367
+ }
368
+ if (launchState.consumedFirstTime) {
369
+ // bundleURL may be resolved multiple times in one process.
370
+ ignoreRollback = true;
344
371
  }
345
372
 
346
373
  String currentVersion = launchState.loadVersion;
@@ -372,7 +399,7 @@ public class UpdateContext {
372
399
  );
373
400
  SharedPreferences.Editor editor = sp.edit();
374
401
  applyState(editor, nextState);
375
- editor.apply();
402
+ persistEditor(editor, "rollback");
376
403
  return nextState.currentVersion;
377
404
  }
378
405
 
@@ -4,8 +4,6 @@ import static androidx.core.content.FileProvider.getUriForFile;
4
4
  import android.content.Intent;
5
5
  import android.net.Uri;
6
6
  import android.os.Build;
7
- import android.os.Handler;
8
- import android.os.Looper;
9
7
  import com.facebook.react.bridge.Promise;
10
8
  import com.facebook.react.bridge.ReactApplicationContext;
11
9
  import com.facebook.react.bridge.ReactContext;
@@ -19,7 +17,6 @@ import java.util.Map;
19
17
  public class UpdateModule extends NativePushySpec {
20
18
  UpdateContext updateContext;
21
19
  public static ReactApplicationContext mContext;
22
- private final Handler handler = new Handler(Looper.getMainLooper());
23
20
  public UpdateModule(ReactApplicationContext reactContext, UpdateContext updateContext) {
24
21
  super(reactContext);
25
22
  this.updateContext = updateContext;
@@ -40,25 +37,12 @@ public class UpdateModule extends NativePushySpec {
40
37
  constants.put("currentVersionInfo", updateContext.getKv("hash_" + currentVersion));
41
38
  constants.put("buildTime", updateContext.getBuildTime());
42
39
  constants.put("isUsingBundleUrl", updateContext.getIsUsingBundleUrl());
43
- boolean isFirstTime = updateContext.isFirstTime();
40
+ boolean isFirstTime = updateContext.consumeFirstLoadMarker();
44
41
  constants.put("isFirstTime", isFirstTime);
45
- if (isFirstTime) {
46
- handler.postDelayed(new Runnable() {
47
- @Override
48
- public void run() {
49
- updateContext.clearFirstTime();
50
- }
51
- }, 2000);
52
- }
53
42
  String rolledBackVersion = updateContext.rolledBackVersion();
54
43
  constants.put("rolledBackVersion", rolledBackVersion);
55
44
  if (rolledBackVersion != null) {
56
- handler.postDelayed(new Runnable() {
57
- @Override
58
- public void run() {
59
- updateContext.clearRollbackMark();
60
- }
61
- }, 2000);
45
+ updateContext.clearRollbackMark();
62
46
  }
63
47
  constants.put("uuid", updateContext.getKv("uuid"));
64
48
  return constants;
@@ -53,11 +53,8 @@ public class UpdateModule extends ReactContextBaseJavaModule {
53
53
  constants.put("currentVersionInfo", updateContext.getKv("hash_" + currentVersion));
54
54
  constants.put("buildTime", updateContext.getBuildTime());
55
55
  constants.put("isUsingBundleUrl", updateContext.getIsUsingBundleUrl());
56
- boolean isFirstTime = updateContext.isFirstTime();
56
+ boolean isFirstTime = updateContext.consumeFirstLoadMarker();
57
57
  constants.put("isFirstTime", isFirstTime);
58
- if (isFirstTime) {
59
- updateContext.clearFirstTime();
60
- }
61
58
  String rolledBackVersion = updateContext.rolledBackVersion();
62
59
  constants.put("rolledBackVersion", rolledBackVersion);
63
60
  if (rolledBackVersion != null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-update",
3
- "version": "10.38.0-beta.1",
3
+ "version": "10.38.0-beta.3",
4
4
  "description": "react-native hot update",
5
5
  "main": "src/index",
6
6
  "scripts": {
@@ -6,6 +6,9 @@ mock.module('react-native', () => {
6
6
  OS: 'ios',
7
7
  Version: 13,
8
8
  },
9
+ DeviceEventEmitter: {
10
+ addListener: () => ({ remove: () => {} }),
11
+ },
9
12
  NativeModules: {
10
13
  Pushy: {
11
14
  currentVersionInfo: '{}',
package/src/client.ts CHANGED
@@ -42,8 +42,7 @@ import { dedupeEndpoints, executeEndpointFallback } from './endpoint';
42
42
  const SERVER_PRESETS = {
43
43
  // cn
44
44
  Pushy: {
45
- main: 'https://update.react-native.cn/api',
46
- backups: ['https://update.reactnative.cn/api'],
45
+ main: ['https://update.react-native.cn/api', 'https://update.reactnative.cn/api'],
47
46
  queryUrls: [
48
47
  'https://gitee.com/sunnylqm/react-native-pushy/raw/master/endpoints.json',
49
48
  'https://cdn.jsdelivr.net/gh/reactnativecn/react-native-update@master/endpoints.json',
@@ -51,14 +50,26 @@ const SERVER_PRESETS = {
51
50
  },
52
51
  // i18n
53
52
  Cresc: {
54
- main: 'https://api.cresc.dev',
55
- backups: ['https://api.cresc.app'],
53
+ main: ['https://api.cresc.dev', 'https://api.cresc.app'],
56
54
  queryUrls: [
57
55
  'https://cdn.jsdelivr.net/gh/reactnativecn/react-native-update@master/endpoints_cresc.json',
58
56
  ],
59
57
  },
60
58
  };
61
59
 
60
+ const cloneServerConfig = (server: UpdateServerConfig): UpdateServerConfig => ({
61
+ main: dedupeEndpoints([...(server.main || [])]),
62
+ queryUrls: server.queryUrls ? [...server.queryUrls] : undefined,
63
+ });
64
+
65
+ const excludeConfiguredEndpoints = (
66
+ endpoints: string[],
67
+ configuredEndpoints: string[],
68
+ ) => {
69
+ const configured = new Set(configuredEndpoints);
70
+ return endpoints.filter(endpoint => !configured.has(endpoint));
71
+ };
72
+
62
73
  assertWeb();
63
74
 
64
75
  const defaultClientOptions: ClientOptions = {
@@ -71,19 +82,6 @@ const defaultClientOptions: ClientOptions = {
71
82
  throwError: false,
72
83
  };
73
84
 
74
- const cloneServerConfig = (
75
- server?: UpdateServerConfig,
76
- ): UpdateServerConfig | undefined => {
77
- if (!server) {
78
- return undefined;
79
- }
80
- return {
81
- main: server.main,
82
- backups: server.backups ? [...server.backups] : undefined,
83
- queryUrls: server.queryUrls ? [...server.queryUrls] : undefined,
84
- };
85
- };
86
-
87
85
  export const sharedState: {
88
86
  progressHandlers: Record<string, EmitterSubscription>;
89
87
  downloadedHash?: string;
@@ -209,7 +207,7 @@ export class Pushy {
209
207
  throw e;
210
208
  }
211
209
  };
212
- getCheckUrl = (endpoint: string = this.options.server!.main) => {
210
+ getCheckUrl = (endpoint: string) => {
213
211
  return `${endpoint}/checkUpdate/${this.options.appKey}`;
214
212
  };
215
213
  getConfiguredCheckEndpoints = () => {
@@ -217,7 +215,7 @@ export class Pushy {
217
215
  if (!server) {
218
216
  return [];
219
217
  }
220
- return dedupeEndpoints([server.main, ...(server.backups || [])]);
218
+ return dedupeEndpoints(server.main);
221
219
  };
222
220
  getRemoteEndpoints = async () => {
223
221
  const { server } = this.options;
@@ -233,16 +231,14 @@ export class Pushy {
233
231
  const remoteEndpoints = await resp.json();
234
232
  log('fetch endpoints:', remoteEndpoints);
235
233
  if (Array.isArray(remoteEndpoints)) {
236
- const normalizedRemoteEndpoints = dedupeEndpoints(
234
+ return excludeConfiguredEndpoints(
235
+ dedupeEndpoints(
237
236
  remoteEndpoints.filter(
238
237
  (endpoint): endpoint is string => typeof endpoint === 'string',
239
238
  ),
240
- ).filter(endpoint => endpoint !== server.main);
241
- server.backups = dedupeEndpoints([
242
- ...(server.backups || []),
243
- ...normalizedRemoteEndpoints,
244
- ]).filter(endpoint => endpoint !== server.main);
245
- return normalizedRemoteEndpoints;
239
+ ),
240
+ this.getConfiguredCheckEndpoints(),
241
+ );
246
242
  }
247
243
  } catch (e) {
248
244
  log('failed to fetch endpoints from: ', server.queryUrls, e);
@@ -410,8 +406,9 @@ export class Pushy {
410
406
  return [];
411
407
  }
412
408
  const remoteEndpoints = await this.getRemoteEndpoints();
413
- return dedupeEndpoints([...(server.backups || []), ...remoteEndpoints]).filter(
414
- endpoint => endpoint !== server.main,
409
+ return excludeConfiguredEndpoints(
410
+ dedupeEndpoints(remoteEndpoints),
411
+ this.getConfiguredCheckEndpoints(),
415
412
  );
416
413
  };
417
414
  downloadUpdate = async (
package/src/type.ts CHANGED
@@ -77,8 +77,7 @@ export type UpdateEventsLogger = ({
77
77
  }) => void;
78
78
 
79
79
  export interface UpdateServerConfig {
80
- main: string;
81
- backups?: string[];
80
+ main: string[];
82
81
  queryUrls?: string[];
83
82
  }
84
83