1
0
mirror of https://gitcode.com/gh_mirrors/re/react-native-pushy.git synced 2025-09-16 13:11:39 +08:00
Code Issues Packages Projects Releases Wiki Activity GitHub Gitee

Compare commits

...

8 Commits

Author SHA1 Message Date
sunnylqm
bf3a0808f6 fix type error 2025-04-11 18:23:38 +08:00
sunnylqm
4a7bb19ca1 do not use static properties 2025-04-11 18:14:57 +08:00
sunnylqm
7a8640d582 fix lint 2025-04-11 17:36:04 +08:00
sunnylqm
ff50e03446 bump 10.28.2 2025-04-11 17:29:44 +08:00
sunnylqm
7888010061 fix asserthash 2025-04-11 17:28:36 +08:00
sunnylqm
a9c360620f add onpackageexpired 2025-04-11 14:48:18 +08:00
sunnylqm
05738ec204 fix android build 2025-04-11 10:17:08 +08:00
sunnylqm
e4ef93595b feat: enhance Pushy logging with version info and update EventData interface 2025-04-10 12:25:16 +08:00
7 changed files with 97 additions and 71 deletions

View File

@@ -204,17 +204,18 @@ const styles = StyleSheet.create({
});
// use Pushy for China users
// const updateClient = new Pushy({
const updateClient = new Pushy({
appKey,
debug: true,
// updateStrategy: 'silentAndLater',
});
// use Cresc for global users
// const updateClient = new Cresc({
// appKey,
// debug: true,
// });
// use Cresc for global users
const updateClient = new Cresc({
appKey,
debug: true,
});
export default function Root() {
return (
<UpdateProvider client={updateClient}>

View File

@@ -99,7 +99,7 @@ public class UpdateModule extends NativePushySpec {
@Override
public void restartApp(Promise promise) {
UpdateModuleImpl.restartApp(updateContext, mContext, promise);
UpdateModuleImpl.restartApp(mContext, promise);
}
@Override

View File

@@ -1,6 +1,6 @@
{
"name": "react-native-update",
"version": "10.28.0",
"version": "10.28.2",
"description": "react-native hot update",
"main": "src/index",
"scripts": {

View File

@@ -26,6 +26,7 @@ import {
setLocalHashInfo,
isFirstTime,
isRolledBack,
getCurrentVersionInfo,
} from './core';
const SERVER_PRESETS = {
@@ -60,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;
@@ -67,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 = () => {};
@@ -128,6 +147,7 @@ export class Pushy {
log(type + ' ' + message);
await this.loggerPromise.promise;
const { logger = noop, appKey } = this.options;
const info = await getCurrentVersionInfo();
logger({
type,
data: {
@@ -137,6 +157,7 @@ export class Pushy {
packageVersion,
buildTime,
message,
...info,
...data,
},
});
@@ -149,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(
@@ -169,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' });
};
@@ -180,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 });
}
};
@@ -191,7 +202,7 @@ export class Pushy {
if (!assertDev('switchVersionLater()')) {
return;
}
if (Pushy.assertHash(hash)) {
if (assertHash(hash)) {
log('switchVersionLater: ' + hash);
return PushyModule.setNeedUpdate({ hash });
}
@@ -346,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) {
@@ -366,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 = '';
@@ -441,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;
@@ -479,7 +491,7 @@ export class Pushy {
description,
metaInfo,
});
Pushy.downloadedHash = hash;
sharedState.downloadedHash = hash;
return hash;
};
downloadAndInstallApk = async (
@@ -489,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;
@@ -513,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 () => {

View File

@@ -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,

View File

@@ -54,6 +54,9 @@ export interface EventData {
message?: string;
rolledBackVersion?: string;
newVersion?: string;
name?: string;
description?: string;
metaInfo?: string;
[key: string]: any;
}
@@ -89,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 {

View File

@@ -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 {}