mirror of
https://github.com/zhigang1992/react-native-code-push.git
synced 2026-06-13 17:45:34 +08:00
report acquisition status
This commit is contained in:
124
CodePush.m
124
CodePush.m
@@ -15,9 +15,14 @@ RCT_EXPORT_MODULE()
|
||||
|
||||
static BOOL testConfigurationFlag = NO;
|
||||
|
||||
// These constants represent valid deployment statuses
|
||||
static NSString *const DeploymentSucceeded = @"DeploymentSucceeded";
|
||||
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";
|
||||
|
||||
// These keys are already "namespaced" by the PendingUpdateKey, so
|
||||
// their values don't need to be obfuscated to prevent collision with app data
|
||||
@@ -26,6 +31,8 @@ static NSString *const PendingUpdateIsLoadingKey = @"isLoading";
|
||||
|
||||
// These keys are used to inspect/augment the metadata
|
||||
// that is associated with an update's package.
|
||||
static NSString *const DeploymentKeyKey = @"deploymentKey";
|
||||
static NSString *const LabelKey = @"label";
|
||||
static NSString *const PackageHashKey = @"packageHash";
|
||||
static NSString *const PackageIsPendingKey = @"isPending";
|
||||
|
||||
@@ -70,7 +77,7 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
|
||||
NSString *packageAppVersion = [currentPackageMetadata objectForKey:@"appVersion"];
|
||||
|
||||
if ([binaryDate compare:packageDate] == NSOrderedAscending && [binaryAppVersion isEqualToString:packageAppVersion]) {
|
||||
if ([binaryDate compare:packageDate] == NSOrderedAscending && ([CodePush isUsingTestConfiguration] ||[binaryAppVersion isEqualToString:packageAppVersion])) {
|
||||
// Return package file because it is newer than the app store binary's JS bundle
|
||||
NSURL *packageUrl = [[NSURL alloc] initFileURLWithPath:packageFile];
|
||||
NSLog(logMessageFormat, packageUrl);
|
||||
@@ -148,6 +155,19 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (NSString *)getPackageStatusReportIdentifier:(NSDictionary *)package
|
||||
{
|
||||
// Because deploymentKeys can be dynamically switched, we use a
|
||||
// combination of the deploymentKey and label as the packageIdentifier.
|
||||
NSString *deploymentKey = [package objectForKey:DeploymentKeyKey];
|
||||
NSString *label = [package objectForKey:LabelKey];
|
||||
if (deploymentKey && label) {
|
||||
return [[deploymentKey stringByAppendingString:@":"] stringByAppendingString:label];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
self = [super init];
|
||||
@@ -185,6 +205,13 @@ 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method checks to see whether a specific package hash
|
||||
* has previously failed installation.
|
||||
@@ -193,7 +220,25 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
{
|
||||
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
|
||||
NSMutableArray *failedUpdates = [preferences objectForKey:FailedUpdatesKey];
|
||||
return (failedUpdates != nil && [failedUpdates containsObject:packageHash]);
|
||||
if (failedUpdates == nil) {
|
||||
return NO;
|
||||
} else {
|
||||
for (NSDictionary *failedPackage in failedUpdates)
|
||||
{
|
||||
// Type check is needed for backwards compatibility, where we used to just store
|
||||
// the failed package hash instead of the metadata. This only impacts "dev"
|
||||
// scenarios, since in production we clear out old information whenever a new
|
||||
// binary is applied.
|
||||
if ([failedPackage isKindOfClass:[NSDictionary class]]) {
|
||||
NSString *failedPackageHash = [failedPackage objectForKey:PackageHashKey];
|
||||
if ([packageHash isEqualToString:failedPackageHash]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -237,6 +282,22 @@ 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 synchronize];
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is used when an update has failed installation
|
||||
* and the app needs to be rolled back to the previous bundle.
|
||||
@@ -247,10 +308,10 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
- (void)rollbackPackage
|
||||
{
|
||||
NSError *error;
|
||||
NSString *packageHash = [CodePushPackage getCurrentPackageHash:&error];
|
||||
NSDictionary *failedPackage = [CodePushPackage getCurrentPackage:&error];
|
||||
|
||||
// Write the current package's hash to the "failed list"
|
||||
[self saveFailedUpdate:packageHash];
|
||||
// Write the current package's metadata to the "failed list"
|
||||
[self saveFailedUpdate:failedPackage];
|
||||
|
||||
// Rollback to the previous version and de-register the new update
|
||||
[CodePushPackage rollbackPackage];
|
||||
@@ -263,7 +324,7 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
* to store its hash so that it can be ignored on future
|
||||
* attempts to check the server for an update.
|
||||
*/
|
||||
- (void)saveFailedUpdate:(NSString *)packageHash
|
||||
- (void)saveFailedUpdate:(NSDictionary *)failedPackage
|
||||
{
|
||||
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
|
||||
NSMutableArray *failedUpdates = [preferences objectForKey:FailedUpdatesKey];
|
||||
@@ -275,7 +336,7 @@ static NSString *const PackageIsPendingKey = @"isPending";
|
||||
failedUpdates = [failedUpdates mutableCopy];
|
||||
}
|
||||
|
||||
[failedUpdates addObject:packageHash];
|
||||
[failedUpdates addObject:failedPackage];
|
||||
[preferences setObject:failedUpdates forKey:FailedUpdatesKey];
|
||||
[preferences synchronize];
|
||||
}
|
||||
@@ -467,6 +528,55 @@ RCT_EXPORT_METHOD(notifyApplicationReady:(RCTPromiseResolveBlock)resolve
|
||||
resolve([NSNull null]);
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is checks if a new status update exists (new version was installed,
|
||||
* or an update failed) and return its details (version label, status).
|
||||
*/
|
||||
RCT_EXPORT_METHOD(getNewStatusReport:(RCTPromiseResolveBlock)resolve
|
||||
rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Check if there was a rollback that was not yet reported
|
||||
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
|
||||
NSMutableArray *failedUpdates = [preferences objectForKey:FailedUpdatesKey];
|
||||
if (failedUpdates) {
|
||||
NSDictionary* lastFailedPackage = [failedUpdates lastObject];
|
||||
if (lastFailedPackage) {
|
||||
NSString* lastFailedPackageIdentifier = [self getPackageStatusReportIdentifier:lastFailedPackage];
|
||||
if (lastFailedPackageIdentifier && [self isDeploymentStatusNotYetReported:lastFailedPackageIdentifier]) {
|
||||
[self recordDeploymentStatusReported:lastFailedPackageIdentifier
|
||||
status:DeploymentFailed];
|
||||
resolve(@{ @"package": lastFailedPackage, @"status": DeploymentFailed });
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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];
|
||||
resolve(@{ @"package": currentPackage, @"status": DeploymentSucceeded });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
resolve([NSNull null]);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* This method is the native side of the CodePush.restartApp() method.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user