mirror of
https://github.com/zhigang1992/react-native-code-push.git
synced 2026-06-10 07:10:36 +08:00
feedback
This commit is contained in:
58
CodePush.m
58
CodePush.m
@@ -23,7 +23,7 @@ static NSString *const DeploymentFailed = @"DeploymentFailed";
|
||||
// These keys represent the names we use to store data in NSUserDefaults
|
||||
static NSString *const FailedUpdatesKey = @"CODE_PUSH_FAILED_UPDATES";
|
||||
static NSString *const PendingUpdateKey = @"CODE_PUSH_PENDING_UPDATE";
|
||||
static NSString *const StatusReportsKey = @"CODE_PUSH_STATUS_REPORTS";
|
||||
static NSString *const LastDeploymentReportKey = @"CODE_PUSH_LAST_DEPLOYMENT_REPORT";
|
||||
|
||||
// These keys are already "namespaced" by the PendingUpdateKey, so
|
||||
// their values don't need to be obfuscated to prevent collision with app data
|
||||
@@ -211,8 +211,8 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
- (BOOL)isDeploymentStatusNotYetReported:(NSString *)appVersionOrPackageIdentifier
|
||||
{
|
||||
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
|
||||
NSDictionary *sentStatusReports = [preferences objectForKey:StatusReportsKey];
|
||||
return sentStatusReports == nil || [sentStatusReports objectForKey:appVersionOrPackageIdentifier] == nil;
|
||||
NSString *sentStatusReportIdentifier = [preferences objectForKey:LastDeploymentReportKey];
|
||||
return sentStatusReportIdentifier == nil || ![sentStatusReportIdentifier isEqualToString:appVersionOrPackageIdentifier];
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -286,18 +286,9 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
}
|
||||
|
||||
- (void)recordDeploymentStatusReported:(NSString *)appVersionOrPackageIdentifier
|
||||
status:(NSString *)status
|
||||
{
|
||||
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
|
||||
NSMutableDictionary *sentStatusReports = [preferences objectForKey:StatusReportsKey];
|
||||
if (sentStatusReports == nil) {
|
||||
sentStatusReports = [NSMutableDictionary dictionary];
|
||||
} else {
|
||||
sentStatusReports = [sentStatusReports mutableCopy];
|
||||
}
|
||||
|
||||
[sentStatusReports setValue:status forKey:appVersionOrPackageIdentifier];
|
||||
[preferences setValue:sentStatusReports forKey:StatusReportsKey];
|
||||
[preferences setValue:LastDeploymentReportKey forKey:appVersionOrPackageIdentifier];
|
||||
[preferences synchronize];
|
||||
}
|
||||
|
||||
@@ -543,45 +534,48 @@ RCT_EXPORT_METHOD(getNewStatusReport:(RCTPromiseResolveBlock)resolve
|
||||
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
|
||||
NSMutableArray *failedUpdates = [preferences objectForKey:FailedUpdatesKey];
|
||||
if (failedUpdates) {
|
||||
NSDictionary* lastFailedPackage = [failedUpdates lastObject];
|
||||
NSDictionary *lastFailedPackage = [failedUpdates lastObject];
|
||||
if (lastFailedPackage) {
|
||||
NSString* lastFailedPackageIdentifier = [self getPackageStatusReportIdentifier:lastFailedPackage];
|
||||
NSString *lastFailedPackageIdentifier = [self getPackageStatusReportIdentifier:lastFailedPackage];
|
||||
if (lastFailedPackageIdentifier && [self isDeploymentStatusNotYetReported:lastFailedPackageIdentifier]) {
|
||||
[self recordDeploymentStatusReported:lastFailedPackageIdentifier
|
||||
status:DeploymentFailed];
|
||||
[self recordDeploymentStatusReported:lastFailedPackageIdentifier];
|
||||
resolve(@{ @"package": lastFailedPackage, @"status": DeploymentFailed });
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_isFirstRunAfterUpdate) {
|
||||
} else if (_isFirstRunAfterUpdate) {
|
||||
// Check if the current CodePush package has been reported
|
||||
NSError *error;
|
||||
NSDictionary* currentPackage = [CodePushPackage getCurrentPackage:&error];
|
||||
if (currentPackage) {
|
||||
NSString* currentPackageIdentifier = [self getPackageStatusReportIdentifier:currentPackage];
|
||||
if (currentPackageIdentifier && [self isDeploymentStatusNotYetReported:currentPackageIdentifier]) {
|
||||
[self recordDeploymentStatusReported:currentPackageIdentifier
|
||||
status:DeploymentSucceeded];
|
||||
[self recordDeploymentStatusReported:currentPackageIdentifier];
|
||||
resolve(@{ @"package": currentPackage, @"status": DeploymentSucceeded });
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NSError *error;
|
||||
NSString *currentPackageHash = [CodePushPackage getCurrentPackageHash:&error];
|
||||
if (error || currentPackageHash == nil) {
|
||||
// Check if the current appVersion has been reported. Use date as the binary identifier to
|
||||
// handle binary releases that do not modify the appVersion.
|
||||
NSURL *binaryJsBundleUrl = [CodePush bundleURL];
|
||||
NSDictionary *binaryFileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[binaryJsBundleUrl path] error:nil];
|
||||
NSTimeInterval binaryDate = [[binaryFileAttributes objectForKey:NSFileModificationDate] timeIntervalSince1970];
|
||||
NSString* binaryIdentifier = [NSString stringWithFormat:@"%f", binaryDate];
|
||||
|
||||
if ([self isDeploymentStatusNotYetReported:binaryIdentifier]) {
|
||||
[self recordDeploymentStatusReported:binaryIdentifier];
|
||||
resolve(@{ @"appVersion": [[CodePushConfig current] appVersion] });
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the current appVersion has been reported.
|
||||
NSString *appVersion = [[CodePushConfig current] appVersion];
|
||||
if ([self isDeploymentStatusNotYetReported:appVersion]) {
|
||||
[self recordDeploymentStatusReported:appVersion
|
||||
status:DeploymentSucceeded];
|
||||
resolve(@{ @"appVersion": appVersion });
|
||||
return;
|
||||
}
|
||||
|
||||
resolve([NSNull null]);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -61,7 +61,7 @@ public class CodePush {
|
||||
private final String PENDING_UPDATE_IS_LOADING_KEY = "isLoading";
|
||||
private final String PENDING_UPDATE_KEY = "CODE_PUSH_PENDING_UPDATE";
|
||||
private final String RESOURCES_BUNDLE = "resources.arsc";
|
||||
private final String STATUS_REPORTS_KEY = "CODE_PUSH_STATUS_REPORTS";
|
||||
private final String LAST_DEPLOYMENT_REPORT_KEY = "CODE_PUSH_LAST_DEPLOYMENT_REPORT";
|
||||
|
||||
// This needs to be kept in sync with https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManager.java#L78
|
||||
private final String REACT_DEV_BUNDLE_CACHE_FILE_NAME = "ReactNativeDevBundle.js";
|
||||
@@ -153,10 +153,10 @@ public class CodePush {
|
||||
binaryModifiedDateDuringPackageInstall = Long.parseLong(binaryModifiedDateDuringPackageInstallString);
|
||||
}
|
||||
|
||||
String pacakgeAppVersion = CodePushUtils.tryGetString(packageMetadata, "appVersion");
|
||||
String packageAppVersion = CodePushUtils.tryGetString(packageMetadata, "appVersion");
|
||||
if (binaryModifiedDateDuringPackageInstall != null &&
|
||||
binaryModifiedDateDuringPackageInstall == binaryResourcesModifiedTime &&
|
||||
(this.isUsingTestConfiguration() || this.appVersion.equals(pacakgeAppVersion))) {
|
||||
(this.isUsingTestConfiguration() || this.appVersion.equals(packageAppVersion))) {
|
||||
CodePushUtils.logBundleUrl(packageFilePath);
|
||||
return packageFilePath;
|
||||
} else {
|
||||
@@ -169,8 +169,6 @@ public class CodePush {
|
||||
CodePushUtils.logBundleUrl(binaryJsBundleUrl);
|
||||
return binaryJsBundleUrl;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new CodePushUnknownException("Error in getting current package bundle path", e);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new CodePushUnknownException("Error in reading binary modified date from package metadata", e);
|
||||
}
|
||||
@@ -263,17 +261,11 @@ public class CodePush {
|
||||
|
||||
private boolean isDeploymentStatusNotYetReported(String appVersionOrPackageIdentifier) {
|
||||
SharedPreferences settings = applicationContext.getSharedPreferences(CODE_PUSH_PREFERENCES, 0);
|
||||
String sentStatusReportsString = settings.getString(STATUS_REPORTS_KEY, null);
|
||||
if (sentStatusReportsString == null) {
|
||||
String lastDeploymentReportIdentifier = settings.getString(LAST_DEPLOYMENT_REPORT_KEY, null);
|
||||
if (lastDeploymentReportIdentifier == null) {
|
||||
return true;
|
||||
} else {
|
||||
try {
|
||||
JSONObject sentStatusReports = new JSONObject(sentStatusReportsString);
|
||||
return !sentStatusReports.has(appVersionOrPackageIdentifier);
|
||||
} catch (JSONException e) {
|
||||
throw new CodePushUnknownException("Unable to parse sent status reports information " +
|
||||
sentStatusReportsString + " stored in SharedPreferences.", e);
|
||||
}
|
||||
return !lastDeploymentReportIdentifier.equals(appVersionOrPackageIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,22 +303,9 @@ public class CodePush {
|
||||
}
|
||||
}
|
||||
|
||||
private void recordDeploymentStatusReported(String appVersionOrPackageIdentifier, String status) {
|
||||
private void recordDeploymentStatusReported(String appVersionOrPackageIdentifier) {
|
||||
SharedPreferences settings = applicationContext.getSharedPreferences(CODE_PUSH_PREFERENCES, 0);
|
||||
String sentStatusReportsString = settings.getString(STATUS_REPORTS_KEY, null);
|
||||
JSONObject sentStatusReports;
|
||||
try {
|
||||
if (sentStatusReportsString == null) {
|
||||
sentStatusReports = new JSONObject();
|
||||
} else {
|
||||
sentStatusReports = new JSONObject(sentStatusReportsString);
|
||||
}
|
||||
|
||||
sentStatusReports.put(appVersionOrPackageIdentifier, status);
|
||||
settings.edit().putString(STATUS_REPORTS_KEY, sentStatusReports.toString()).commit();
|
||||
} catch (JSONException e) {
|
||||
throw new CodePushUnknownException("Unable to save new entry in SharedPreferences under " + STATUS_REPORTS_KEY + ".", e);
|
||||
}
|
||||
settings.edit().putString(LAST_DEPLOYMENT_REPORT_KEY, appVersionOrPackageIdentifier).commit();
|
||||
}
|
||||
|
||||
private void removeFailedUpdates() {
|
||||
@@ -340,19 +319,9 @@ public class CodePush {
|
||||
}
|
||||
|
||||
private void rollbackPackage() {
|
||||
try {
|
||||
WritableMap failedPackage = codePushPackage.getCurrentPackage();
|
||||
saveFailedUpdate(failedPackage);
|
||||
} catch (IOException e) {
|
||||
throw new CodePushUnknownException("Attempted a rollback without having a current downloaded package", e);
|
||||
}
|
||||
|
||||
try {
|
||||
codePushPackage.rollbackPackage();
|
||||
} catch (IOException e) {
|
||||
throw new CodePushUnknownException("Error in rolling back package", e);
|
||||
}
|
||||
|
||||
WritableMap failedPackage = codePushPackage.getCurrentPackage();
|
||||
saveFailedUpdate(failedPackage);
|
||||
codePushPackage.rollbackPackage();
|
||||
removePendingUpdate();
|
||||
}
|
||||
|
||||
@@ -464,23 +433,17 @@ public class CodePush {
|
||||
AsyncTask asyncTask = new AsyncTask() {
|
||||
@Override
|
||||
protected Void doInBackground(Object... params) {
|
||||
try {
|
||||
WritableMap currentPackage = codePushPackage.getCurrentPackage();
|
||||
WritableMap currentPackage = codePushPackage.getCurrentPackage();
|
||||
|
||||
Boolean isPendingUpdate = false;
|
||||
Boolean isPendingUpdate = false;
|
||||
|
||||
if (currentPackage.hasKey(codePushPackage.PACKAGE_HASH_KEY)) {
|
||||
String currentHash = currentPackage.getString(codePushPackage.PACKAGE_HASH_KEY);
|
||||
isPendingUpdate = CodePush.this.isPendingUpdate(currentHash);
|
||||
}
|
||||
|
||||
currentPackage.putBoolean("isPending", isPendingUpdate);
|
||||
promise.resolve(currentPackage);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
promise.reject(e.getMessage());
|
||||
if (currentPackage.hasKey(codePushPackage.PACKAGE_HASH_KEY)) {
|
||||
String currentHash = currentPackage.getString(codePushPackage.PACKAGE_HASH_KEY);
|
||||
isPendingUpdate = CodePush.this.isPendingUpdate(currentHash);
|
||||
}
|
||||
|
||||
|
||||
currentPackage.putBoolean("isPending", isPendingUpdate);
|
||||
promise.resolve(currentPackage);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@@ -490,8 +453,8 @@ public class CodePush {
|
||||
|
||||
@ReactMethod
|
||||
public void getNewStatusReport(Promise promise) {
|
||||
// Check if there was a rollback that was not yet reported
|
||||
if (didRollback) {
|
||||
// Check if there was a rollback that was not yet reported
|
||||
JSONArray failedUpdates = getFailedUpdates();
|
||||
if (failedUpdates != null && failedUpdates.length() > 0) {
|
||||
try {
|
||||
@@ -499,7 +462,7 @@ public class CodePush {
|
||||
WritableMap lastFailedPackage = CodePushUtils.convertJsonObjectToWriteable(lastFailedPackageJSON);
|
||||
String lastFailedPackageIdentifier = getPackageStatusReportIdentifier(lastFailedPackage);
|
||||
if (lastFailedPackage != null && isDeploymentStatusNotYetReported(lastFailedPackageIdentifier)) {
|
||||
recordDeploymentStatusReported(lastFailedPackageIdentifier, DEPLOYMENT_FAILED_STATUS);
|
||||
recordDeploymentStatusReported(lastFailedPackageIdentifier);
|
||||
WritableNativeMap reportMap = new WritableNativeMap();
|
||||
reportMap.putMap("package", lastFailedPackage);
|
||||
reportMap.putString("status", DEPLOYMENT_FAILED_STATUS);
|
||||
@@ -510,36 +473,34 @@ public class CodePush {
|
||||
throw new CodePushUnknownException("Unable to read failed updates information stored in SharedPreferences.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the current CodePush package has been reported
|
||||
if (didUpdate) {
|
||||
try {
|
||||
WritableMap currentPackage = codePushPackage.getCurrentPackage();
|
||||
if (currentPackage != null) {
|
||||
String currentPackageIdentifier = getPackageStatusReportIdentifier(currentPackage);
|
||||
if (currentPackageIdentifier != null && isDeploymentStatusNotYetReported(currentPackageIdentifier)) {
|
||||
recordDeploymentStatusReported(currentPackageIdentifier, DEPLOYMENT_SUCCEEDED_STATUS);
|
||||
WritableNativeMap reportMap = new WritableNativeMap();
|
||||
reportMap.putMap("package", currentPackage);
|
||||
reportMap.putString("status", DEPLOYMENT_SUCCEEDED_STATUS);
|
||||
promise.resolve(reportMap);
|
||||
return;
|
||||
}
|
||||
} else if (didUpdate) {
|
||||
// Check if the current CodePush package has been reported
|
||||
WritableMap currentPackage = codePushPackage.getCurrentPackage();
|
||||
if (currentPackage != null) {
|
||||
String currentPackageIdentifier = getPackageStatusReportIdentifier(currentPackage);
|
||||
if (currentPackageIdentifier != null && isDeploymentStatusNotYetReported(currentPackageIdentifier)) {
|
||||
recordDeploymentStatusReported(currentPackageIdentifier);
|
||||
WritableNativeMap reportMap = new WritableNativeMap();
|
||||
reportMap.putMap("package", currentPackage);
|
||||
reportMap.putString("status", DEPLOYMENT_SUCCEEDED_STATUS);
|
||||
promise.resolve(reportMap);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String currentPackageHash = null;
|
||||
currentPackageHash = codePushPackage.getCurrentPackageHash();
|
||||
if (currentPackageHash == null) {
|
||||
// Check if the current appVersion has been reported.
|
||||
String binaryIdentifier = "" + getBinaryResourcesModifiedTime();
|
||||
if (isDeploymentStatusNotYetReported(binaryIdentifier)) {
|
||||
recordDeploymentStatusReported(binaryIdentifier);
|
||||
WritableNativeMap reportMap = new WritableNativeMap();
|
||||
reportMap.putString("appVersion", appVersion);
|
||||
promise.resolve(reportMap);
|
||||
return;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// If didUpdate is true, there should be a current package, so this should not happen.
|
||||
throw new CodePushUnknownException("Error getting current package after an update.", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the current appVersion has been reported.
|
||||
if (isDeploymentStatusNotYetReported(appVersion)) {
|
||||
recordDeploymentStatusReported(appVersion, DEPLOYMENT_SUCCEEDED_STATUS);
|
||||
WritableNativeMap reportMap = new WritableNativeMap();
|
||||
reportMap.putString("appVersion", appVersion);
|
||||
promise.resolve(reportMap);
|
||||
return;
|
||||
}
|
||||
|
||||
promise.resolve("");
|
||||
@@ -600,16 +561,11 @@ public class CodePush {
|
||||
|
||||
@ReactMethod
|
||||
public void isFirstRun(String packageHash, Promise promise) {
|
||||
try {
|
||||
boolean isFirstRun = didUpdate
|
||||
&& packageHash != null
|
||||
&& packageHash.length() > 0
|
||||
&& packageHash.equals(codePushPackage.getCurrentPackageHash());
|
||||
promise.resolve(isFirstRun);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
promise.reject(e.getMessage());
|
||||
}
|
||||
boolean isFirstRun = didUpdate
|
||||
&& packageHash != null
|
||||
&& packageHash.length() > 0
|
||||
&& packageHash.equals(codePushPackage.getCurrentPackageHash());
|
||||
promise.resolve(isFirstRun);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
|
||||
@@ -50,20 +50,28 @@ public class CodePushPackage {
|
||||
return CodePushUtils.appendPathComponent(getCodePushPath(), STATUS_FILE);
|
||||
}
|
||||
|
||||
public WritableMap getCurrentPackageInfo() throws IOException {
|
||||
public WritableMap getCurrentPackageInfo() {
|
||||
String statusFilePath = getStatusFilePath();
|
||||
if (!CodePushUtils.fileAtPathExists(statusFilePath)) {
|
||||
return new WritableNativeMap();
|
||||
}
|
||||
|
||||
return CodePushUtils.getWritableMapFromFile(statusFilePath);
|
||||
try {
|
||||
return CodePushUtils.getWritableMapFromFile(statusFilePath);
|
||||
} catch (IOException e) {
|
||||
throw new CodePushUnknownException("Error getting current package info" , e);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateCurrentPackageInfo(ReadableMap packageInfo) throws IOException {
|
||||
CodePushUtils.writeReadableMapToFile(packageInfo, getStatusFilePath());
|
||||
public void updateCurrentPackageInfo(ReadableMap packageInfo) {
|
||||
try {
|
||||
CodePushUtils.writeReadableMapToFile(packageInfo, getStatusFilePath());
|
||||
} catch (IOException e) {
|
||||
throw new CodePushUnknownException("Error updating current package info" , e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getCurrentPackageFolderPath() throws IOException {
|
||||
public String getCurrentPackageFolderPath() {
|
||||
WritableMap info = getCurrentPackageInfo();
|
||||
String packageHash = CodePushUtils.tryGetString(info, CURRENT_PACKAGE_KEY);
|
||||
if (packageHash == null) {
|
||||
@@ -73,7 +81,7 @@ public class CodePushPackage {
|
||||
return getPackageFolderPath(packageHash);
|
||||
}
|
||||
|
||||
public String getCurrentPackageBundlePath() throws IOException {
|
||||
public String getCurrentPackageBundlePath() {
|
||||
String packageFolder = getCurrentPackageFolderPath();
|
||||
if (packageFolder == null) {
|
||||
return null;
|
||||
@@ -86,17 +94,17 @@ public class CodePushPackage {
|
||||
return CodePushUtils.appendPathComponent(getCodePushPath(), packageHash);
|
||||
}
|
||||
|
||||
public String getCurrentPackageHash() throws IOException {
|
||||
public String getCurrentPackageHash() {
|
||||
WritableMap info = getCurrentPackageInfo();
|
||||
return CodePushUtils.tryGetString(info, CURRENT_PACKAGE_KEY);
|
||||
}
|
||||
|
||||
public String getPreviousPackageHash() throws IOException {
|
||||
public String getPreviousPackageHash() {
|
||||
WritableMap info = getCurrentPackageInfo();
|
||||
return CodePushUtils.tryGetString(info, PREVIOUS_PACKAGE_KEY);
|
||||
}
|
||||
|
||||
public WritableMap getCurrentPackage() throws IOException {
|
||||
public WritableMap getCurrentPackage() {
|
||||
String folderPath = getCurrentPackageFolderPath();
|
||||
if (folderPath == null) {
|
||||
return new WritableNativeMap();
|
||||
@@ -111,7 +119,7 @@ public class CodePushPackage {
|
||||
}
|
||||
}
|
||||
|
||||
public WritableMap getPackage(String packageHash) throws IOException {
|
||||
public WritableMap getPackage(String packageHash) {
|
||||
String folderPath = getPackageFolderPath(packageHash);
|
||||
String packageFilePath = CodePushUtils.appendPathComponent(folderPath, PACKAGE_FILE_NAME);
|
||||
try {
|
||||
@@ -185,7 +193,7 @@ public class CodePushPackage {
|
||||
updateCurrentPackageInfo(info);
|
||||
}
|
||||
|
||||
public void rollbackPackage() throws IOException {
|
||||
public void rollbackPackage() {
|
||||
WritableMap info = getCurrentPackageInfo();
|
||||
String currentPackageFolderPath = getCurrentPackageFolderPath();
|
||||
CodePushUtils.deleteDirectoryAtPath(currentPackageFolderPath);
|
||||
|
||||
@@ -31,6 +31,8 @@ module.exports = {
|
||||
};
|
||||
|
||||
function getHttpMethodName(verb) {
|
||||
// Note: This should stay in sync with the enum definition in
|
||||
// https://github.com/Microsoft/code-push/blob/master/sdk/script/acquisition-sdk.ts#L6
|
||||
return [
|
||||
"GET",
|
||||
"HEAD",
|
||||
|
||||
Reference in New Issue
Block a user