mirror of
https://gitcode.com/gh_mirrors/re/react-native-pushy.git
synced 2025-11-22 15:36:10 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33bc69c3fb | ||
|
|
5028ce31be |
@@ -60,13 +60,13 @@ export class DownloadTask {
|
||||
const exists = fileIo.accessSync(params.targetFile);
|
||||
if (exists) {
|
||||
await fileIo.unlink(params.targetFile);
|
||||
}else{
|
||||
} else {
|
||||
const targetDir = params.targetFile.substring(
|
||||
0,
|
||||
params.targetFile.lastIndexOf('/'),
|
||||
);
|
||||
const exists = fileIo.accessSync(targetDir);
|
||||
if(!exists){
|
||||
if (!exists) {
|
||||
await fileIo.mkdir(targetDir);
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ export class DownloadTask {
|
||||
},
|
||||
});
|
||||
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');
|
||||
@@ -108,9 +108,10 @@ export class DownloadTask {
|
||||
const stats = await fileIo.stat(params.targetFile);
|
||||
const fileSize = stats.size;
|
||||
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) {
|
||||
console.error('Download failed:', error);
|
||||
throw error;
|
||||
@@ -142,7 +143,7 @@ export class DownloadTask {
|
||||
bytesRead = await fileIo
|
||||
.read(reader.fd, arrayBuffer)
|
||||
.catch((err: BusinessError) => {
|
||||
throw new Error(
|
||||
throw Error(
|
||||
`Error reading file: ${err.message}, code: ${err.code}`,
|
||||
);
|
||||
});
|
||||
@@ -154,7 +155,7 @@ export class DownloadTask {
|
||||
length: bytesRead,
|
||||
})
|
||||
.catch((err: BusinessError) => {
|
||||
throw new Error(
|
||||
throw Error(
|
||||
`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);
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundDiff) {
|
||||
throw new Error('diff.json not found');
|
||||
throw Error('diff.json not found');
|
||||
}
|
||||
if (!foundBundlePatch) {
|
||||
throw new Error('bundle patch not found');
|
||||
throw Error('bundle patch not found');
|
||||
}
|
||||
await this.copyFromResource(copyList);
|
||||
}
|
||||
@@ -366,12 +367,18 @@ export class DownloadTask {
|
||||
new Uint8Array(entry.content),
|
||||
);
|
||||
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;
|
||||
let bytesWritten = 0;
|
||||
const totalLength = patched.byteLength;
|
||||
while (bytesWritten < totalLength) {
|
||||
const chunk = patched.slice(bytesWritten, bytesWritten + chunkSize);
|
||||
const chunk = patched.slice(
|
||||
bytesWritten,
|
||||
bytesWritten + chunkSize,
|
||||
);
|
||||
await fileIo.write(writer.fd, chunk);
|
||||
bytesWritten += chunk.byteLength;
|
||||
}
|
||||
@@ -387,10 +394,10 @@ export class DownloadTask {
|
||||
}
|
||||
|
||||
if (!foundDiff) {
|
||||
throw new Error('diff.json not found');
|
||||
throw Error('diff.json not found');
|
||||
}
|
||||
if (!foundBundlePatch) {
|
||||
throw new Error('bundle patch not found');
|
||||
throw Error('bundle patch not found');
|
||||
}
|
||||
console.info('Patch from PPK completed');
|
||||
}
|
||||
@@ -478,7 +485,7 @@ export class DownloadTask {
|
||||
await this.downloadFile(params);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown task type: ${params.type}`);
|
||||
throw Error(`Unknown task type: ${params.type}`);
|
||||
}
|
||||
|
||||
params.listener?.onDownloadCompleted(params);
|
||||
|
||||
@@ -6,249 +6,276 @@ import common from '@ohos.app.ability.common';
|
||||
import { DownloadTaskParams } from './DownloadTaskParams';
|
||||
|
||||
export class UpdateContext {
|
||||
private context: common.UIAbilityContext;
|
||||
private rootDir: string;
|
||||
private preferences: preferences.Preferences;
|
||||
private static DEBUG: boolean = false;
|
||||
private static isUsingBundleUrl: boolean = false;
|
||||
private context: common.UIAbilityContext;
|
||||
private rootDir: string;
|
||||
private preferences: preferences.Preferences;
|
||||
private static DEBUG: boolean = false;
|
||||
private static isUsingBundleUrl: boolean = false;
|
||||
|
||||
constructor(context: common.UIAbilityContext) {
|
||||
this.context = context;
|
||||
this.rootDir = context.filesDir + '/_update';
|
||||
|
||||
try {
|
||||
if (!fileIo.accessSync(this.rootDir)) {
|
||||
fileIo.mkdirSync(this.rootDir);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to create root directory:', e);
|
||||
}
|
||||
this.initPreferences();
|
||||
constructor(context: common.UIAbilityContext) {
|
||||
this.context = context;
|
||||
this.rootDir = context.filesDir + '/_update';
|
||||
|
||||
try {
|
||||
if (!fileIo.accessSync(this.rootDir)) {
|
||||
fileIo.mkdirSync(this.rootDir);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to create root directory:', e);
|
||||
}
|
||||
this.initPreferences();
|
||||
}
|
||||
|
||||
private initPreferences() {
|
||||
try {
|
||||
this.preferences = preferences.getPreferencesSync(this.context, {name:'update'});
|
||||
const packageVersion = this.getPackageVersion();
|
||||
const storedVersion = this.preferences.getSync('packageVersion', '');
|
||||
if(!storedVersion){
|
||||
this.preferences.putSync('packageVersion', packageVersion);
|
||||
this.preferences.flush();
|
||||
} else if (storedVersion && packageVersion !== storedVersion) {
|
||||
this.preferences.clear();
|
||||
this.preferences.putSync('packageVersion', packageVersion);
|
||||
this.preferences.flush();
|
||||
this.cleanUp();
|
||||
}
|
||||
} 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}`);
|
||||
}
|
||||
private initPreferences() {
|
||||
try {
|
||||
this.preferences = preferences.getPreferencesSync(this.context, {
|
||||
name: 'update',
|
||||
});
|
||||
const packageVersion = this.getPackageVersion();
|
||||
const storedVersion = this.preferences.getSync('packageVersion', '');
|
||||
if (!storedVersion) {
|
||||
this.preferences.putSync('packageVersion', packageVersion);
|
||||
this.preferences.flush();
|
||||
} else if (storedVersion && packageVersion !== storedVersion) {
|
||||
this.preferences.clear();
|
||||
this.preferences.putSync('packageVersion', packageVersion);
|
||||
this.preferences.flush();
|
||||
this.cleanUp();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Failed to init preferences:', e);
|
||||
}
|
||||
}
|
||||
|
||||
public clearFirstTime(): void {
|
||||
this.preferences.putSync('firstTime', false);
|
||||
this.preferences.flush();
|
||||
this.cleanUp();
|
||||
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.cleanUp();
|
||||
}
|
||||
|
||||
public clearRollbackMark(): void {
|
||||
this.preferences.putSync('rolledBackVersion', null);
|
||||
this.preferences.flush();
|
||||
this.cleanUp();
|
||||
public clearFirstTime(): void {
|
||||
this.preferences.putSync('firstTime', false);
|
||||
this.preferences.flush();
|
||||
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> {
|
||||
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 downloadFile(
|
||||
url: string,
|
||||
hash: string,
|
||||
fileName: string,
|
||||
listener: DownloadFileListener,
|
||||
): Promise<void> {
|
||||
const params = new DownloadTaskParams();
|
||||
params.type = DownloadTaskParams.TASK_TYPE_PLAIN_DOWNLOAD;
|
||||
params.url = url;
|
||||
params.hash = hash;
|
||||
params.listener = listener;
|
||||
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> {
|
||||
const params = new DownloadTaskParams();
|
||||
params.type = DownloadTaskParams.TASK_TYPE_PLAIN_DOWNLOAD;
|
||||
params.url = url;
|
||||
params.hash = hash;
|
||||
params.listener = listener;
|
||||
params.targetFile = this.rootDir + '/' + fileName;
|
||||
|
||||
const downloadTask = new DownloadTask(this.context);
|
||||
await downloadTask.execute(params);
|
||||
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 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 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;
|
||||
}
|
||||
|
||||
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}`;
|
||||
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);
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
public getIsUsingBundleUrl(): boolean {
|
||||
return UpdateContext.isUsingBundleUrl;
|
||||
}
|
||||
}
|
||||
|
||||
export interface DownloadFileListener {
|
||||
onDownloadCompleted(params: DownloadTaskParams): void;
|
||||
onDownloadFailed(error: Error): void;
|
||||
}
|
||||
onDownloadCompleted(params: DownloadTaskParams): void;
|
||||
onDownloadFailed(error: Error): void;
|
||||
}
|
||||
|
||||
@@ -4,14 +4,14 @@ import { UpdateContext } from './UpdateContext';
|
||||
import { DownloadTaskParams } from './DownloadTaskParams';
|
||||
import logger from './Logger';
|
||||
|
||||
const TAG = "UpdateModuleImpl";
|
||||
const TAG = 'UpdateModuleImpl';
|
||||
|
||||
export class UpdateModuleImpl {
|
||||
static readonly NAME = "Pushy";
|
||||
static readonly NAME = 'Pushy';
|
||||
|
||||
static async downloadFullUpdate(
|
||||
updateContext: UpdateContext,
|
||||
options: { updateUrl: string; hash: string }
|
||||
updateContext: UpdateContext,
|
||||
options: { updateUrl: string; hash: string },
|
||||
): Promise<void> {
|
||||
try {
|
||||
await updateContext.downloadFullUpdate(options.updateUrl, options.hash, {
|
||||
@@ -20,7 +20,7 @@ export class UpdateModuleImpl {
|
||||
},
|
||||
onDownloadFailed: (error: Error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error(TAG, `downloadFullUpdate failed: ${error}`);
|
||||
@@ -30,18 +30,18 @@ export class UpdateModuleImpl {
|
||||
|
||||
static async downloadAndInstallApk(
|
||||
context: common.UIAbilityContext,
|
||||
options: { url: string; hash: string; target: string }
|
||||
options: { url: string; hash: string; target: string },
|
||||
): Promise<void> {
|
||||
try {
|
||||
const want = {
|
||||
action: 'action.system.home',
|
||||
parameters: {
|
||||
uri: 'appmarket://details'
|
||||
}
|
||||
uri: 'appmarket://details',
|
||||
},
|
||||
};
|
||||
|
||||
if (!context) {
|
||||
throw new Error('获取context失败');
|
||||
throw Error('获取context失败');
|
||||
}
|
||||
|
||||
await context.startAbility(want);
|
||||
@@ -53,17 +53,21 @@ export class UpdateModuleImpl {
|
||||
|
||||
static async downloadPatchFromPackage(
|
||||
updateContext: UpdateContext,
|
||||
options: { updateUrl: string; hash: string }
|
||||
options: { updateUrl: string; hash: string },
|
||||
): Promise<void> {
|
||||
try {
|
||||
return await updateContext.downloadPatchFromPackage(options.updateUrl, options.hash, {
|
||||
onDownloadCompleted: (params: DownloadTaskParams) => {
|
||||
return Promise.resolve();
|
||||
return await updateContext.downloadPatchFromPackage(
|
||||
options.updateUrl,
|
||||
options.hash,
|
||||
{
|
||||
onDownloadCompleted: (params: DownloadTaskParams) => {
|
||||
return Promise.resolve();
|
||||
},
|
||||
onDownloadFailed: (error: Error) => {
|
||||
return Promise.reject(error);
|
||||
},
|
||||
},
|
||||
onDownloadFailed: (error: Error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
});
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error(TAG, `downloadPatchFromPackage failed: ${error}`);
|
||||
throw error;
|
||||
@@ -72,7 +76,7 @@ export class UpdateModuleImpl {
|
||||
|
||||
static async downloadPatchFromPpk(
|
||||
updateContext: UpdateContext,
|
||||
options: { updateUrl: string; hash: string; originHash: string }
|
||||
options: { updateUrl: string; hash: string; originHash: string },
|
||||
): Promise<void> {
|
||||
try {
|
||||
await updateContext.downloadPatchFromPpk(
|
||||
@@ -85,49 +89,49 @@ export class UpdateModuleImpl {
|
||||
},
|
||||
onDownloadFailed: (error: Error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error(TAG, `downloadPatchFromPpk failed: ${error}`);
|
||||
throw new Error(`执行报错: ${error.message}`);
|
||||
throw Error(`执行报错: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
static async reloadUpdate(
|
||||
updateContext: UpdateContext,
|
||||
context: common.UIAbilityContext,
|
||||
options: { hash: string }
|
||||
options: { hash: string },
|
||||
): Promise<void> {
|
||||
const hash = options.hash;
|
||||
if (!hash) {
|
||||
throw new Error('hash不能为空');
|
||||
throw Error('hash不能为空');
|
||||
}
|
||||
|
||||
try {
|
||||
await updateContext.switchVersion(hash);
|
||||
const bundleInfo = await bundleManager.getBundleInfoForSelf(
|
||||
bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION
|
||||
bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_REQUESTED_PERMISSION,
|
||||
);
|
||||
await context.terminateSelf();
|
||||
const want = {
|
||||
bundleName: bundleInfo.name,
|
||||
abilityName: context.abilityInfo?.name
|
||||
abilityName: context.abilityInfo?.name,
|
||||
};
|
||||
await context.startAbility(want);
|
||||
} catch (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(
|
||||
updateContext: UpdateContext,
|
||||
options: { hash: string }
|
||||
options: { hash: string },
|
||||
): Promise<boolean> {
|
||||
const hash = options.hash;
|
||||
if (!hash) {
|
||||
throw new Error('hash不能为空');
|
||||
throw Error('hash不能为空');
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -135,7 +139,7 @@ export class UpdateModuleImpl {
|
||||
return true;
|
||||
} catch (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;
|
||||
} catch (error) {
|
||||
logger.error(TAG, `markSuccess failed: ${error}`);
|
||||
throw new Error(`执行报错: ${error.message}`);
|
||||
throw Error(`执行报错: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
static async setUuid(
|
||||
updateContext: UpdateContext,
|
||||
uuid: string
|
||||
uuid: string,
|
||||
): Promise<boolean> {
|
||||
try {
|
||||
await updateContext.setKv('uuid', uuid);
|
||||
return true;
|
||||
} catch (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(
|
||||
updateContext: UpdateContext,
|
||||
hash: string,
|
||||
info: string
|
||||
info: string,
|
||||
): boolean {
|
||||
updateContext.setKv(`hash_${hash}`, info);
|
||||
return true;
|
||||
}
|
||||
|
||||
static getLocalHashInfo(
|
||||
updateContext: UpdateContext,
|
||||
hash: string
|
||||
): string {
|
||||
static getLocalHashInfo(updateContext: UpdateContext, hash: string): string {
|
||||
const value = updateContext.getKv(`hash_${hash}`);
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-update",
|
||||
"version": "10.31.3",
|
||||
"version": "10.32.0",
|
||||
"description": "react-native hot update",
|
||||
"main": "src/index",
|
||||
"scripts": {
|
||||
@@ -72,6 +72,5 @@
|
||||
"react-native": "0.73",
|
||||
"ts-jest": "^29.3.2",
|
||||
"typescript": "^5.6.3"
|
||||
},
|
||||
"packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,6 @@ export class Pushy {
|
||||
clientType: 'Pushy' | 'Cresc' = 'Pushy';
|
||||
lastChecking?: number;
|
||||
lastRespJson?: Promise<CheckResult>;
|
||||
lastRespText?: Promise<string>;
|
||||
|
||||
version = cInfo.rnu;
|
||||
loggerPromise = (() => {
|
||||
@@ -116,7 +115,7 @@ export class Pushy {
|
||||
|
||||
if (Platform.OS === 'ios' || Platform.OS === 'android') {
|
||||
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) {
|
||||
this.throwIfEnabled(new Error('errorCheckingUseBackup'));
|
||||
this.throwIfEnabled(Error('errorCheckingUseBackup'));
|
||||
}
|
||||
} else {
|
||||
this.throwIfEnabled(new Error('errorCheckingGetBackup'));
|
||||
this.throwIfEnabled(Error('errorCheckingGetBackup'));
|
||||
}
|
||||
}
|
||||
if (!resp) {
|
||||
@@ -304,21 +303,21 @@ export class Pushy {
|
||||
type: 'errorChecking',
|
||||
message: this.t('error_cannot_connect_server'),
|
||||
});
|
||||
this.throwIfEnabled(new Error('errorChecking'));
|
||||
this.throwIfEnabled(Error('errorChecking'));
|
||||
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', {
|
||||
status: resp.status,
|
||||
statusText: resp.statusText,
|
||||
statusText: respText,
|
||||
});
|
||||
this.report({
|
||||
type: 'errorChecking',
|
||||
message: errorMessage,
|
||||
});
|
||||
this.throwIfEnabled(new Error(errorMessage));
|
||||
log('error checking response:', resp.status, await resp.text());
|
||||
this.throwIfEnabled(Error(errorMessage));
|
||||
return this.lastRespJson ? await this.lastRespJson : emptyObj;
|
||||
}
|
||||
this.lastRespJson = resp.json();
|
||||
@@ -435,7 +434,7 @@ export class Pushy {
|
||||
message: e.message,
|
||||
});
|
||||
errorMessages.push(errorMessage);
|
||||
lastError = new Error(errorMessage);
|
||||
lastError = Error(errorMessage);
|
||||
log(errorMessage);
|
||||
}
|
||||
}
|
||||
@@ -454,7 +453,7 @@ export class Pushy {
|
||||
message: e.message,
|
||||
});
|
||||
errorMessages.push(errorMessage);
|
||||
lastError = new Error(errorMessage);
|
||||
lastError = Error(errorMessage);
|
||||
log(errorMessage);
|
||||
}
|
||||
}
|
||||
@@ -474,7 +473,7 @@ export class Pushy {
|
||||
message: e.message,
|
||||
});
|
||||
errorMessages.push(errorMessage);
|
||||
lastError = new Error(errorMessage);
|
||||
lastError = Error(errorMessage);
|
||||
log(errorMessage);
|
||||
}
|
||||
} else if (__DEV__) {
|
||||
@@ -532,7 +531,7 @@ export class Pushy {
|
||||
}
|
||||
if (sharedState.apkStatus === 'downloaded') {
|
||||
this.report({ type: 'errorInstallApk' });
|
||||
this.throwIfEnabled(new Error('errorInstallApk'));
|
||||
this.throwIfEnabled(Error('errorInstallApk'));
|
||||
return;
|
||||
}
|
||||
if (Platform.Version <= 23) {
|
||||
@@ -542,7 +541,7 @@ export class Pushy {
|
||||
);
|
||||
if (granted !== PermissionsAndroid.RESULTS.GRANTED) {
|
||||
this.report({ type: 'rejectStoragePermission' });
|
||||
this.throwIfEnabled(new Error('rejectStoragePermission'));
|
||||
this.throwIfEnabled(Error('rejectStoragePermission'));
|
||||
return;
|
||||
}
|
||||
} catch (e: any) {
|
||||
@@ -575,7 +574,7 @@ export class Pushy {
|
||||
}).catch(() => {
|
||||
sharedState.apkStatus = null;
|
||||
this.report({ type: 'errorDownloadAndInstallApk' });
|
||||
this.throwIfEnabled(new Error('errorDownloadAndInstallApk'));
|
||||
this.throwIfEnabled(Error('errorDownloadAndInstallApk'));
|
||||
});
|
||||
sharedState.apkStatus = 'downloaded';
|
||||
if (sharedState.progressHandlers[progressKey]) {
|
||||
|
||||
@@ -18,7 +18,7 @@ export const PushyModule =
|
||||
export const UpdateModule = PushyModule;
|
||||
|
||||
if (!PushyModule) {
|
||||
throw new Error(
|
||||
throw Error(
|
||||
'Failed to load react-native-update native module, please try to recompile',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@ import { Pushy, Cresc, sharedState } from './client';
|
||||
import { currentVersion, packageVersion, getCurrentVersionInfo, currentVersionInfo } from './core';
|
||||
import {
|
||||
CheckResult,
|
||||
MixedCheckResult,
|
||||
ProgressData,
|
||||
UpdateTestPayload,
|
||||
VersionInfo,
|
||||
} from './type';
|
||||
import { UpdateContext } from './context';
|
||||
import { URL } from 'react-native-url-polyfill';
|
||||
@@ -163,7 +163,7 @@ export const UpdateProvider = ({
|
||||
return;
|
||||
}
|
||||
lastChecking.current = now;
|
||||
let rootInfo: MixedCheckResult | undefined;
|
||||
let rootInfo: CheckResult | undefined;
|
||||
try {
|
||||
rootInfo = await client.checkUpdate(extra);
|
||||
} catch (e: any) {
|
||||
@@ -175,8 +175,8 @@ export const UpdateProvider = ({
|
||||
if (!rootInfo) {
|
||||
return;
|
||||
}
|
||||
const versions = rootInfo.versions || [rootInfo as CheckResult];
|
||||
delete rootInfo.versions;
|
||||
const versions = [rootInfo.expVersion, rootInfo].filter(Boolean) as VersionInfo[];
|
||||
delete rootInfo.expVersion;
|
||||
for (const versionInfo of versions) {
|
||||
const info: CheckResult = {
|
||||
...versionInfo,
|
||||
@@ -242,7 +242,7 @@ export const UpdateProvider = ({
|
||||
alertUpdate(
|
||||
client.t('alert_title'),
|
||||
client.t('alert_new_version_found', {
|
||||
name: info.name,
|
||||
name: info.name!,
|
||||
description: info.description,
|
||||
}),
|
||||
[
|
||||
|
||||
12
src/type.ts
12
src/type.ts
@@ -24,14 +24,10 @@ interface RootResult {
|
||||
paths?: string[];
|
||||
}
|
||||
|
||||
export type CheckResult = RootResult & VersionInfo;
|
||||
|
||||
export type CheckResultV2 = RootResult & {
|
||||
versions?: VersionInfo[];
|
||||
};
|
||||
|
||||
export type MixedCheckResult = CheckResult | CheckResultV2;
|
||||
|
||||
export type CheckResult = RootResult &
|
||||
Partial<VersionInfo> & {
|
||||
expVersion?: VersionInfo;
|
||||
};
|
||||
|
||||
export interface ProgressData {
|
||||
hash: string;
|
||||
|
||||
@@ -17,7 +17,7 @@ export function promiseAny<T>(promises: Promise<T>[]) {
|
||||
.catch(() => {
|
||||
count++;
|
||||
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;
|
||||
}
|
||||
log('ping failed', url, status, statusText);
|
||||
throw new Error(i18n.t('error_ping_failed'));
|
||||
throw Error(i18n.t('error_ping_failed'));
|
||||
})
|
||||
.catch(e => {
|
||||
pingFinished = true;
|
||||
@@ -60,7 +60,7 @@ const ping = isWeb
|
||||
}),
|
||||
new Promise((_, reject) =>
|
||||
setTimeout(() => {
|
||||
reject(new Error(i18n.t('error_ping_timeout')));
|
||||
reject(Error(i18n.t('error_ping_timeout')));
|
||||
if (!pingFinished) {
|
||||
log('ping timeout', url);
|
||||
}
|
||||
@@ -115,7 +115,7 @@ export const enhancedFetch = async (
|
||||
if (r.ok) {
|
||||
return r;
|
||||
}
|
||||
throw new Error(
|
||||
throw Error(
|
||||
i18n.t('error_http_status', {
|
||||
status: r.status,
|
||||
statusText: r.statusText,
|
||||
|
||||
Reference in New Issue
Block a user