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

Update react-native-update to version 10.32.0 in package.json, refactor error handling in DownloadTask and UpdateContext for improved readability, and enhance type definitions in various files for better TypeScript support.

This commit is contained in:
sunnylqm
2025-09-20 12:07:53 +08:00
parent d3a4007763
commit 5028ce31be
9 changed files with 341 additions and 312 deletions

View File

@@ -60,13 +60,13 @@ export class DownloadTask {
const exists = fileIo.accessSync(params.targetFile); const exists = fileIo.accessSync(params.targetFile);
if (exists) { if (exists) {
await fileIo.unlink(params.targetFile); await fileIo.unlink(params.targetFile);
}else{ } else {
const targetDir = params.targetFile.substring( const targetDir = params.targetFile.substring(
0, 0,
params.targetFile.lastIndexOf('/'), params.targetFile.lastIndexOf('/'),
); );
const exists = fileIo.accessSync(targetDir); const exists = fileIo.accessSync(targetDir);
if(!exists){ if (!exists) {
await fileIo.mkdir(targetDir); await fileIo.mkdir(targetDir);
} }
} }
@@ -83,7 +83,7 @@ export class DownloadTask {
}, },
}); });
if (response.responseCode > 299) { if (response.responseCode > 299) {
throw new Error(`Server error: ${response.responseCode}`); throw Error(`Server error: ${response.responseCode}`);
} }
const contentLength = parseInt(response.header['content-length'] || '0'); const contentLength = parseInt(response.header['content-length'] || '0');
@@ -108,9 +108,10 @@ export class DownloadTask {
const stats = await fileIo.stat(params.targetFile); const stats = await fileIo.stat(params.targetFile);
const fileSize = stats.size; const fileSize = stats.size;
if (fileSize !== contentLength) { if (fileSize !== contentLength) {
throw new Error(`Download incomplete: expected ${contentLength} bytes but got ${stats.size} bytes`); throw Error(
`Download incomplete: expected ${contentLength} bytes but got ${stats.size} bytes`,
);
} }
} catch (error) { } catch (error) {
console.error('Download failed:', error); console.error('Download failed:', error);
throw error; throw error;
@@ -142,7 +143,7 @@ export class DownloadTask {
bytesRead = await fileIo bytesRead = await fileIo
.read(reader.fd, arrayBuffer) .read(reader.fd, arrayBuffer)
.catch((err: BusinessError) => { .catch((err: BusinessError) => {
throw new Error( throw Error(
`Error reading file: ${err.message}, code: ${err.code}`, `Error reading file: ${err.message}, code: ${err.code}`,
); );
}); });
@@ -154,7 +155,7 @@ export class DownloadTask {
length: bytesRead, length: bytesRead,
}) })
.catch((err: BusinessError) => { .catch((err: BusinessError) => {
throw new Error( throw Error(
`Error writing file: ${err.message}, code: ${err.code}`, `Error writing file: ${err.message}, code: ${err.code}`,
); );
}); });
@@ -295,16 +296,16 @@ export class DownloadTask {
} }
} }
if(fn !== '.DS_Store'){ if (fn !== '.DS_Store') {
await zip.decompressFile(fn, params.unzipDirectory); await zip.decompressFile(fn, params.unzipDirectory);
} }
} }
if (!foundDiff) { if (!foundDiff) {
throw new Error('diff.json not found'); throw Error('diff.json not found');
} }
if (!foundBundlePatch) { if (!foundBundlePatch) {
throw new Error('bundle patch not found'); throw Error('bundle patch not found');
} }
await this.copyFromResource(copyList); await this.copyFromResource(copyList);
} }
@@ -366,12 +367,18 @@ export class DownloadTask {
new Uint8Array(entry.content), new Uint8Array(entry.content),
); );
const outputFile = `${params.unzipDirectory}/bundle.harmony.js`; const outputFile = `${params.unzipDirectory}/bundle.harmony.js`;
const writer = await fileIo.open(outputFile, fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY); const writer = await fileIo.open(
outputFile,
fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY,
);
const chunkSize = 4096; const chunkSize = 4096;
let bytesWritten = 0; let bytesWritten = 0;
const totalLength = patched.byteLength; const totalLength = patched.byteLength;
while (bytesWritten < totalLength) { while (bytesWritten < totalLength) {
const chunk = patched.slice(bytesWritten, bytesWritten + chunkSize); const chunk = patched.slice(
bytesWritten,
bytesWritten + chunkSize,
);
await fileIo.write(writer.fd, chunk); await fileIo.write(writer.fd, chunk);
bytesWritten += chunk.byteLength; bytesWritten += chunk.byteLength;
} }
@@ -387,10 +394,10 @@ export class DownloadTask {
} }
if (!foundDiff) { if (!foundDiff) {
throw new Error('diff.json not found'); throw Error('diff.json not found');
} }
if (!foundBundlePatch) { if (!foundBundlePatch) {
throw new Error('bundle patch not found'); throw Error('bundle patch not found');
} }
console.info('Patch from PPK completed'); console.info('Patch from PPK completed');
} }
@@ -478,7 +485,7 @@ export class DownloadTask {
await this.downloadFile(params); await this.downloadFile(params);
break; break;
default: default:
throw new Error(`Unknown task type: ${params.type}`); throw Error(`Unknown task type: ${params.type}`);
} }
params.listener?.onDownloadCompleted(params); params.listener?.onDownloadCompleted(params);

