mirror of
https://gitcode.com/gh_mirrors/re/react-native-pushy.git
synced 2025-09-16 13:11:39 +08:00
Compare commits
6 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
bf3a0808f6 | ||
![]() |
4a7bb19ca1 | ||
![]() |
7a8640d582 | ||
![]() |
ff50e03446 | ||
![]() |
7888010061 | ||
![]() |
a9c360620f |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-update",
|
||||
"version": "10.28.1",
|
||||
"version": "10.28.2",
|
||||
"description": "react-native hot update",
|
||||
"main": "src/index",
|
||||
"scripts": {
|
||||
|
124
src/client.ts
124
src/client.ts
@@ -61,6 +61,31 @@ const defaultClientOptions: ClientOptions = {
|
||||
throwError: false,
|
||||
};
|
||||
|
||||
export const sharedState: {
|
||||
progressHandlers: Record<string, EmitterSubscription>;
|
||||
downloadedHash?: string;
|
||||
apkStatus: 'downloading' | 'downloaded' | null;
|
||||
marked: boolean;
|
||||
applyingUpdate: boolean;
|
||||
} = {
|
||||
progressHandlers: {},
|
||||
downloadedHash: undefined,
|
||||
apkStatus: null,
|
||||
marked: false,
|
||||
applyingUpdate: false,
|
||||
};
|
||||
|
||||
const assertHash = (hash: string) => {
|
||||
if (!sharedState.downloadedHash) {
|
||||
return;
|
||||
}
|
||||
if (hash !== sharedState.downloadedHash) {
|
||||
log(`use downloaded hash ${sharedState.downloadedHash} first`);
|
||||
return;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// for China users
|
||||
export class Pushy {
|
||||
options = defaultClientOptions;
|
||||
@@ -68,13 +93,6 @@ export class Pushy {
|
||||
lastChecking?: number;
|
||||
lastRespJson?: Promise<any>;
|
||||
|
||||
static progressHandlers: Record<string, EmitterSubscription> = {};
|
||||
static downloadedHash?: string;
|
||||
|
||||
static apkStatus: 'downloading' | 'downloaded' | null = null;
|
||||
|
||||
static marked = false;
|
||||
static applyingUpdate = false;
|
||||
version = cInfo.rnu;
|
||||
loggerPromise = (() => {
|
||||
let resolve: (value?: unknown) => void = () => {};
|
||||
@@ -152,16 +170,6 @@ export class Pushy {
|
||||
getCheckUrl = (endpoint: string = this.options.server!.main) => {
|
||||
return `${endpoint}/checkUpdate/${this.options.appKey}`;
|
||||
};
|
||||
static assertHash = (hash: string) => {
|
||||
if (!this.downloadedHash) {
|
||||
return;
|
||||
}
|
||||
if (hash !== this.downloadedHash) {
|
||||
log(`use downloaded hash ${Pushy.downloadedHash} first`);
|
||||
return;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
assertDebug = () => {
|
||||
if (__DEV__ && !this.options.debug) {
|
||||
console.info(
|
||||
@@ -172,10 +180,10 @@ export class Pushy {
|
||||
return true;
|
||||
};
|
||||
markSuccess = () => {
|
||||
if (Pushy.marked || __DEV__ || !isFirstTime) {
|
||||
if (sharedState.marked || __DEV__ || !isFirstTime) {
|
||||
return;
|
||||
}
|
||||
Pushy.marked = true;
|
||||
sharedState.marked = true;
|
||||
PushyModule.markSuccess();
|
||||
this.report({ type: 'markSuccess' });
|
||||
};
|
||||
@@ -183,9 +191,9 @@ export class Pushy {
|
||||
if (!assertDev('switchVersion()')) {
|
||||
return;
|
||||
}
|
||||
if (Pushy.assertHash(hash) && !Pushy.applyingUpdate) {
|
||||
if (assertHash(hash) && !sharedState.applyingUpdate) {
|
||||
log('switchVersion: ' + hash);
|
||||
Pushy.applyingUpdate = true;
|
||||
sharedState.applyingUpdate = true;
|
||||
return PushyModule.reloadUpdate({ hash });
|
||||
}
|
||||
};
|
||||
@@ -194,7 +202,7 @@ export class Pushy {
|
||||
if (!assertDev('switchVersionLater()')) {
|
||||
return;
|
||||
}
|
||||
if (Pushy.assertHash(hash)) {
|
||||
if (assertHash(hash)) {
|
||||
log('switchVersionLater: ' + hash);
|
||||
return PushyModule.setNeedUpdate({ hash });
|
||||
}
|
||||
@@ -349,18 +357,18 @@ export class Pushy {
|
||||
log(`rolledback hash ${rolledBackVersion}, ignored`);
|
||||
return;
|
||||
}
|
||||
if (Pushy.downloadedHash === hash) {
|
||||
log(`duplicated downloaded hash ${Pushy.downloadedHash}, ignored`);
|
||||
return Pushy.downloadedHash;
|
||||
if (sharedState.downloadedHash === hash) {
|
||||
log(`duplicated downloaded hash ${sharedState.downloadedHash}, ignored`);
|
||||
return sharedState.downloadedHash;
|
||||
}
|
||||
if (Pushy.progressHandlers[hash]) {
|
||||
if (sharedState.progressHandlers[hash]) {
|
||||
return;
|
||||
}
|
||||
const patchStartTime = Date.now();
|
||||
if (onDownloadProgress) {
|
||||
// @ts-expect-error harmony not in existing platforms
|
||||
if (Platform.OS === 'harmony') {
|
||||
Pushy.progressHandlers[hash] = DeviceEventEmitter.addListener(
|
||||
sharedState.progressHandlers[hash] = DeviceEventEmitter.addListener(
|
||||
'RCTPushyDownloadProgress',
|
||||
progressData => {
|
||||
if (progressData.hash === hash) {
|
||||
@@ -369,14 +377,15 @@ export class Pushy {
|
||||
},
|
||||
);
|
||||
} else {
|
||||
Pushy.progressHandlers[hash] = pushyNativeEventEmitter.addListener(
|
||||
'RCTPushyDownloadProgress',
|
||||
progressData => {
|
||||
if (progressData.hash === hash) {
|
||||
onDownloadProgress(progressData);
|
||||
}
|
||||
},
|
||||
);
|
||||
sharedState.progressHandlers[hash] =
|
||||
pushyNativeEventEmitter.addListener(
|
||||
'RCTPushyDownloadProgress',
|
||||
progressData => {
|
||||
if (progressData.hash === hash) {
|
||||
onDownloadProgress(progressData);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
let succeeded = '';
|
||||
@@ -444,9 +453,9 @@ export class Pushy {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Pushy.progressHandlers[hash]) {
|
||||
Pushy.progressHandlers[hash].remove();
|
||||
delete Pushy.progressHandlers[hash];
|
||||
if (sharedState.progressHandlers[hash]) {
|
||||
sharedState.progressHandlers[hash].remove();
|
||||
delete sharedState.progressHandlers[hash];
|
||||
}
|
||||
if (__DEV__) {
|
||||
return hash;
|
||||
@@ -482,7 +491,7 @@ export class Pushy {
|
||||
description,
|
||||
metaInfo,
|
||||
});
|
||||
Pushy.downloadedHash = hash;
|
||||
sharedState.downloadedHash = hash;
|
||||
return hash;
|
||||
};
|
||||
downloadAndInstallApk = async (
|
||||
@@ -492,10 +501,10 @@ export class Pushy {
|
||||
if (Platform.OS !== 'android') {
|
||||
return;
|
||||
}
|
||||
if (Pushy.apkStatus === 'downloading') {
|
||||
if (sharedState.apkStatus === 'downloading') {
|
||||
return;
|
||||
}
|
||||
if (Pushy.apkStatus === 'downloaded') {
|
||||
if (sharedState.apkStatus === 'downloaded') {
|
||||
this.report({ type: 'errorInstallApk' });
|
||||
this.throwIfEnabled(new Error('errorInstallApk'));
|
||||
return;
|
||||
@@ -516,35 +525,36 @@ export class Pushy {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Pushy.apkStatus = 'downloading';
|
||||
sharedState.apkStatus = 'downloading';
|
||||
this.report({ type: 'downloadingApk' });
|
||||
const progressKey = 'downloadingApk';
|
||||
if (onDownloadProgress) {
|
||||
if (Pushy.progressHandlers[progressKey]) {
|
||||
Pushy.progressHandlers[progressKey].remove();
|
||||
if (sharedState.progressHandlers[progressKey]) {
|
||||
sharedState.progressHandlers[progressKey].remove();
|
||||
}
|
||||
Pushy.progressHandlers[progressKey] = pushyNativeEventEmitter.addListener(
|
||||
'RCTPushyDownloadProgress',
|
||||
(progressData: ProgressData) => {
|
||||
if (progressData.hash === progressKey) {
|
||||
onDownloadProgress(progressData);
|
||||
}
|
||||
},
|
||||
);
|
||||
sharedState.progressHandlers[progressKey] =
|
||||
pushyNativeEventEmitter.addListener(
|
||||
'RCTPushyDownloadProgress',
|
||||
(progressData: ProgressData) => {
|
||||
if (progressData.hash === progressKey) {
|
||||
onDownloadProgress(progressData);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
await PushyModule.downloadAndInstallApk({
|
||||
url,
|
||||
target: 'update.apk',
|
||||
hash: progressKey,
|
||||
}).catch(() => {
|
||||
Pushy.apkStatus = null;
|
||||
sharedState.apkStatus = null;
|
||||
this.report({ type: 'errorDownloadAndInstallApk' });
|
||||
this.throwIfEnabled(new Error('errorDownloadAndInstallApk'));
|
||||
});
|
||||
Pushy.apkStatus = 'downloaded';
|
||||
if (Pushy.progressHandlers[progressKey]) {
|
||||
Pushy.progressHandlers[progressKey].remove();
|
||||
delete Pushy.progressHandlers[progressKey];
|
||||
sharedState.apkStatus = 'downloaded';
|
||||
if (sharedState.progressHandlers[progressKey]) {
|
||||
sharedState.progressHandlers[progressKey].remove();
|
||||
delete sharedState.progressHandlers[progressKey];
|
||||
}
|
||||
};
|
||||
restartApp = async () => {
|
||||
|
@@ -12,7 +12,7 @@ import {
|
||||
Platform,
|
||||
Linking,
|
||||
} from 'react-native';
|
||||
import { Pushy, Cresc } from './client';
|
||||
import { Pushy, Cresc, sharedState } from './client';
|
||||
import { currentVersion, packageVersion, getCurrentVersionInfo } from './core';
|
||||
import { CheckResult, ProgressData, UpdateTestPayload } from './type';
|
||||
import { UpdateContext } from './context';
|
||||
@@ -171,7 +171,7 @@ export const UpdateProvider = ({
|
||||
return;
|
||||
}
|
||||
const rollout = info.config?.rollout?.[packageVersion];
|
||||
if (rollout) {
|
||||
if (info.update && rollout) {
|
||||
if (!isInRollout(rollout)) {
|
||||
log(`not in ${rollout}% rollout, ignored`);
|
||||
return;
|
||||
@@ -182,8 +182,15 @@ export const UpdateProvider = ({
|
||||
updateInfoRef.current = info;
|
||||
setUpdateInfo(info);
|
||||
if (info.expired) {
|
||||
if (
|
||||
options.onPackageExpired &&
|
||||
(await options.onPackageExpired(info)) === false
|
||||
) {
|
||||
log('onPackageExpired returned false, skipping');
|
||||
return;
|
||||
}
|
||||
const { downloadUrl } = info;
|
||||
if (downloadUrl && Pushy.apkStatus === null) {
|
||||
if (downloadUrl && sharedState.apkStatus === null) {
|
||||
if (options.updateStrategy === 'silentAndNow') {
|
||||
if (Platform.OS === 'android' && downloadUrl.endsWith('.apk')) {
|
||||
downloadAndInstallApk(downloadUrl);
|
||||
@@ -234,7 +241,7 @@ export const UpdateProvider = ({
|
||||
client,
|
||||
alertError,
|
||||
throwErrorIfEnabled,
|
||||
options.updateStrategy,
|
||||
options,
|
||||
alertUpdate,
|
||||
downloadAndInstallApk,
|
||||
downloadUpdate,
|
||||
|
@@ -92,6 +92,7 @@ export interface ClientOptions {
|
||||
beforeCheckUpdate?: () => Promise<boolean>;
|
||||
beforeDownloadUpdate?: (info: CheckResult) => Promise<boolean>;
|
||||
afterDownloadUpdate?: (info: CheckResult) => Promise<boolean>;
|
||||
onPackageExpired?: (info: CheckResult) => Promise<boolean>;
|
||||
}
|
||||
|
||||
export interface UpdateTestPayload {
|
||||
|
@@ -62,7 +62,7 @@ const ping =
|
||||
if (!pingFinished) {
|
||||
log('ping timeout', url);
|
||||
}
|
||||
}, 2000),
|
||||
}, 5000),
|
||||
),
|
||||
]);
|
||||
};
|
||||
@@ -81,6 +81,7 @@ export const testUrls = async (urls?: string[]) => {
|
||||
try {
|
||||
const ret = await promiseAny(urls.map(ping));
|
||||
if (ret) {
|
||||
log('ping success, use url:', ret);
|
||||
return ret;
|
||||
}
|
||||
} catch {}
|
||||
|
Reference in New Issue
Block a user