mirror of
https://gitcode.com/gh_mirrors/re/react-native-pushy.git
synced 2025-11-22 23:46:10 +08:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f8a29eda8 | ||
|
|
a78542b214 | ||
|
|
8d9ae57a5f | ||
|
|
2502935fc0 | ||
|
|
8e6d9bf460 | ||
|
|
897f334343 | ||
|
|
33bc69c3fb | ||
|
|
5028ce31be |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -25,6 +25,7 @@ import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.CRC32;
|
||||
import java.util.HashMap;
|
||||
|
||||
import okio.BufferedSink;
|
||||
@@ -100,7 +101,7 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
if (UpdateContext.DEBUG) {
|
||||
Log.d("react-native-update", "Progress " + received + "/" + contentLength);
|
||||
}
|
||||
|
||||
|
||||
int percentage = (int)(received * 100.0 / contentLength + 0.5);
|
||||
if (percentage > currentPercentage) {
|
||||
currentPercentage = percentage;
|
||||
@@ -198,6 +199,10 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
return fout.toByteArray();
|
||||
}
|
||||
|
||||
private String getCRC32AsDecimal(long crc32Value) {
|
||||
return String.valueOf(crc32Value & 0xFFFFFFFFL);
|
||||
}
|
||||
|
||||
private void copyFilesWithBlacklist(String current, File from, File to, JSONObject blackList) throws IOException {
|
||||
File[] files = from.listFiles();
|
||||
for (File file : files) {
|
||||
@@ -273,12 +278,41 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
zipFile.close();
|
||||
}
|
||||
|
||||
private void copyFromResourceV2(HashMap<String, ArrayList<File>> resToCopy2) throws IOException {
|
||||
SafeZipFile zipFile = new SafeZipFile(new File(context.getPackageResourcePath()));
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry ze = entries.nextElement();
|
||||
String fn = ze.getName();
|
||||
long zipCrc32 = ze.getCrc();
|
||||
String crc32Decimal = getCRC32AsDecimal(zipCrc32);
|
||||
ArrayList<File> targets = resToCopy2.get(crc32Decimal);
|
||||
if (targets != null) {
|
||||
File lastTarget = null;
|
||||
for (File target: targets) {
|
||||
if (UpdateContext.DEBUG) {
|
||||
Log.d("react-native-update", "Copying from resource " + fn + " to " + target);
|
||||
}
|
||||
if (lastTarget != null) {
|
||||
copyFile(lastTarget, target);
|
||||
} else {
|
||||
zipFile.unzipToFile(ze, target);
|
||||
lastTarget = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
zipFile.close();
|
||||
}
|
||||
|
||||
private void doPatchFromApk(DownloadTaskParams param) throws IOException, JSONException {
|
||||
downloadFile(param);
|
||||
|
||||
removeDirectory(param.unzipDirectory);
|
||||
param.unzipDirectory.mkdirs();
|
||||
HashMap<String, ArrayList<File>> copyList = new HashMap<String, ArrayList<File>>();
|
||||
HashMap<String, ArrayList<File>> copiesv2List = new HashMap<String, ArrayList<File>>();
|
||||
Boolean isV2 = false;
|
||||
|
||||
boolean foundDiff = false;
|
||||
boolean foundBundlePatch = false;
|
||||
@@ -297,29 +331,58 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
JSONObject obj = (JSONObject)new JSONTokener(json).nextValue();
|
||||
|
||||
JSONObject copies = obj.getJSONObject("copies");
|
||||
JSONObject copiesv2 = obj.getJSONObject("copiesv2");
|
||||
Iterator<?> keys = copies.keys();
|
||||
while( keys.hasNext() ) {
|
||||
String to = (String)keys.next();
|
||||
String from = copies.getString(to);
|
||||
if (from.isEmpty()) {
|
||||
from = to;
|
||||
}
|
||||
ArrayList<File> target = null;
|
||||
if (!copyList.containsKey(from)) {
|
||||
target = new ArrayList<File>();
|
||||
copyList.put(from, target);
|
||||
} else {
|
||||
target = copyList.get((from));
|
||||
}
|
||||
File toFile = new File(param.unzipDirectory, to);
|
||||
Iterator<?> keysV2 = copiesv2.keys();
|
||||
if(keysV2.hasNext()){
|
||||
isV2 = true;
|
||||
while( keysV2.hasNext() ) {
|
||||
String from = (String)keysV2.next();
|
||||
String to = copiesv2.getString(from);
|
||||
if (from.isEmpty()) {
|
||||
from = to;
|
||||
}
|
||||
ArrayList<File> target = null;
|
||||
if (!copiesv2List.containsKey(from)) {
|
||||
target = new ArrayList<File>();
|
||||
copiesv2List.put(from, target);
|
||||
} else {
|
||||
target = copiesv2List.get((from));
|
||||
}
|
||||
File toFile = new File(param.unzipDirectory, to);
|
||||
|
||||
// Fixing a Zip Path Traversal Vulnerability
|
||||
// https://support.google.com/faqs/answer/9294009
|
||||
String canonicalPath = toFile.getCanonicalPath();
|
||||
if (!canonicalPath.startsWith(param.unzipDirectory.getCanonicalPath() + File.separator)) {
|
||||
throw new SecurityException("Illegal name: " + to);
|
||||
// Fixing a Zip Path Traversal Vulnerability
|
||||
// https://support.google.com/faqs/answer/9294009
|
||||
String canonicalPath = toFile.getCanonicalPath();
|
||||
if (!canonicalPath.startsWith(param.unzipDirectory.getCanonicalPath() + File.separator)) {
|
||||
throw new SecurityException("Illegal name: " + to);
|
||||
}
|
||||
target.add(toFile);
|
||||
}
|
||||
}else{
|
||||
while( keys.hasNext() ) {
|
||||
String to = (String)keys.next();
|
||||
String from = copies.getString(to);
|
||||
if (from.isEmpty()) {
|
||||
from = to;
|
||||
}
|
||||
ArrayList<File> target = null;
|
||||
if (!copyList.containsKey(from)) {
|
||||
target = new ArrayList<File>();
|
||||
copyList.put(from, target);
|
||||
} else {
|
||||
target = copyList.get((from));
|
||||
}
|
||||
File toFile = new File(param.unzipDirectory, to);
|
||||
|
||||
// Fixing a Zip Path Traversal Vulnerability
|
||||
// https://support.google.com/faqs/answer/9294009
|
||||
String canonicalPath = toFile.getCanonicalPath();
|
||||
if (!canonicalPath.startsWith(param.unzipDirectory.getCanonicalPath() + File.separator)) {
|
||||
throw new SecurityException("Illegal name: " + to);
|
||||
}
|
||||
target.add(toFile);
|
||||
}
|
||||
target.add(toFile);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -348,7 +411,11 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
throw new Error("bundle patch not found");
|
||||
}
|
||||
|
||||
copyFromResource(copyList);
|
||||
if(isV2){
|
||||
copyFromResourceV2(copiesv2List);
|
||||
}else{
|
||||
copyFromResource(copyList);
|
||||
}
|
||||
|
||||
if (UpdateContext.DEBUG) {
|
||||
Log.d("react-native-update", "Unzip finished");
|
||||
|
||||
@@ -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.34.0",
|
||||
"description": "react-native hot update",
|
||||
"main": "src/index",
|
||||
"scripts": {
|
||||
@@ -9,7 +9,7 @@
|
||||
"lint": "eslint \"src/*.@(ts|tsx|js|jsx)\" && tsc --noEmit",
|
||||
"submodule": "git submodule update --init --recursive",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build-lib": "bun submodule && $ANDROID_HOME/ndk/20.1.5948944/ndk-build NDK_PROJECT_PATH=android APP_BUILD_SCRIPT=android/jni/Android.mk NDK_APPLICATION_MK=android/jni/Application.mk NDK_LIBS_OUT=android/lib",
|
||||
"build-lib": "bun submodule && $ANDROID_HOME/ndk/28.2.13676358/ndk-build NDK_PROJECT_PATH=android APP_BUILD_SCRIPT=android/jni/Android.mk NDK_APPLICATION_MK=android/jni/Application.mk NDK_LIBS_OUT=android/lib",
|
||||
"build:ios-debug": "cd Example/testHotUpdate && bun && detox build --configuration ios.sim.debug",
|
||||
"build:ios-release": "cd Example/testHotUpdate && bun && detox build --configuration ios.sim.release",
|
||||
"test:ios-debug": "cd Example/testHotUpdate && detox test --configuration ios.sim.debug",
|
||||
|
||||
@@ -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