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.
- package/android/src/main/java/cn/reactnative/modules/update/UpdateContext.java +37 -10
- package/android/src/newarch/cn/reactnative/modules/update/UpdateModule.java +2 -18
- package/android/src/oldarch/cn/reactnative/modules/update/UpdateModule.java +1 -4
- package/package.json +1 -1
- package/src/__tests__/setup.ts +3 -0
- package/src/client.ts +25 -28
- package/src/type.ts +1 -2
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
-
|
|
338
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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
package/src/__tests__/setup.ts
CHANGED
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
|
|
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(
|
|
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
|
-
|
|
234
|
+
return excludeConfiguredEndpoints(
|
|
235
|
+
dedupeEndpoints(
|
|
237
236
|
remoteEndpoints.filter(
|
|
238
237
|
(endpoint): endpoint is string => typeof endpoint === 'string',
|
|
239
238
|
),
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
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
|
|
414
|
-
|
|
409
|
+
return excludeConfiguredEndpoints(
|
|
410
|
+
dedupeEndpoints(remoteEndpoints),
|
|
411
|
+
this.getConfiguredCheckEndpoints(),
|
|
415
412
|
);
|
|
416
413
|
};
|
|
417
414
|
downloadUpdate = async (
|