diff --git a/src/client.ts b/src/client.ts index cd8bc9a..f8ea4c2 100644 --- a/src/client.ts +++ b/src/client.ts @@ -91,7 +91,8 @@ export class Pushy { options = defaultClientOptions; clientType: 'Pushy' | 'Cresc' = 'Pushy'; lastChecking?: number; - lastRespJson?: Promise; + lastRespJson?: Promise; + lastRespText?: Promise; version = cInfo.rnu; loggerPromise = (() => { @@ -294,20 +295,23 @@ export class Pushy { this.throwIfEnabled(new Error('errorChecking')); return this.lastRespJson ? await this.lastRespJson : emptyObj; } + + if (resp.status !== 200) { + const errorMessage = `${resp.status}: ${resp.statusText}`; + this.report({ + type: 'errorChecking', + message: errorMessage, + }); + this.throwIfEnabled(new Error(errorMessage)); + log('error checking response:', resp.status, await resp.text()); + return this.lastRespJson ? await this.lastRespJson : emptyObj; + } this.lastRespJson = resp.json(); const result: CheckResult = await this.lastRespJson; log('checking result:', result); - if (resp.status !== 200) { - this.report({ - type: 'errorChecking', - message: result.message, - }); - this.throwIfEnabled(new Error(result.message)); - } - return result; }; getBackupEndpoints = async () => { diff --git a/src/provider.tsx b/src/provider.tsx index 2dc1fa1..6b1e28c 100644 --- a/src/provider.tsx +++ b/src/provider.tsx @@ -14,7 +14,12 @@ import { } from 'react-native'; import { Pushy, Cresc, sharedState } from './client'; import { currentVersion, packageVersion, getCurrentVersionInfo } from './core'; -import { CheckResult, ProgressData, UpdateTestPayload } from './type'; +import { + CheckResult, + MixedCheckResult, + ProgressData, + UpdateTestPayload, +} from './type'; import { UpdateContext } from './context'; import { URL } from 'react-native-url-polyfill'; import { isInRollout } from './isInRollout'; @@ -158,84 +163,95 @@ export const UpdateProvider = ({ return; } lastChecking.current = now; - let info: CheckResult; + let rootInfo: MixedCheckResult | undefined; try { - info = await client.checkUpdate(extra); + rootInfo = await client.checkUpdate(extra); } catch (e: any) { setLastError(e); alertError('更新检查失败', e.message); throwErrorIfEnabled(e); return; } - if (!info) { + if (!rootInfo) { return; } - const rollout = info.config?.rollout?.[packageVersion]; - if (info.update && rollout) { - if (!isInRollout(rollout)) { - log(`not in ${rollout}% rollout, ignored`); - return; + const versions = rootInfo.versions || [rootInfo as CheckResult]; + delete rootInfo.versions; + for (const versionInfo of versions) { + const info: CheckResult = { + ...versionInfo, + ...rootInfo, + }; + const rollout = info.config?.rollout?.[packageVersion]; + if (info.update && rollout) { + if (!isInRollout(rollout)) { + log(`${info.name} not in ${rollout}% rollout, ignored`); + continue; + } + log(`${info.name} in ${rollout}% rollout, continue`); } - log(`in ${rollout}% rollout, continue`); - } - info.description = info.description ?? ''; - 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 && sharedState.apkStatus === null) { - if (options.updateStrategy === 'silentAndNow') { - if (Platform.OS === 'android' && downloadUrl.endsWith('.apk')) { - downloadAndInstallApk(downloadUrl); - } else { - Linking.openURL(downloadUrl); + info.description = info.description ?? ''; + 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 && sharedState.apkStatus === null) { + if (options.updateStrategy === 'silentAndNow') { + if (Platform.OS === 'android' && downloadUrl.endsWith('.apk')) { + downloadAndInstallApk(downloadUrl); + } else { + Linking.openURL(downloadUrl); + } + return info; } + alertUpdate('提示', '您的应用版本已更新,点击更新下载安装新版本', [ + { + text: '更新', + onPress: () => { + if ( + Platform.OS === 'android' && + downloadUrl.endsWith('.apk') + ) { + downloadAndInstallApk(downloadUrl); + } else { + Linking.openURL(downloadUrl); + } + }, + }, + ]); + } + } else if (info.update) { + if ( + options.updateStrategy === 'silentAndNow' || + options.updateStrategy === 'silentAndLater' + ) { + downloadUpdate(info); return info; } - alertUpdate('提示', '您的应用版本已更新,点击更新下载安装新版本', [ - { - text: '更新', - onPress: () => { - if (Platform.OS === 'android' && downloadUrl.endsWith('.apk')) { - downloadAndInstallApk(downloadUrl); - } else { - Linking.openURL(downloadUrl); - } + alertUpdate( + '提示', + '检查到新的版本' + info.name + ',是否下载?\n' + info.description, + [ + { text: '取消', style: 'cancel' }, + { + text: '确定', + style: 'default', + onPress: () => { + downloadUpdate(); + }, }, - }, - ]); + ], + ); } - } else if (info.update) { - if ( - options.updateStrategy === 'silentAndNow' || - options.updateStrategy === 'silentAndLater' - ) { - downloadUpdate(info); - return info; - } - alertUpdate( - '提示', - '检查到新的版本' + info.name + ',是否下载?\n' + info.description, - [ - { text: '取消', style: 'cancel' }, - { - text: '确定', - style: 'default', - onPress: () => { - downloadUpdate(); - }, - }, - ], - ); + return info; } - return info; }, [ client, diff --git a/src/type.ts b/src/type.ts index c0bb679..62b1cb3 100644 --- a/src/type.ts +++ b/src/type.ts @@ -1,14 +1,10 @@ -export interface CheckResult { - upToDate?: true; - expired?: true; - downloadUrl?: string; - update?: true; - name?: string; // version name - hash?: string; - description?: string; - metaInfo?: string; - config?: { - rollout?: { +export interface VersionInfo { + name: string; + hash: string; + description: string; + metaInfo: string; + config: { + rollout: { [packageVersion: string]: number; }; [key: string]: any; @@ -16,11 +12,27 @@ export interface CheckResult { pdiff?: string; diff?: string; full?: string; - paths?: string[]; +} + +interface RootResult { + upToDate?: true; + expired?: true; + downloadUrl?: string; + update?: true; paused?: 'app' | 'package'; message?: string; + paths?: string[]; } +export type CheckResult = RootResult & VersionInfo; + +export type CheckResultV2 = RootResult & { + versions?: VersionInfo[]; +}; + +export type MixedCheckResult = CheckResult | CheckResultV2; + + export interface ProgressData { hash: string; received: number;