View File

@@ -6,249 +6,276 @@ import common from '@ohos.app.ability.common';
import { DownloadTaskParams } from './DownloadTaskParams'; import { DownloadTaskParams } from './DownloadTaskParams';
export class UpdateContext { export class UpdateContext {
private context: common.UIAbilityContext; private context: common.UIAbilityContext;
private rootDir: string; private rootDir: string;
private preferences: preferences.Preferences; private preferences: preferences.Preferences;
private static DEBUG: boolean = false; private static DEBUG: boolean = false;
private static isUsingBundleUrl: boolean = false; private static isUsingBundleUrl: boolean = false;
constructor(context: common.UIAbilityContext) { constructor(context: common.UIAbilityContext) {
this.context = context; this.context = context;
this.rootDir = context.filesDir + '/_update'; this.rootDir = context.filesDir + '/_update';
try { try {
if (!fileIo.accessSync(this.rootDir)) { if (!fileIo.accessSync(this.rootDir)) {
fileIo.mkdirSync(this.rootDir); fileIo.mkdirSync(this.rootDir);
} }
} catch (e) { } catch (e) {
console.error('Failed to create root directory:', e); console.error('Failed to create root directory:', e);
}
this.initPreferences();
} }
this.initPreferences();
}
private initPreferences() { private initPreferences() {
try { try {
this.preferences = preferences.getPreferencesSync(this.context, {name:'update'}); this.preferences = preferences.getPreferencesSync(this.context, {
const packageVersion = this.getPackageVersion(); name: 'update',
const storedVersion = this.preferences.getSync('packageVersion', ''); });
if(!storedVersion){ const packageVersion = this.getPackageVersion();
this.preferences.putSync('packageVersion', packageVersion); const storedVersion = this.preferences.getSync('packageVersion', '');
this.preferences.flush(); if (!storedVersion) {
} else if (storedVersion && packageVersion !== storedVersion) { this.preferences.putSync('packageVersion', packageVersion);
this.preferences.clear(); this.preferences.flush();
this.preferences.putSync('packageVersion', packageVersion); } else if (storedVersion && packageVersion !== storedVersion) {
this.preferences.flush(); this.preferences.clear();
this.cleanUp(); this.preferences.putSync('packageVersion', packageVersion);
}
} catch (e) {
console.error('Failed to init preferences:', e);
}
}
public setKv(key: string, value: string): void {
this.preferences.putSync(key, value);
this.preferences.flush();
}
public getKv(key: string): string {
return this.preferences.getSync(key, '') as string;
}
public isFirstTime(): boolean {
return this.preferences.getSync('firstTime', false) as boolean;
}
public rolledBackVersion(): string {
return this.preferences.getSync('rolledBackVersion', '') as string;
}
public markSuccess(): void {
this.preferences.putSync('firstTimeOk', true);
const lastVersion = this.preferences.getSync('lastVersion', '') as string;
const curVersion = this.preferences.getSync('currentVersion', '') as string;
if (lastVersion && lastVersion !== curVersion) {
this.preferences.deleteSync('lastVersion');
this.preferences.deleteSync(`hash_${lastVersion}`);
}
this.preferences.flush(); this.preferences.flush();
this.cleanUp(); this.cleanUp();
}
} catch (e) {
console.error('Failed to init preferences:', e);
} }
}
public clearFirstTime(): void { public setKv(key: string, value: string): void {
this.preferences.putSync('firstTime', false); this.preferences.putSync(key, value);
this.preferences.flush(); this.preferences.flush();
this.cleanUp(); }
public getKv(key: string): string {
return this.preferences.getSync(key, '') as string;
}
public isFirstTime(): boolean {
return this.preferences.getSync('firstTime', false) as boolean;
}
public rolledBackVersion(): string {
return this.preferences.getSync('rolledBackVersion', '') as string;
}
public markSuccess(): void {
this.preferences.putSync('firstTimeOk', true);
const lastVersion = this.preferences.getSync('lastVersion', '') as string;
const curVersion = this.preferences.getSync('currentVersion', '') as string;
if (lastVersion && lastVersion !== curVersion) {
this.preferences.deleteSync('lastVersion');
this.preferences.deleteSync(`hash_${lastVersion}`);
} }
this.preferences.flush();
this.cleanUp();
}
public clearRollbackMark(): void { public clearFirstTime(): void {
this.preferences.putSync('rolledBackVersion', null); this.preferences.putSync('firstTime', false);
this.preferences.flush(); this.preferences.flush();
this.cleanUp(); this.cleanUp();
}
public clearRollbackMark(): void {
this.preferences.putSync('rolledBackVersion', null);
this.preferences.flush();
this.cleanUp();
}
public async downloadFullUpdate(
url: string,
hash: string,
listener: DownloadFileListener,
): Promise<void> {
try {
const params = new DownloadTaskParams();
params.type = DownloadTaskParams.TASK_TYPE_PATCH_FULL;
params.url = url;
params.hash = hash;
params.listener = listener;
params.targetFile = `${this.rootDir}/${hash}.ppk`;
const downloadTask = new DownloadTask(this.context);
await downloadTask.execute(params);
} catch (e) {
console.error('Failed to download full update:', e);
} }
}
public async downloadFullUpdate(url: string, hash: string, listener: DownloadFileListener): Promise<void> { public async downloadFile(
try { url: string,
const params = new DownloadTaskParams(); hash: string,
params.type = DownloadTaskParams.TASK_TYPE_PATCH_FULL; fileName: string,
params.url = url; listener: DownloadFileListener,
params.hash = hash; ): Promise<void> {
params.listener = listener; const params = new DownloadTaskParams();
params.targetFile = `${this.rootDir}/${hash}.ppk`; params.type = DownloadTaskParams.TASK_TYPE_PLAIN_DOWNLOAD;
const downloadTask = new DownloadTask(this.context); params.url = url;
await downloadTask.execute(params); params.hash = hash;
} catch (e) { params.listener = listener;
console.error('Failed to download full update:', e); params.targetFile = this.rootDir + '/' + fileName;
const downloadTask = new DownloadTask(this.context);
await downloadTask.execute(params);
}
public async downloadPatchFromPpk(
url: string,
hash: string,
originHash: string,
listener: DownloadFileListener,
): Promise<void> {
const params = new DownloadTaskParams();
params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK;
params.url = url;
params.hash = hash;
params.originHash = originHash;
params.listener = listener;
params.targetFile = `${this.rootDir}/${originHash}_${hash}.ppk.patch`;
params.unzipDirectory = `${this.rootDir}/${hash}`;
params.originDirectory = `${this.rootDir}/${params.originHash}`;
const downloadTask = new DownloadTask(this.context);
await downloadTask.execute(params);
}
public async downloadPatchFromPackage(
url: string,
hash: string,
listener: DownloadFileListener,
): Promise<void> {
try {
const params = new DownloadTaskParams();
params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_APP;
params.url = url;
params.hash = hash;
params.listener = listener;
params.targetFile = `${this.rootDir}/${hash}.app.patch`;
params.unzipDirectory = `${this.rootDir}/${hash}`;
const downloadTask = new DownloadTask(this.context);
return await downloadTask.execute(params);
} catch (e) {
throw e;
console.error('Failed to download APK patch:', e);
}
}
public switchVersion(hash: string): void {
try {
const bundlePath = `${this.rootDir}/${hash}/bundle.harmony.js`;
if (!fileIo.accessSync(bundlePath)) {
throw Error(`Bundle version ${hash} not found.`);
}
const lastVersion = this.getKv('currentVersion');
this.setKv('currentVersion', hash);
if (lastVersion && lastVersion !== hash) {
this.setKv('lastVersion', lastVersion);
}
this.setKv('firstTime', 'true');
this.setKv('firstTimeOk', 'false');
this.setKv('rolledBackVersion', '');
} catch (e) {
console.error('Failed to switch version:', e);
}
}
public static getBundleUrl(
context: common.UIAbilityContext,
defaultAssetsUrl?: string,
): string {
return new UpdateContext(context).getBundleUrl(defaultAssetsUrl);
}
public getBundleUrl(defaultAssetsUrl?: string): string {
UpdateContext.isUsingBundleUrl = true;
const currentVersion = this.getCurrentVersion();
if (!currentVersion) {
return defaultAssetsUrl;
}
if (!this.isFirstTime()) {
if (!this.preferences.getSync('firstTimeOk', true)) {
return this.rollBack();
}
}
let version = currentVersion;
while (version) {
const bundleFile = `${this.rootDir}/${version}/bundle.harmony.js`;
try {
if (!fileIo.accessSync(bundleFile)) {
console.error(`Bundle version ${version} not found.`);
version = this.rollBack();
continue;
} }
return bundleFile;
} catch (e) {
console.error('Failed to access bundle file:', e);
version = this.rollBack();
}
} }
return defaultAssetsUrl;
}
public async downloadFile(url: string, hash: string, fileName: string, listener: DownloadFileListener): Promise<void> { getPackageVersion(): string {
const params = new DownloadTaskParams(); let bundleFlags =
params.type = DownloadTaskParams.TASK_TYPE_PLAIN_DOWNLOAD; bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION;
params.url = url; let packageVersion = '';
params.hash = hash; try {
params.listener = listener; const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleFlags);
params.targetFile = this.rootDir + '/' + fileName; packageVersion = bundleInfo?.versionName || 'Unknown';
} catch (error) {
const downloadTask = new DownloadTask(this.context); console.error('获取包信息失败:', error);
await downloadTask.execute(params);
} }
return packageVersion;
}
public async downloadPatchFromPpk(url: string, hash: string, originHash: string, listener: DownloadFileListener): Promise<void> { public getCurrentVersion(): string {
const params = new DownloadTaskParams(); const currentVersion = this.getKv('currentVersion');
params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK; return currentVersion;
params.url = url; }
params.hash = hash;
params.originHash = originHash; private rollBack(): string {
params.listener = listener; const lastVersion = this.preferences.getSync('lastVersion', '') as string;
params.targetFile = `${this.rootDir}/${originHash}_${hash}.ppk.patch`; const currentVersion = this.preferences.getSync(
params.unzipDirectory = `${this.rootDir}/${hash}`; 'currentVersion',
params.originDirectory = `${this.rootDir}/${params.originHash}`; '',
) as string;
const downloadTask = new DownloadTask(this.context); if (!lastVersion) {
await downloadTask.execute(params); this.preferences.deleteSync('currentVersion');
} else {
this.preferences.putSync('currentVersion', lastVersion);
} }
this.preferences.putSync('firstTimeOk', true);
this.preferences.putSync('firstTime', false);
this.preferences.putSync('rolledBackVersion', currentVersion);
this.preferences.flush();
return lastVersion;
}
public async downloadPatchFromPackage(url: string, hash: string, listener: DownloadFileListener): Promise<void> { private cleanUp(): void {
try { const params = new DownloadTaskParams();
const params = new DownloadTaskParams(); params.type = DownloadTaskParams.TASK_TYPE_CLEANUP;
params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_APP; params.hash = this.preferences.getSync('currentVersion', '') as string;
params.url = url; params.originHash = this.preferences.getSync('lastVersion', '') as string;
params.hash = hash; params.unzipDirectory = this.rootDir;
params.listener = listener; const downloadTask = new DownloadTask(this.context);
params.targetFile = `${this.rootDir}/${hash}.app.patch`; downloadTask.execute(params);
params.unzipDirectory = `${this.rootDir}/${hash}`; }
const downloadTask = new DownloadTask(this.context); public getIsUsingBundleUrl(): boolean {
return await downloadTask.execute(params); return UpdateContext.isUsingBundleUrl;
} catch (e) { }
throw e;
console.error('Failed to download APK patch:', e);
}
}
public switchVersion(hash: string): void {
try {
const bundlePath = `${this.rootDir}/${hash}/bundle.harmony.js`;
if (!fileIo.accessSync(bundlePath)) {
throw new Error(`Bundle version ${hash} not found.`);
}
const lastVersion = this.getKv('currentVersion');
this.setKv('currentVersion', hash);
if (lastVersion && lastVersion !== hash) {
this.setKv('lastVersion', lastVersion);
}
this.setKv('firstTime', 'true');
this.setKv('firstTimeOk', 'false');
this.setKv('rolledBackVersion', "");
} catch (e) {
console.error('Failed to switch version:', e);
}
}
public static getBundleUrl(context: common.UIAbilityContext, defaultAssetsUrl?: string): string {
return new UpdateContext(context).getBundleUrl(defaultAssetsUrl);
}
public getBundleUrl(defaultAssetsUrl?: string): string {
UpdateContext.isUsingBundleUrl = true;
const currentVersion = this.getCurrentVersion();
if (!currentVersion) {
return defaultAssetsUrl;
}
if (!this.isFirstTime()) {
if (!this.preferences.getSync('firstTimeOk', true)) {
return this.rollBack();
}
}
let version = currentVersion;
while (version) {
const bundleFile = `${this.rootDir}/${version}/bundle.harmony.js`;
try {
if (!fileIo.accessSync(bundleFile)) {
console.error(`Bundle version ${version} not found.`);
version = this.rollBack();
continue;
}
return bundleFile;
} catch (e) {
console.error('Failed to access bundle file:', e);
version = this.rollBack();
}
}
return defaultAssetsUrl;
}
getPackageVersion(): string {
let bundleFlags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION;
let packageVersion = '';
try {
const bundleInfo = bundleManager.getBundleInfoForSelfSync(bundleFlags);
packageVersion = bundleInfo?.versionName || "Unknown";
} catch (error) {
console.error("获取包信息失败:", error);
}
return packageVersion;
}
public getCurrentVersion() : string {
const currentVersion = this.getKv('currentVersion');
return currentVersion;
}
private rollBack(): string {
const lastVersion = this.preferences.getSync('lastVersion', '') as string;
const currentVersion = this.preferences.getSync('currentVersion', '') as string;
if (!lastVersion) {
this.preferences.deleteSync('currentVersion');
} else {
this.preferences.putSync('currentVersion', lastVersion);
}
this.preferences.putSync('firstTimeOk', true);
this.preferences.putSync('firstTime', false);
this.preferences.putSync('rolledBackVersion', currentVersion);
this.preferences.flush();
return lastVersion;
}
private cleanUp(): void {
const params = new DownloadTaskParams();
params.type = DownloadTaskParams.TASK_TYPE_CLEANUP;
params.hash = this.preferences.getSync('currentVersion', '') as string;
params.originHash = this.preferences.getSync('lastVersion', '') as string;
params.unzipDirectory = this.rootDir;
const downloadTask = new DownloadTask(this.context);
downloadTask.execute(params);
}
public getIsUsingBundleUrl(): boolean {
return UpdateContext.isUsingBundleUrl;
}
} }
export interface DownloadFileListener { export interface DownloadFileListener {
onDownloadCompleted(params: DownloadTaskParams): void; onDownloadCompleted(params: DownloadTaskParams): void;
onDownloadFailed(error: Error): void; onDownloadFailed(error: Error): void;
} }

