mirror of
https://gitcode.com/gh_mirrors/re/react-native-pushy.git
synced 2025-09-17 21:56:11 +08:00
Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f5c307deca | ||
![]() |
b4feae292d | ||
![]() |
a1c2679427 | ||
![]() |
17ff366f51 | ||
![]() |
3c5792423e | ||
![]() |
d071fbfc2b | ||
![]() |
17dffa1eb5 | ||
![]() |
bcd61315e9 | ||
![]() |
f626cc1933 |
@@ -21,6 +21,7 @@ import {
|
||||
switchVersion,
|
||||
switchVersionLater,
|
||||
markSuccess,
|
||||
downloadAndInstallApk,
|
||||
} from 'react-native-update';
|
||||
|
||||
import _updateConfig from '../update.json';
|
||||
@@ -94,11 +95,29 @@ export default class App extends Component {
|
||||
return;
|
||||
}
|
||||
if (info.expired) {
|
||||
Alert.alert('提示', '您的应用版本已更新,请前往应用商店下载新的版本', [
|
||||
Alert.alert('提示', '您的应用版本已更新,点击确定下载安装新版本', [
|
||||
{
|
||||
text: '确定',
|
||||
onPress: () => {
|
||||
info.downloadUrl && Linking.openURL(info.downloadUrl);
|
||||
if (info.downloadUrl) {
|
||||
// apk可直接下载安装
|
||||
if (
|
||||
Platform.OS === 'android' &&
|
||||
info.downloadUrl.endsWith('.apk')
|
||||
) {
|
||||
downloadAndInstallApk({
|
||||
url: info.downloadUrl,
|
||||
onDownloadProgress: ({received, total}) => {
|
||||
this.setState({
|
||||
received,
|
||||
total,
|
||||
});
|
||||
},
|
||||
});
|
||||
} else {
|
||||
Linking.openURL(info.downloadUrl);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
@@ -1,7 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="cn.reactnative.modules.update">
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<application>
|
||||
<meta-data android:name="pushy_build_time" android:value="@string/pushy_build_time" />
|
||||
<provider
|
||||
android:name=".PushyFileProvider"
|
||||
android:authorities="${applicationId}.pushy.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/file_paths" />
|
||||
</provider>
|
||||
</application>
|
||||
</manifest>
|
||||
|
@@ -72,7 +72,7 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
|
||||
private void downloadFile(DownloadTaskParams param) throws IOException {
|
||||
String url = param.url;
|
||||
File writePath = param.zipFilePath;
|
||||
File writePath = param.targetFile;
|
||||
this.hash = param.hash;
|
||||
OkHttpClient client = new OkHttpClient();
|
||||
Request request = new Request.Builder().url(url)
|
||||
@@ -97,6 +97,7 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
|
||||
long bytesRead = 0;
|
||||
long received = 0;
|
||||
int currentPercentage = 0;
|
||||
while ((bytesRead = source.read(sink.buffer(), DOWNLOAD_CHUNK_SIZE)) != -1) {
|
||||
received += bytesRead;
|
||||
sink.emit();
|
||||
@@ -104,11 +105,16 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
Log.d("RNUpdate", "Progress " + received + "/" + contentLength);
|
||||
}
|
||||
|
||||
publishProgress(new long[]{received, contentLength});
|
||||
int percentage = (int)(received * 100.0 / contentLength + 0.5);
|
||||
if (percentage > currentPercentage) {
|
||||
currentPercentage = percentage;
|
||||
publishProgress(new long[]{received, contentLength});
|
||||
}
|
||||
}
|
||||
if (received != contentLength) {
|
||||
throw new Error("Unexpected eof while reading ppk");
|
||||
throw new Error("Unexpected eof while reading downloaded update");
|
||||
}
|
||||
publishProgress(new long[]{received, contentLength});
|
||||
sink.writeAll(source);
|
||||
sink.close();
|
||||
|
||||
@@ -123,7 +129,7 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
WritableMap params = Arguments.createMap();
|
||||
params.putDouble("received", (values[0][0]));
|
||||
params.putDouble("total", (values[0][1]));
|
||||
params.putString("hashname", this.hash);
|
||||
params.putString("hash", this.hash);
|
||||
sendEvent("RCTPushyDownloadProgress", params);
|
||||
|
||||
}
|
||||
@@ -237,10 +243,10 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
copyFilesWithBlacklist("", from, to, blackList);
|
||||
}
|
||||
|
||||
private void doDownload(DownloadTaskParams param) throws IOException {
|
||||
private void doFullPatch(DownloadTaskParams param) throws IOException {
|
||||
downloadFile(param);
|
||||
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.zipFilePath)));
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.targetFile)));
|
||||
ZipEntry ze;
|
||||
String filename;
|
||||
|
||||
@@ -297,7 +303,7 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
private void doPatchFromApk(DownloadTaskParams param) throws IOException, JSONException {
|
||||
downloadFile(param);
|
||||
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.zipFilePath)));
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.targetFile)));
|
||||
ZipEntry ze;
|
||||
int count;
|
||||
String filename;
|
||||
@@ -373,7 +379,7 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
private void doPatchFromPpk(DownloadTaskParams param) throws IOException, JSONException {
|
||||
downloadFile(param);
|
||||
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.zipFilePath)));
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.targetFile)));
|
||||
ZipEntry ze;
|
||||
int count;
|
||||
String filename;
|
||||
@@ -458,8 +464,8 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
protected Void doInBackground(DownloadTaskParams... params) {
|
||||
try {
|
||||
switch (params[0].type) {
|
||||
case DownloadTaskParams.TASK_TYPE_FULL_DOWNLOAD:
|
||||
doDownload(params[0]);
|
||||
case DownloadTaskParams.TASK_TYPE_PATCH_FULL:
|
||||
doFullPatch(params[0]);
|
||||
break;
|
||||
case DownloadTaskParams.TASK_TYPE_PATCH_FROM_APK:
|
||||
doPatchFromApk(params[0]);
|
||||
@@ -467,11 +473,18 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
case DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK:
|
||||
doPatchFromPpk(params[0]);
|
||||
break;
|
||||
case DownloadTaskParams.TASK_TYPE_CLEARUP:
|
||||
case DownloadTaskParams.TASK_TYPE_CLEANUP:
|
||||
doCleanUp(params[0]);
|
||||
break;
|
||||
case DownloadTaskParams.TASK_TYPE_PLAIN_DOWNLOAD:
|
||||
downloadFile(params[0]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (params[0].listener != null) {
|
||||
params[0].listener.onDownloadCompleted(params[0]);
|
||||
}
|
||||
params[0].listener.onDownloadCompleted();
|
||||
} catch (Throwable e) {
|
||||
if (UpdateContext.DEBUG) {
|
||||
e.printStackTrace();
|
||||
|
@@ -8,17 +8,18 @@ import java.io.File;
|
||||
* Created by tdzl2003 on 3/31/16.
|
||||
*/
|
||||
class DownloadTaskParams {
|
||||
static final int TASK_TYPE_FULL_DOWNLOAD = 1;
|
||||
static final int TASK_TYPE_PATCH_FULL = 1;
|
||||
static final int TASK_TYPE_PATCH_FROM_APK = 2;
|
||||
static final int TASK_TYPE_PATCH_FROM_PPK = 3;
|
||||
static final int TASK_TYPE_PLAIN_DOWNLOAD = 4;
|
||||
|
||||
static final int TASK_TYPE_CLEARUP = 0; //Keep hash & originHash
|
||||
static final int TASK_TYPE_CLEANUP = 0; //Keep hash & originHash
|
||||
|
||||
int type;
|
||||
String url;
|
||||
String hash;
|
||||
String originHash;
|
||||
File zipFilePath;
|
||||
File targetFile;
|
||||
File unzipDirectory;
|
||||
File originDirectory;
|
||||
UpdateContext.DownloadFileListener listener;
|
||||
|
@@ -0,0 +1,14 @@
|
||||
package cn.reactnative.modules.update;
|
||||
|
||||
import android.support.v4.content.FileProvider;
|
||||
|
||||
/**
|
||||
* Providing a custom {@code FileProvider} prevents manifest {@code <provider>} name collisions.
|
||||
*
|
||||
* See https://developer.android.com/guide/topics/manifest/provider-element.html for details.
|
||||
*/
|
||||
public class PushyFileProvider extends FileProvider {
|
||||
|
||||
// This class intentionally left blank.
|
||||
|
||||
}
|
@@ -46,7 +46,7 @@ public class UpdateContext {
|
||||
editor.putString("packageVersion", packageVersion);
|
||||
editor.apply();
|
||||
|
||||
this.clearUp();
|
||||
this.cleanUp();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,54 +86,65 @@ public class UpdateContext {
|
||||
}
|
||||
|
||||
public interface DownloadFileListener {
|
||||
void onDownloadCompleted();
|
||||
void onDownloadCompleted(DownloadTaskParams params);
|
||||
void onDownloadFailed(Throwable error);
|
||||
}
|
||||
|
||||
public void downloadFile(String url, String hashName, DownloadFileListener listener) {
|
||||
public void downloadFullUpdate(String url, String hash, DownloadFileListener listener) {
|
||||
DownloadTaskParams params = new DownloadTaskParams();
|
||||
params.type = DownloadTaskParams.TASK_TYPE_FULL_DOWNLOAD;
|
||||
params.type = DownloadTaskParams.TASK_TYPE_PATCH_FULL;
|
||||
params.url = url;
|
||||
params.hash = hashName;
|
||||
params.hash = hash;
|
||||
params.listener = listener;
|
||||
params.zipFilePath = new File(rootDir, hashName + ".ppk");
|
||||
params.unzipDirectory = new File(rootDir, hashName);
|
||||
params.targetFile = new File(rootDir, hash + ".ppk");
|
||||
params.unzipDirectory = new File(rootDir, hash);
|
||||
new DownloadTask(context).executeOnExecutor(this.executor, params);
|
||||
}
|
||||
|
||||
public void downloadPatchFromApk(String url, String hashName, DownloadFileListener listener) {
|
||||
public void downloadFile(String url, String hash, String fileName, DownloadFileListener listener) {
|
||||
DownloadTaskParams params = new DownloadTaskParams();
|
||||
params.type = DownloadTaskParams.TASK_TYPE_PLAIN_DOWNLOAD;
|
||||
params.url = url;
|
||||
params.hash = hash;
|
||||
params.listener = listener;
|
||||
params.targetFile = new File(rootDir, fileName);
|
||||
// params.unzipDirectory = new File(rootDir, hash);
|
||||
new DownloadTask(context).executeOnExecutor(this.executor, params);
|
||||
}
|
||||
|
||||
public void downloadPatchFromApk(String url, String hash, DownloadFileListener listener) {
|
||||
DownloadTaskParams params = new DownloadTaskParams();
|
||||
params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_APK;
|
||||
params.url = url;
|
||||
params.hash = hashName;
|
||||
params.hash = hash;
|
||||
params.listener = listener;
|
||||
params.zipFilePath = new File(rootDir, hashName + ".apk.patch");
|
||||
params.unzipDirectory = new File(rootDir, hashName);
|
||||
params.targetFile = new File(rootDir, hash + ".apk.patch");
|
||||
params.unzipDirectory = new File(rootDir, hash);
|
||||
new DownloadTask(context).executeOnExecutor(this.executor, params);
|
||||
}
|
||||
|
||||
public void downloadPatchFromPpk(String url, String hashName, String originHashName, DownloadFileListener listener) {
|
||||
public void downloadPatchFromPpk(String url, String hash, String originHash, DownloadFileListener listener) {
|
||||
DownloadTaskParams params = new DownloadTaskParams();
|
||||
params.type = DownloadTaskParams.TASK_TYPE_PATCH_FROM_PPK;
|
||||
params.url = url;
|
||||
params.hash = hashName;
|
||||
params.originHash = originHashName;
|
||||
params.hash = hash;
|
||||
params.originHash = originHash;
|
||||
params.listener = listener;
|
||||
params.zipFilePath = new File(rootDir, originHashName + "-" + hashName + ".ppk.patch");
|
||||
params.unzipDirectory = new File(rootDir, hashName);
|
||||
params.originDirectory = new File(rootDir, originHashName);
|
||||
params.targetFile = new File(rootDir, originHash + "-" + hash + ".ppk.patch");
|
||||
params.unzipDirectory = new File(rootDir, hash);
|
||||
params.originDirectory = new File(rootDir, originHash);
|
||||
new DownloadTask(context).executeOnExecutor(this.executor, params);
|
||||
}
|
||||
|
||||
private SharedPreferences sp;
|
||||
|
||||
public void switchVersion(String hashName) {
|
||||
if (!new File(rootDir, hashName+"/index.bundlejs").exists()) {
|
||||
throw new Error("Bundle version " + hashName + " not found.");
|
||||
public void switchVersion(String hash) {
|
||||
if (!new File(rootDir, hash+"/index.bundlejs").exists()) {
|
||||
throw new Error("Bundle version " + hash + " not found.");
|
||||
}
|
||||
String lastVersion = getCurrentVersion();
|
||||
SharedPreferences.Editor editor = sp.edit();
|
||||
editor.putString("currentVersion", hashName);
|
||||
editor.putString("currentVersion", hash);
|
||||
if (lastVersion != null) {
|
||||
editor.putString("lastVersion", lastVersion);
|
||||
}
|
||||
@@ -174,7 +185,7 @@ public class UpdateContext {
|
||||
editor.remove("lastVersion");
|
||||
editor.apply();
|
||||
|
||||
this.clearUp();
|
||||
this.cleanUp();
|
||||
}
|
||||
|
||||
public void clearFirstTime() {
|
||||
@@ -182,7 +193,7 @@ public class UpdateContext {
|
||||
editor.putBoolean("firstTime", false);
|
||||
editor.apply();
|
||||
|
||||
this.clearUp();
|
||||
this.cleanUp();
|
||||
}
|
||||
|
||||
public void clearRollbackMark() {
|
||||
@@ -190,7 +201,7 @@ public class UpdateContext {
|
||||
editor.putBoolean("rolledBack", false);
|
||||
editor.apply();
|
||||
|
||||
this.clearUp();
|
||||
this.cleanUp();
|
||||
}
|
||||
|
||||
|
||||
@@ -256,21 +267,12 @@ public class UpdateContext {
|
||||
return lastVersion;
|
||||
}
|
||||
|
||||
private void clearUp() {
|
||||
private void cleanUp() {
|
||||
DownloadTaskParams params = new DownloadTaskParams();
|
||||
params.type = DownloadTaskParams.TASK_TYPE_CLEARUP;
|
||||
params.type = DownloadTaskParams.TASK_TYPE_CLEANUP;
|
||||
params.hash = sp.getString("currentVersion", null);
|
||||
params.originHash = sp.getString("lastVersion", null);
|
||||
params.unzipDirectory = rootDir;
|
||||
params.listener = new DownloadFileListener() {
|
||||
@Override
|
||||
public void onDownloadCompleted() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownloadFailed(Throwable error) {
|
||||
}
|
||||
};
|
||||
new DownloadTask(context).executeOnExecutor(this.executor, params);
|
||||
}
|
||||
}
|
||||
|
@@ -3,6 +3,8 @@ package cn.reactnative.modules.update;
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.ReactApplication;
|
||||
@@ -18,11 +20,14 @@ import com.facebook.react.bridge.JSBundleLoader;
|
||||
import com.facebook.react.bridge.WritableMap;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static android.support.v4.content.FileProvider.getUriForFile;
|
||||
|
||||
/**
|
||||
* Created by tdzl2003 on 3/31/16.
|
||||
*/
|
||||
@@ -70,10 +75,10 @@ public class UpdateModule extends ReactContextBaseJavaModule{
|
||||
@ReactMethod
|
||||
public void downloadUpdate(ReadableMap options, final Promise promise){
|
||||
String url = options.getString("updateUrl");
|
||||
String hash = options.getString("hashName");
|
||||
updateContext.downloadFile(url, hash, new UpdateContext.DownloadFileListener() {
|
||||
String hash = options.getString("hash");
|
||||
updateContext.downloadFullUpdate(url, hash, new UpdateContext.DownloadFileListener() {
|
||||
@Override
|
||||
public void onDownloadCompleted() {
|
||||
public void onDownloadCompleted(DownloadTaskParams params) {
|
||||
promise.resolve(null);
|
||||
}
|
||||
|
||||
@@ -84,13 +89,58 @@ public class UpdateModule extends ReactContextBaseJavaModule{
|
||||
});
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void downloadAndInstallApk(ReadableMap options, final Promise promise){
|
||||
String url = options.getString("url");
|
||||
String hash = options.getString("hash");
|
||||
String target = options.getString("target");
|
||||
updateContext.downloadFile(url, hash, target, new UpdateContext.DownloadFileListener() {
|
||||
@Override
|
||||
public void onDownloadCompleted(DownloadTaskParams params) {
|
||||
installApk(params.targetFile);
|
||||
promise.resolve(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownloadFailed(Throwable error) {
|
||||
promise.reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// install downloaded apk
|
||||
@ReactMethod
|
||||
public static void installApk(String url) {
|
||||
File toInstall = new File(url);
|
||||
installApk(toInstall);
|
||||
}
|
||||
|
||||
public static void installApk(File toInstall) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
Uri apkUri = getUriForFile(mContext, mContext.getPackageName() + ".pushy.fileprovider", toInstall);
|
||||
|
||||
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
|
||||
intent.setData(apkUri);
|
||||
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivity(intent);
|
||||
} else {
|
||||
Uri apkUri = Uri.fromFile(toInstall);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ReactMethod
|
||||
public void downloadPatchFromPackage(ReadableMap options, final Promise promise){
|
||||
String url = options.getString("updateUrl");
|
||||
String hash = options.getString("hashName");
|
||||
String hash = options.getString("hash");
|
||||
updateContext.downloadPatchFromApk(url, hash, new UpdateContext.DownloadFileListener() {
|
||||
@Override
|
||||
public void onDownloadCompleted() {
|
||||
public void onDownloadCompleted(DownloadTaskParams params) {
|
||||
promise.resolve(null);
|
||||
}
|
||||
|
||||
@@ -104,11 +154,11 @@ public class UpdateModule extends ReactContextBaseJavaModule{
|
||||
@ReactMethod
|
||||
public void downloadPatchFromPpk(ReadableMap options, final Promise promise){
|
||||
String url = options.getString("updateUrl");
|
||||
String hash = options.getString("hashName");
|
||||
String originHash = options.getString("originHashName");
|
||||
String hash = options.getString("hash");
|
||||
String originHash = options.getString("originHash");
|
||||
updateContext.downloadPatchFromPpk(url, hash, originHash, new UpdateContext.DownloadFileListener() {
|
||||
@Override
|
||||
public void onDownloadCompleted() {
|
||||
public void onDownloadCompleted(DownloadTaskParams params) {
|
||||
promise.resolve(null);
|
||||
}
|
||||
|
||||
@@ -121,7 +171,7 @@ public class UpdateModule extends ReactContextBaseJavaModule{
|
||||
|
||||
@ReactMethod
|
||||
public void reloadUpdate(ReadableMap options) {
|
||||
final String hash = options.getString("hashName");
|
||||
final String hash = options.getString("hash");
|
||||
|
||||
UiThreadUtil.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
@@ -162,7 +212,7 @@ public class UpdateModule extends ReactContextBaseJavaModule{
|
||||
|
||||
@ReactMethod
|
||||
public void setNeedUpdate(ReadableMap options) {
|
||||
final String hash = options.getString("hashName");
|
||||
final String hash = options.getString("hash");
|
||||
|
||||
UiThreadUtil.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
|
3
android/src/main/res/xml/file_paths.xml
Normal file
3
android/src/main/res/xml/file_paths.xml
Normal file
@@ -0,0 +1,3 @@
|
||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<files-path name="." path="."/>
|
||||
</paths>
|
@@ -43,8 +43,8 @@ static NSString * const ERROR_FILE_OPERATION = @"file operation error";
|
||||
|
||||
// event def
|
||||
static NSString * const EVENT_PROGRESS_DOWNLOAD = @"RCTPushyDownloadProgress";
|
||||
static NSString * const EVENT_PROGRESS_UNZIP = @"RCTPushyUnzipProgress";
|
||||
static NSString * const PARAM_PROGRESS_HASHNAME = @"hashname";
|
||||
// static NSString * const EVENT_PROGRESS_UNZIP = @"RCTPushyUnzipProgress";
|
||||
static NSString * const PARAM_PROGRESS_HASH = @"hash";
|
||||
static NSString * const PARAM_PROGRESS_RECEIVED = @"received";
|
||||
static NSString * const PARAM_PROGRESS_TOTAL = @"total";
|
||||
|
||||
@@ -62,7 +62,6 @@ static BOOL ignoreRollback = false;
|
||||
bool hasListeners;
|
||||
}
|
||||
|
||||
@synthesize bridge = _bridge;
|
||||
@synthesize methodQueue = _methodQueue;
|
||||
|
||||
RCT_EXPORT_MODULE(RCTPushy);
|
||||
@@ -248,8 +247,8 @@ RCT_EXPORT_METHOD(downloadPatchFromPpk:(NSDictionary *)options
|
||||
|
||||
RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options)
|
||||
{
|
||||
NSString *hashName = options[@"hashName"];
|
||||
if (hashName.length) {
|
||||
NSString *hash = options[@"hash"];
|
||||
if (hash.length) {
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
NSString *lastVersion = nil;
|
||||
if ([defaults objectForKey:keyPushyInfo]) {
|
||||
@@ -258,7 +257,7 @@ RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options)
|
||||
}
|
||||
|
||||
NSMutableDictionary *newInfo = [[NSMutableDictionary alloc] init];
|
||||
newInfo[paramCurrentVersion] = hashName;
|
||||
newInfo[paramCurrentVersion] = hash;
|
||||
newInfo[paramLastVersion] = lastVersion;
|
||||
newInfo[paramIsFirstTime] = @(YES);
|
||||
newInfo[paramIsFirstLoadOk] = @(NO);
|
||||
@@ -271,8 +270,8 @@ RCT_EXPORT_METHOD(setNeedUpdate:(NSDictionary *)options)
|
||||
|
||||
RCT_EXPORT_METHOD(reloadUpdate:(NSDictionary *)options)
|
||||
{
|
||||
NSString *hashName = options[@"hashName"];
|
||||
if (hashName.length) {
|
||||
NSString *hash = options[@"hash"];
|
||||
if (hash.length) {
|
||||
[self setNeedUpdate:options];
|
||||
|
||||
// reload 0.62+
|
||||
@@ -305,7 +304,10 @@ RCT_EXPORT_METHOD(markSuccess)
|
||||
#pragma mark - private
|
||||
- (NSArray<NSString *> *)supportedEvents
|
||||
{
|
||||
return @[EVENT_PROGRESS_DOWNLOAD, EVENT_PROGRESS_UNZIP];
|
||||
return @[
|
||||
EVENT_PROGRESS_DOWNLOAD,
|
||||
// EVENT_PROGRESS_UNZIP
|
||||
];
|
||||
}
|
||||
|
||||
// Will be called when this module's first listener is added.
|
||||
@@ -324,13 +326,13 @@ RCT_EXPORT_METHOD(markSuccess)
|
||||
- (void)doPushy:(PushyType)type options:(NSDictionary *)options callback:(void (^)(NSError *error))callback
|
||||
{
|
||||
NSString *updateUrl = [RCTConvert NSString:options[@"updateUrl"]];
|
||||
NSString *hashName = [RCTConvert NSString:options[@"hashName"]];
|
||||
if (updateUrl.length<=0 || hashName.length<=0) {
|
||||
NSString *hash = [RCTConvert NSString:options[@"hash"]];
|
||||
if (updateUrl.length <= 0 || hash.length <= 0) {
|
||||
callback([self errorWithMessage:ERROR_OPTIONS]);
|
||||
return;
|
||||
}
|
||||
NSString *originHashName = [RCTConvert NSString:options[@"originHashName"]];
|
||||
if (type == PushyTypePatchFromPpk && originHashName<=0) {
|
||||
NSString *originHash = [RCTConvert NSString:options[@"originHash"]];
|
||||
if (type == PushyTypePatchFromPpk && originHash <= 0) {
|
||||
callback([self errorWithMessage:ERROR_OPTIONS]);
|
||||
return;
|
||||
}
|
||||
@@ -342,14 +344,14 @@ RCT_EXPORT_METHOD(markSuccess)
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *zipFilePath = [dir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@%@",hashName, [self zipExtension:type]]];
|
||||
// NSString *unzipDir = [dir stringByAppendingPathComponent:hashName];
|
||||
NSString *zipFilePath = [dir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@%@",hash, [self zipExtension:type]]];
|
||||
// NSString *unzipDir = [dir stringByAppendingPathComponent:hash];
|
||||
|
||||
RCTLogInfo(@"RCTPushy -- download file %@", updateUrl);
|
||||
[RCTPushyDownloader download:updateUrl savePath:zipFilePath progressHandler:^(long long receivedBytes, long long totalBytes) {
|
||||
if (self->hasListeners) {
|
||||
[self sendEventWithName:EVENT_PROGRESS_DOWNLOAD body:@{
|
||||
PARAM_PROGRESS_HASHNAME:hashName,
|
||||
PARAM_PROGRESS_HASH:hash,
|
||||
PARAM_PROGRESS_RECEIVED:[NSNumber numberWithLongLong:receivedBytes],
|
||||
PARAM_PROGRESS_TOTAL:[NSNumber numberWithLongLong:totalBytes]
|
||||
}];
|
||||
@@ -360,16 +362,16 @@ RCT_EXPORT_METHOD(markSuccess)
|
||||
}
|
||||
else {
|
||||
RCTLogInfo(@"RCTPushy -- unzip file %@", zipFilePath);
|
||||
NSString *unzipFilePath = [dir stringByAppendingPathComponent:hashName];
|
||||
NSString *unzipFilePath = [dir stringByAppendingPathComponent:hash];
|
||||
[self->_fileManager unzipFileAtPath:zipFilePath toDestination:unzipFilePath progressHandler:^(NSString *entry,long entryNumber, long total) {
|
||||
if (self->hasListeners) {
|
||||
[self sendEventWithName:EVENT_PROGRESS_UNZIP
|
||||
body:@{
|
||||
PARAM_PROGRESS_HASHNAME:hashName,
|
||||
PARAM_PROGRESS_RECEIVED:[NSNumber numberWithLong:entryNumber],
|
||||
PARAM_PROGRESS_TOTAL:[NSNumber numberWithLong:total]
|
||||
}];
|
||||
}
|
||||
// if (self->hasListeners) {
|
||||
// [self sendEventWithName:EVENT_PROGRESS_UNZIP
|
||||
// body:@{
|
||||
// PARAM_PROGRESS_HASH:hash,
|
||||
// PARAM_PROGRESS_RECEIVED:[NSNumber numberWithLong:entryNumber],
|
||||
// PARAM_PROGRESS_TOTAL:[NSNumber numberWithLong:total]
|
||||
// }];
|
||||
// }
|
||||
|
||||
} completionHandler:^(NSString *path, BOOL succeeded, NSError *error) {
|
||||
dispatch_async(self->_methodQueue, ^{
|
||||
@@ -382,16 +384,16 @@ RCT_EXPORT_METHOD(markSuccess)
|
||||
{
|
||||
NSString *sourceOrigin = [[NSBundle mainBundle] resourcePath];
|
||||
NSString *bundleOrigin = [[RCTPushy binaryBundleURL] path];
|
||||
[self patch:hashName fromBundle:bundleOrigin source:sourceOrigin callback:callback];
|
||||
[self patch:hash fromBundle:bundleOrigin source:sourceOrigin callback:callback];
|
||||
}
|
||||
break;
|
||||
case PushyTypePatchFromPpk:
|
||||
{
|
||||
NSString *lastVersionDir = [dir stringByAppendingPathComponent:originHashName];
|
||||
NSString *lastVersionDir = [dir stringByAppendingPathComponent:originHash];
|
||||
|
||||
NSString *sourceOrigin = lastVersionDir;
|
||||
NSString *bundleOrigin = [lastVersionDir stringByAppendingPathComponent:BUNDLE_FILE_NAME];
|
||||
[self patch:hashName fromBundle:bundleOrigin source:sourceOrigin callback:callback];
|
||||
[self patch:hash fromBundle:bundleOrigin source:sourceOrigin callback:callback];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -405,9 +407,9 @@ RCT_EXPORT_METHOD(markSuccess)
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)patch:(NSString *)hashName fromBundle:(NSString *)bundleOrigin source:(NSString *)sourceOrigin callback:(void (^)(NSError *error))callback
|
||||
- (void)patch:(NSString *)hash fromBundle:(NSString *)bundleOrigin source:(NSString *)sourceOrigin callback:(void (^)(NSError *error))callback
|
||||
{
|
||||
NSString *unzipDir = [[RCTPushy downloadDir] stringByAppendingPathComponent:hashName];
|
||||
NSString *unzipDir = [[RCTPushy downloadDir] stringByAppendingPathComponent:hash];
|
||||
NSString *sourcePatch = [unzipDir stringByAppendingPathComponent:SOURCE_PATCH_NAME];
|
||||
NSString *bundlePatch = [unzipDir stringByAppendingPathComponent:BUNDLE_PATCH_NAME];
|
||||
|
||||
|
17
lib/index.d.ts
vendored
17
lib/index.d.ts
vendored
@@ -5,15 +5,19 @@ export const isFirstTime: boolean;
|
||||
export const isRolledBack: boolean;
|
||||
|
||||
export interface ExpiredResult {
|
||||
upToDate?: false;
|
||||
expired: true;
|
||||
downloadUrl: string;
|
||||
}
|
||||
|
||||
export interface UpTodateResult {
|
||||
expired?: false;
|
||||
upToDate: true;
|
||||
}
|
||||
|
||||
export interface UpdateAvailableResult {
|
||||
expired?: false;
|
||||
upToDate?: false;
|
||||
update: true;
|
||||
name: string; // version name
|
||||
hash: string;
|
||||
@@ -34,7 +38,6 @@ export function downloadUpdate(
|
||||
info: UpdateAvailableResult,
|
||||
eventListeners?: {
|
||||
onDownloadProgress?: (data: ProgressData) => void;
|
||||
onUnzipProgress?: (data: ProgressData) => void;
|
||||
},
|
||||
): Promise<undefined | string>;
|
||||
|
||||
@@ -44,6 +47,14 @@ export function switchVersionLater(hash: string): void;
|
||||
|
||||
export function markSuccess(): void;
|
||||
|
||||
export function downloadAndInstallApk({
|
||||
url,
|
||||
onDownloadProgress,
|
||||
}: {
|
||||
url: string;
|
||||
onDownloadProgress?: (data: ProgressData) => void;
|
||||
}): Promise<void>;
|
||||
|
||||
/**
|
||||
* @param {string} main - The main api endpoint
|
||||
* @param {string[]} [backups] - The back up endpoints.
|
||||
@@ -56,12 +67,12 @@ export function setCustomEndpoints({
|
||||
backupQueryUrl,
|
||||
}: {
|
||||
main: string;
|
||||
backUps?: string[];
|
||||
backups?: string[];
|
||||
backupQueryUrl?: string;
|
||||
}): void;
|
||||
|
||||
interface ProgressData {
|
||||
hashname: string;
|
||||
hash: string;
|
||||
received: number;
|
||||
total: number;
|
||||
}
|
||||
|
46
lib/index.js
46
lib/index.js
@@ -9,7 +9,6 @@ const {
|
||||
version: v,
|
||||
} = require('react-native/Libraries/Core/ReactNativeVersion');
|
||||
const RNVersion = `${v.major}.${v.minor}.${v.patch}`;
|
||||
const uuidv4 = require('uuid/v4');
|
||||
|
||||
let Pushy = NativeModules.Pushy;
|
||||
|
||||
@@ -35,7 +34,7 @@ if (Platform.OS === 'android' && !Pushy.isUsingBundleUrl) {
|
||||
const eventEmitter = new NativeEventEmitter(Pushy);
|
||||
|
||||
if (!uuid) {
|
||||
uuid = uuidv4();
|
||||
uuid = require('uuid/v4')();
|
||||
Pushy.setUuid(uuid);
|
||||
}
|
||||
|
||||
@@ -144,53 +143,45 @@ export async function downloadUpdate(options, eventListeners) {
|
||||
if (!options.update) {
|
||||
return;
|
||||
}
|
||||
let progressHandler;
|
||||
if (eventListeners) {
|
||||
if (eventListeners.onDownloadProgress) {
|
||||
const downloadCallback = eventListeners.onDownloadProgress;
|
||||
eventEmitter.addListener('RCTPushyDownloadProgress', (progressData) => {
|
||||
progressHandler = eventEmitter.addListener('RCTPushyDownloadProgress', (progressData) => {
|
||||
if (progressData.hash === options.hash) {
|
||||
downloadCallback(progressData);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (eventListeners.onUnzipProgress) {
|
||||
const unzipCallback = eventListeners.onUnzipProgress;
|
||||
eventEmitter.addListener('RCTPushyUnzipProgress', (progressData) => {
|
||||
if (progressData.hash === options.hash) {
|
||||
unzipCallback(progressData);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
if (options.diffUrl) {
|
||||
logger('downloading diff');
|
||||
await Pushy.downloadPatchFromPpk({
|
||||
updateUrl: options.diffUrl,
|
||||
hashName: options.hash,
|
||||
originHashName: currentVersion,
|
||||
hash: options.hash,
|
||||
originHash: currentVersion,
|
||||
});
|
||||
} else if (options.pdiffUrl) {
|
||||
logger('downloading pdiff');
|
||||
await Pushy.downloadPatchFromPackage({
|
||||
updateUrl: options.pdiffUrl,
|
||||
hashName: options.hash,
|
||||
hash: options.hash,
|
||||
});
|
||||
}
|
||||
eventEmitter.removeAllListeners('RCTPushyDownloadProgress');
|
||||
eventEmitter.removeAllListeners('RCTPushyUnzipProgress');
|
||||
progressHandler && progressHandler.remove();
|
||||
return options.hash;
|
||||
}
|
||||
|
||||
export function switchVersion(hash) {
|
||||
assertRelease();
|
||||
logger('switchVersion');
|
||||
Pushy.reloadUpdate({ hashName: hash });
|
||||
Pushy.reloadUpdate({ hash });
|
||||
}
|
||||
|
||||
export function switchVersionLater(hash) {
|
||||
assertRelease();
|
||||
logger('switchVersionLater');
|
||||
Pushy.setNeedUpdate({ hashName: hash });
|
||||
Pushy.setNeedUpdate({ hash });
|
||||
}
|
||||
|
||||
export function markSuccess() {
|
||||
@@ -198,3 +189,22 @@ export function markSuccess() {
|
||||
logger('markSuccess');
|
||||
Pushy.markSuccess();
|
||||
}
|
||||
|
||||
export async function downloadAndInstallApk({ url, onDownloadProgress }) {
|
||||
logger('downloadAndInstallApk');
|
||||
let hash = Date.now().toString();
|
||||
let progressHandler;
|
||||
if (onDownloadProgress) {
|
||||
progressHandler = eventEmitter.addListener('RCTPushyDownloadProgress', (progressData) => {
|
||||
if (progressData.hash === hash) {
|
||||
onDownloadProgress(progressData);
|
||||
}
|
||||
});
|
||||
}
|
||||
await Pushy.downloadAndInstallApk({
|
||||
url,
|
||||
target: 'update.apk',
|
||||
hash,
|
||||
});
|
||||
progressHandler && progressHandler.remove();
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-update",
|
||||
"version": "5.8.1",
|
||||
"version": "5.9.1",
|
||||
"description": "react-native hot update",
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
|
Reference in New Issue
Block a user