View File

@@ -4,14 +4,14 @@ import { UpdateContext } from './UpdateContext';
import { DownloadTaskParams } from './DownloadTaskParams'; import { DownloadTaskParams } from './DownloadTaskParams';
import logger from './Logger'; import logger from './Logger';
const TAG = "UpdateModuleImpl"; const TAG = 'UpdateModuleImpl';
export class UpdateModuleImpl { export class UpdateModuleImpl {
static readonly NAME = "Pushy"; static readonly NAME = 'Pushy';
static async downloadFullUpdate( static async downloadFullUpdate(
updateContext: UpdateContext, updateContext: UpdateContext,
options: { updateUrl: string; hash: string } options: { updateUrl: string; hash: string },
): Promise<void> { ): Promise<void> {
try { try {
await updateContext.downloadFullUpdate(options.updateUrl, options.hash, { await updateContext.downloadFullUpdate(options.updateUrl, options.hash, {
@@ -20,7 +20,7 @@ export class UpdateModuleImpl {
}, },
onDownloadFailed: (error: Error) => { onDownloadFailed: (error: Error) => {
return Promise.reject(error); return Promise.reject(error);
} },
}); });
} catch (error) { } catch (error) {
logger.error(TAG, `downloadFullUpdate failed: ${error}`); logger.error(TAG, `downloadFullUpdate failed: ${error}`);
@@ -30,18 +30,18 @@ export class UpdateModuleImpl {
static async downloadAndInstallApk( static async downloadAndInstallApk(
context: common.UIAbilityContext, context: common.UIAbilityContext,
options: { url: string; hash: string; target: string } options: { url: string; hash: string; target: string },
): Promise<void> { ): Promise<void> {
try { try {
const want = { const want = {
action: 'action.system.home', action: 'action.system.home',
parameters: { parameters: {
uri: 'appmarket://details' uri: 'appmarket://details',
} },
}; };
if (!context) { if (!context) {
throw new Error('获取context失败'); throw Error('获取context失败');
} }
await context.startAbility(want); await context.startAbility(want);
@@ -53,17 +53,21 @@ export class UpdateModuleImpl {
static async downloadPatchFromPackage( static async downloadPatchFromPackage(
updateContext: UpdateContext, updateContext: UpdateContext,
options: { updateUrl: string; hash: string } options: { updateUrl: string; hash: string },
): Promise<void> { ): Promise<void> {
try { try {
return await updateContext.downloadPatchFromPackage(options.updateUrl, options.hash, { return await updateContext.downloadPatchFromPackage(
onDownloadCompleted: (params: DownloadTaskParams) => { options.updateUrl,
return Promise.resolve(); options.hash,
{
onDownloadCompleted: (params: DownloadTaskParams) => {
return Promise.resolve();
},
onDownloadFailed: (error: Error) => {
return Promise.reject(error);
},
}, },
onDownloadFailed: (error: Error) => { );
return Promise.reject(error);
}
});
} catch (error) { } catch (error) {
logger.error(TAG, `downloadPatchFromPackage failed: ${error}`); logger.error(TAG, `downloadPatchFromPackage failed: ${error}`);
throw error; throw error;
@@ -72,7 +76,7 @@ export class UpdateModuleImpl {
static async downloadPatchFromPpk( static async downloadPatchFromPpk(
updateContext: UpdateContext, updateContext: UpdateContext,
options: { updateUrl: string; hash: string; originHash: string } options: { updateUrl: string; hash: string; originHash: string },
): Promise<void> { ): Promise<void> {
try { try {
await updateContext.downloadPatchFromPpk( await updateContext.downloadPatchFromPpk(
@@ -85,49 +89,49 @@ export class UpdateModuleImpl {
}, },
onDownloadFailed: (error: Error) => { onDownloadFailed: (error: Error) => {
return Promise.reject(error); return Promise.reject(error);
} },
} },
); );
} catch (error) { } catch (error) {
logger.error(TAG, `downloadPatchFromPpk failed: ${error}`); logger.error(TAG, `downloadPatchFromPpk failed: ${error}`);
throw new Error(`执行报错: ${error.message}`); throw Error(`执行报错: ${error.message}`);
} }
} }
static async reloadUpdate( static async reloadUpdate(
updateContext: UpdateContext, updateContext: UpdateContext,
context: common.UIAbilityContext, context: common.UIAbilityContext,
options: { hash: string } options: { hash: string },
): Promise<void> { ): Promise<void> {
const hash = options.hash; const hash = options.hash;
if (!hash) { if (!hash) {
throw new Error('hash不能为空'); throw Error('hash不能为空');
} }
try { try {
await updateContext.switchVersion(hash); await updateContext.switchVersion(hash);
const bundleInfo = await bundleManager.getBundleInfoForSelf( const bundleInfo = await bundleManager.getBundleInfoForSelf(
bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION,
); );
await context.terminateSelf(); await context.terminateSelf();
const want = { const want = {
bundleName: bundleInfo.name, bundleName: bundleInfo.name,
abilityName: context.abilityInfo?.name abilityName: context.abilityInfo?.name,
}; };
await context.startAbility(want); await context.startAbility(want);
} catch (error) { } catch (error) {
logger.error(TAG, `reloadUpdate failed: ${error}`); logger.error(TAG, `reloadUpdate failed: ${error}`);
throw new Error(`pushy:switchVersion failed ${error.message}`); throw Error(`pushy:switchVersion failed ${error.message}`);
} }
} }
static async setNeedUpdate( static async setNeedUpdate(
updateContext: UpdateContext, updateContext: UpdateContext,
options: { hash: string } options: { hash: string },
): Promise<boolean> { ): Promise<boolean> {
const hash = options.hash; const hash = options.hash;
if (!hash) { if (!hash) {
throw new Error('hash不能为空'); throw Error('hash不能为空');
} }
try { try {
@@ -135,7 +139,7 @@ export class UpdateModuleImpl {
return true; return true;
} catch (error) { } catch (error) {
logger.error(TAG, `setNeedUpdate failed: ${error}`); logger.error(TAG, `setNeedUpdate failed: ${error}`);
throw new Error(`switchVersionLater failed: ${error.message}`); throw Error(`switchVersionLater failed: ${error.message}`);
} }
} }
@@ -145,20 +149,20 @@ export class UpdateModuleImpl {
return true; return true;
} catch (error) { } catch (error) {
logger.error(TAG, `markSuccess failed: ${error}`); logger.error(TAG, `markSuccess failed: ${error}`);
throw new Error(`执行报错: ${error.message}`); throw Error(`执行报错: ${error.message}`);
} }
} }
static async setUuid( static async setUuid(
updateContext: UpdateContext, updateContext: UpdateContext,
uuid: string uuid: string,
): Promise<boolean> { ): Promise<boolean> {
try { try {
await updateContext.setKv('uuid', uuid); await updateContext.setKv('uuid', uuid);
return true; return true;
} catch (error) { } catch (error) {
logger.error(TAG, `setUuid failed: ${error}`); logger.error(TAG, `setUuid failed: ${error}`);
throw new Error(`执行报错: ${error.message}`); throw Error(`执行报错: ${error.message}`);
} }
} }
@@ -174,17 +178,14 @@ export class UpdateModuleImpl {
static setLocalHashInfo( static setLocalHashInfo(
updateContext: UpdateContext, updateContext: UpdateContext,
hash: string, hash: string,
info: string info: string,
): boolean { ): boolean {
updateContext.setKv(`hash_${hash}`, info); updateContext.setKv(`hash_${hash}`, info);
return true; return true;
} }
static getLocalHashInfo( static getLocalHashInfo(updateContext: UpdateContext, hash: string): string {
updateContext: UpdateContext,
hash: string
): string {
const value = updateContext.getKv(`hash_${hash}`); const value = updateContext.getKv(`hash_${hash}`);
return value; return value;
} }
} }

View File

@@ -72,6 +72,5 @@
"react-native": "0.73", "react-native": "0.73",
"ts-jest": "^29.3.2", "ts-jest": "^29.3.2",
"typescript": "^5.6.3" "typescript": "^5.6.3"
}, }
"packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72"
} }

View File

@@ -93,7 +93,6 @@ export class Pushy {
clientType: 'Pushy' | 'Cresc' = 'Pushy'; clientType: 'Pushy' | 'Cresc' = 'Pushy';
lastChecking?: number; lastChecking?: number;
lastRespJson?: Promise<CheckResult>; lastRespJson?: Promise<CheckResult>;
lastRespText?: Promise<string>;
version = cInfo.rnu; version = cInfo.rnu;
loggerPromise = (() => { loggerPromise = (() => {
@@ -116,7 +115,7 @@ export class Pushy {
if (Platform.OS === 'ios' || Platform.OS === 'android') { if (Platform.OS === 'ios' || Platform.OS === 'android') {
if (!options.appKey) { if (!options.appKey) {
throw new Error(i18n.t('error_appkey_required')); throw Error(i18n.t('error_appkey_required'));
} }
} }
@@ -293,10 +292,10 @@ export class Pushy {
), ),
); );
} catch (err: any) { } catch (err: any) {
this.throwIfEnabled(new Error('errorCheckingUseBackup')); this.throwIfEnabled(Error('errorCheckingUseBackup'));
} }
} else { } else {
this.throwIfEnabled(new Error('errorCheckingGetBackup')); this.throwIfEnabled(Error('errorCheckingGetBackup'));
} }
} }
if (!resp) { if (!resp) {
@@ -304,21 +303,21 @@ export class Pushy {
type: 'errorChecking', type: 'errorChecking',
message: this.t('error_cannot_connect_server'), message: this.t('error_cannot_connect_server'),
}); });
this.throwIfEnabled(new Error('errorChecking')); this.throwIfEnabled(Error('errorChecking'));
return this.lastRespJson ? await this.lastRespJson : emptyObj; return this.lastRespJson ? await this.lastRespJson : emptyObj;
} }
if (resp.status !== 200) { if (!resp.ok) {
const respText = await resp.text();
const errorMessage = this.t('error_http_status', { const errorMessage = this.t('error_http_status', {
status: resp.status, status: resp.status,
statusText: resp.statusText, statusText: respText,
}); });
this.report({ this.report({
type: 'errorChecking', type: 'errorChecking',
message: errorMessage, message: errorMessage,
}); });
this.throwIfEnabled(new Error(errorMessage)); this.throwIfEnabled(Error(errorMessage));
log('error checking response:', resp.status, await resp.text());
return this.lastRespJson ? await this.lastRespJson : emptyObj; return this.lastRespJson ? await this.lastRespJson : emptyObj;
} }
this.lastRespJson = resp.json(); this.lastRespJson = resp.json();
@@ -435,7 +434,7 @@ export class Pushy {
message: e.message, message: e.message,
}); });
errorMessages.push(errorMessage); errorMessages.push(errorMessage);
lastError = new Error(errorMessage); lastError = Error(errorMessage);
log(errorMessage); log(errorMessage);
} }
} }
@@ -454,7 +453,7 @@ export class Pushy {
message: e.message, message: e.message,
}); });
errorMessages.push(errorMessage); errorMessages.push(errorMessage);
lastError = new Error(errorMessage); lastError = Error(errorMessage);
log(errorMessage); log(errorMessage);
} }
} }
@@ -474,7 +473,7 @@ export class Pushy {
message: e.message, message: e.message,
}); });
errorMessages.push(errorMessage); errorMessages.push(errorMessage);
lastError = new Error(errorMessage); lastError = Error(errorMessage);
log(errorMessage); log(errorMessage);
} }
} else if (__DEV__) { } else if (__DEV__) {
@@ -532,7 +531,7 @@ export class Pushy {
} }
if (sharedState.apkStatus === 'downloaded') { if (sharedState.apkStatus === 'downloaded') {
this.report({ type: 'errorInstallApk' }); this.report({ type: 'errorInstallApk' });
this.throwIfEnabled(new Error('errorInstallApk')); this.throwIfEnabled(Error('errorInstallApk'));
return; return;
} }
if (Platform.Version <= 23) { if (Platform.Version <= 23) {
@@ -542,7 +541,7 @@ export class Pushy {
); );
if (granted !== PermissionsAndroid.RESULTS.GRANTED) { if (granted !== PermissionsAndroid.RESULTS.GRANTED) {
this.report({ type: 'rejectStoragePermission' }); this.report({ type: 'rejectStoragePermission' });
this.throwIfEnabled(new Error('rejectStoragePermission')); this.throwIfEnabled(Error('rejectStoragePermission'));
return; return;
} }
} catch (e: any) { } catch (e: any) {
@@ -575,7 +574,7 @@ export class Pushy {
}).catch(() => { }).catch(() => {
sharedState.apkStatus = null; sharedState.apkStatus = null;
this.report({ type: 'errorDownloadAndInstallApk' }); this.report({ type: 'errorDownloadAndInstallApk' });
this.throwIfEnabled(new Error('errorDownloadAndInstallApk')); this.throwIfEnabled(Error('errorDownloadAndInstallApk'));
}); });
sharedState.apkStatus = 'downloaded'; sharedState.apkStatus = 'downloaded';
if (sharedState.progressHandlers[progressKey]) { if (sharedState.progressHandlers[progressKey]) {

View File

@@ -18,7 +18,7 @@ export const PushyModule =
export const UpdateModule = PushyModule; export const UpdateModule = PushyModule;
if (!PushyModule) { if (!PushyModule) {
throw new Error( throw Error(
'Failed to load react-native-update native module, please try to recompile', 'Failed to load react-native-update native module, please try to recompile',
); );
} }

View File

@@ -16,9 +16,9 @@ import { Pushy, Cresc, sharedState } from './client';
import { currentVersion, packageVersion, getCurrentVersionInfo, currentVersionInfo } from './core'; import { currentVersion, packageVersion, getCurrentVersionInfo, currentVersionInfo } from './core';
import { import {
CheckResult, CheckResult,
MixedCheckResult,
ProgressData, ProgressData,
UpdateTestPayload, UpdateTestPayload,
VersionInfo,
} from './type'; } from './type';
import { UpdateContext } from './context'; import { UpdateContext } from './context';
import { URL } from 'react-native-url-polyfill'; import { URL } from 'react-native-url-polyfill';
@@ -163,7 +163,7 @@ export const UpdateProvider = ({
return; return;
} }
lastChecking.current = now; lastChecking.current = now;
let rootInfo: MixedCheckResult | undefined; let rootInfo: CheckResult | undefined;
try { try {
rootInfo = await client.checkUpdate(extra); rootInfo = await client.checkUpdate(extra);
} catch (e: any) { } catch (e: any) {
@@ -175,8 +175,8 @@ export const UpdateProvider = ({
if (!rootInfo) { if (!rootInfo) {
return; return;
} }
const versions = rootInfo.versions || [rootInfo as CheckResult]; const versions = [rootInfo.expVersion, rootInfo].filter(Boolean) as VersionInfo[];
delete rootInfo.versions; delete rootInfo.expVersion;
for (const versionInfo of versions) { for (const versionInfo of versions) {
const info: CheckResult = { const info: CheckResult = {
...versionInfo, ...versionInfo,
@@ -242,7 +242,7 @@ export const UpdateProvider = ({
alertUpdate( alertUpdate(
client.t('alert_title'), client.t('alert_title'),
client.t('alert_new_version_found', { client.t('alert_new_version_found', {
name: info.name, name: info.name!,
description: info.description, description: info.description,
}), }),
[ [

View File

@@ -24,14 +24,10 @@ interface RootResult {
paths?: string[]; paths?: string[];
} }
export type CheckResult = RootResult & VersionInfo; export type CheckResult = RootResult &
Partial<VersionInfo> & {
export type CheckResultV2 = RootResult & { expVersion?: VersionInfo;
versions?: VersionInfo[]; };
};
export type MixedCheckResult = CheckResult | CheckResultV2;
export interface ProgressData { export interface ProgressData {
hash: string; hash: string;

View File

@@ -17,7 +17,7 @@ export function promiseAny<T>(promises: Promise<T>[]) {
.catch(() => { .catch(() => {
count++; count++;
if (count === promises.length) { if (count === promises.length) {
reject(new Error(i18n.t('error_all_promises_rejected'))); reject(Error(i18n.t('error_all_promises_rejected')));
} }
}); });
}); });
@@ -51,7 +51,7 @@ const ping = isWeb
return finalUrl; return finalUrl;
} }
log('ping failed', url, status, statusText); log('ping failed', url, status, statusText);
throw new Error(i18n.t('error_ping_failed')); throw Error(i18n.t('error_ping_failed'));
}) })
.catch(e => { .catch(e => {
pingFinished = true; pingFinished = true;
@@ -60,7 +60,7 @@ const ping = isWeb
}), }),
new Promise((_, reject) => new Promise((_, reject) =>
setTimeout(() => { setTimeout(() => {
reject(new Error(i18n.t('error_ping_timeout'))); reject(Error(i18n.t('error_ping_timeout')));
if (!pingFinished) { if (!pingFinished) {
log('ping timeout', url); log('ping timeout', url);
} }
@@ -115,7 +115,7 @@ export const enhancedFetch = async (
if (r.ok) { if (r.ok) {
return r; return r;
} }
throw new Error( throw Error(
i18n.t('error_http_status', { i18n.t('error_http_status', {
status: r.status, status: r.status,
statusText: r.statusText, statusText: r.statusText,