From ba24d9abc07c6afc57240b072e787e75890743dd Mon Sep 17 00:00:00 2001 From: Jonathan Carter Date: Sun, 13 Mar 2016 21:20:40 -0700 Subject: [PATCH] Refactoring error creation --- ios/CodePush/CodePush.h | 8 +- ios/CodePush/CodePush.m | 3 +- ios/CodePush/CodePushErrorUtils.m | 20 + ios/CodePush/CodePushPackage.m | 712 +++++++++++++++--------------- 4 files changed, 378 insertions(+), 365 deletions(-) create mode 100644 ios/CodePush/CodePushErrorUtils.m diff --git a/ios/CodePush/CodePush.h b/ios/CodePush/CodePush.h index 1760715..774fccf 100644 --- a/ios/CodePush/CodePush.h +++ b/ios/CodePush/CodePush.h @@ -67,6 +67,13 @@ failCallback:(void (^)(NSError *err))failCallback; @end +@interface CodePushErrorUtils : NSObject + ++ (NSError *)errorWithMessage:(NSString *)errorMessage; ++ (BOOL)isCodePushError:(NSError *)error; + +@end + @interface CodePushPackage : NSObject + (void)downloadPackage:(NSDictionary *)updatePackage @@ -90,7 +97,6 @@ failCallback:(void (^)(NSError *err))failCallback; removePendingUpdate:(BOOL)removePendingUpdate error:(NSError **)error; -+ (BOOL)isCodePushError:(NSError *)err; + (void)rollbackPackage; // The below methods are only used during tests. diff --git a/ios/CodePush/CodePush.m b/ios/CodePush/CodePush.m index 0e77307..55b8675 100644 --- a/ios/CodePush/CodePush.m +++ b/ios/CodePush/CodePush.m @@ -221,8 +221,7 @@ static NSString *bundleResourceName = @"main"; errorMessage = [NSString stringWithFormat:@"The specified JS bundle file wasn't found within the app's binary. Is \"%@\" the correct file name?", [bundleResourceName stringByAppendingPathExtension:bundleResourceExtension]]; #endif - RCTFatal([NSError errorWithDomain:@"CodePushError" code:-1 - userInfo:@{ NSLocalizedDescriptionKey: NSLocalizedString(errorMessage, nil) }]); + RCTFatal([CodePushErrorUtils errorWithMessage:errorMessage]); } } diff --git a/ios/CodePush/CodePushErrorUtils.m b/ios/CodePush/CodePushErrorUtils.m new file mode 100644 index 0000000..97dede4 --- /dev/null +++ b/ios/CodePush/CodePushErrorUtils.m @@ -0,0 +1,20 @@ +#import "CodePush.h" + +@implementation CodePushErrorUtils + +static NSString *const CodePushErrorDomain = @"CodePushError"; +static const int CodePushErrorCode = -1; + ++ (NSError *)errorWithMessage:(NSString *)errorMessage +{ + return [NSError errorWithDomain:CodePushErrorDomain + code:CodePushErrorCode + userInfo:@{ NSLocalizedDescriptionKey: NSLocalizedString(errorMessage, nil) }]; +} + ++ (BOOL)isCodePushError:(NSError *)err +{ + return err != nil && [CodePushErrorDomain isEqualToString:err.domain]; +} + +@end \ No newline at end of file diff --git a/ios/CodePush/CodePushPackage.m b/ios/CodePush/CodePushPackage.m index 979bd34..a0658cc 100644 --- a/ios/CodePush/CodePushPackage.m +++ b/ios/CodePush/CodePushPackage.m @@ -3,15 +3,273 @@ @implementation CodePushPackage -NSString * const CodePushErrorDomain = @"CodePushError"; -const int CodePushErrorCode = -1; -NSString * const DiffManifestFileName = @"hotcodepush.json"; -NSString * const DownloadFileName = @"download.zip"; -NSString * const RelativeBundlePathKey = @"bundlePath"; -NSString * const StatusFile = @"codepush.json"; -NSString * const UpdateBundleFileName = @"app.jsbundle"; -NSString * const UnzippedFolderName = @"unzipped"; +#pragma mark - Private constants +static NSString *const DiffManifestFileName = @"hotcodepush.json"; +static NSString *const DownloadFileName = @"download.zip"; +static NSString *const RelativeBundlePathKey = @"bundlePath"; +static NSString *const StatusFile = @"codepush.json"; +static NSString *const UpdateBundleFileName = @"app.jsbundle"; +static NSString *const UnzippedFolderName = @"unzipped"; + +#pragma mark - Public methods + ++ (void)clearUpdates +{ + [[NSFileManager defaultManager] removeItemAtPath:[self getCodePushPath] error:nil]; + [[NSFileManager defaultManager] removeItemAtPath:[self getStatusFilePath] error:nil]; +} + ++ (void)downloadAndReplaceCurrentBundle:(NSString *)remoteBundleUrl +{ + NSURL *urlRequest = [NSURL URLWithString:remoteBundleUrl]; + NSError *error = nil; + NSString *downloadedBundle = [NSString stringWithContentsOfURL:urlRequest + encoding:NSUTF8StringEncoding + error:&error]; + + if (error) { + NSLog(@"Error downloading from URL %@", remoteBundleUrl); + } else { + NSString *currentPackageBundlePath = [self getCurrentPackageBundlePath:&error]; + [downloadedBundle writeToFile:currentPackageBundlePath + atomically:YES + encoding:NSUTF8StringEncoding + error:&error]; + } +} + ++ (void)downloadPackage:(NSDictionary *)updatePackage + expectedBundleFileName:(NSString *)expectedBundleFileName + progressCallback:(void (^)(long long, long long))progressCallback + doneCallback:(void (^)())doneCallback + failCallback:(void (^)(NSError *err))failCallback +{ + NSString *newUpdateHash = updatePackage[@"packageHash"]; + NSString *newUpdateFolderPath = [self getPackageFolderPath:newUpdateHash]; + NSString *newUpdateMetadataPath = [newUpdateFolderPath stringByAppendingPathComponent:@"app.json"]; + NSError *error; + + if ([[NSFileManager defaultManager] fileExistsAtPath:newUpdateFolderPath]) { + // This removes any stale data in newUpdateFolderPath that could have been left + // uncleared due to a crash or error during the download or install process. + [[NSFileManager defaultManager] removeItemAtPath:newUpdateFolderPath + error:&error]; + } else if (![[NSFileManager defaultManager] fileExistsAtPath:[self getCodePushPath]]) { + [[NSFileManager defaultManager] createDirectoryAtPath:[self getCodePushPath] + withIntermediateDirectories:YES + attributes:nil + error:&error]; + } + + if (error) { + return failCallback(error); + } + + NSString *downloadFilePath = [self getDownloadFilePath]; + NSString *bundleFilePath = [newUpdateFolderPath stringByAppendingPathComponent:UpdateBundleFileName]; + + CodePushDownloadHandler *downloadHandler = [[CodePushDownloadHandler alloc] + init:downloadFilePath + progressCallback:progressCallback + doneCallback:^(BOOL isZip) { + NSError *error = nil; + NSString * unzippedFolderPath = [CodePushPackage getUnzippedFolderPath]; + NSMutableDictionary * mutableUpdatePackage = [updatePackage mutableCopy]; + if (isZip) { + if ([[NSFileManager defaultManager] fileExistsAtPath:unzippedFolderPath]) { + // This removes any unzipped download data that could have been left + // uncleared due to a crash or error during the download process. + [[NSFileManager defaultManager] removeItemAtPath:unzippedFolderPath + error:&error]; + if (error) { + failCallback(error); + return; + } + } + + NSError *nonFailingError = nil; + [SSZipArchive unzipFileAtPath:downloadFilePath + toDestination:unzippedFolderPath]; + [[NSFileManager defaultManager] removeItemAtPath:downloadFilePath + error:&nonFailingError]; + if (nonFailingError) { + NSLog(@"Error deleting downloaded file: %@", nonFailingError); + nonFailingError = nil; + } + + NSString *diffManifestFilePath = [unzippedFolderPath stringByAppendingPathComponent:DiffManifestFileName]; + BOOL isDiffUpdate = [[NSFileManager defaultManager] fileExistsAtPath:diffManifestFilePath]; + + if (isDiffUpdate) { + // Copy the current package to the new package. + NSString *currentPackageFolderPath = [self getCurrentPackageFolderPath:&error]; + if (error) { + failCallback(error); + return; + } + + if (currentPackageFolderPath == nil) { + // Currently running the binary version, copy files from the bundled resources + NSString *newUpdateCodePushPath = [newUpdateFolderPath stringByAppendingPathComponent:[CodePushUpdateUtils manifestFolderPrefix]]; + [[NSFileManager defaultManager] createDirectoryAtPath:newUpdateCodePushPath + withIntermediateDirectories:YES + attributes:nil + error:&error]; + if (error) { + failCallback(error); + return; + } + + [[NSFileManager defaultManager] copyItemAtPath:[self getBinaryAssetsPath] + toPath:[newUpdateCodePushPath stringByAppendingPathComponent:[CodePushUpdateUtils assetsFolderName]] + error:&error]; + if (error) { + failCallback(error); + return; + } + + [[NSFileManager defaultManager] copyItemAtPath:[[CodePush binaryBundleURL] path] + toPath:[newUpdateCodePushPath stringByAppendingPathComponent:[[CodePush binaryBundleURL] lastPathComponent]] + error:&error]; + if (error) { + failCallback(error); + return; + } + } else { + [[NSFileManager defaultManager] copyItemAtPath:currentPackageFolderPath + toPath:newUpdateFolderPath + error:&error]; + if (error) { + failCallback(error); + return; + } + } + + // Delete files mentioned in the manifest. + NSString *manifestContent = [NSString stringWithContentsOfFile:diffManifestFilePath + encoding:NSUTF8StringEncoding + error:&error]; + if (error) { + failCallback(error); + return; + } + + NSData *data = [manifestContent dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary *manifestJSON = [NSJSONSerialization JSONObjectWithData:data + options:kNilOptions + error:&error]; + NSArray *deletedFiles = manifestJSON[@"deletedFiles"]; + for (NSString *deletedFileName in deletedFiles) { + NSString *absoluteDeletedFilePath = [newUpdateFolderPath stringByAppendingPathComponent:deletedFileName]; + if ([[NSFileManager defaultManager] fileExistsAtPath:absoluteDeletedFilePath]) { + [[NSFileManager defaultManager] removeItemAtPath:absoluteDeletedFilePath + error:&error]; + if (error) { + failCallback(error); + return; + } + } + } + + [[NSFileManager defaultManager] removeItemAtPath:diffManifestFilePath + error:&error]; + if (error) { + failCallback(error); + return; + } + } + + [CodePushUpdateUtils copyEntriesInFolder:unzippedFolderPath + destFolder:newUpdateFolderPath + error:&error]; + if (error) { + failCallback(error); + return; + } + + [[NSFileManager defaultManager] removeItemAtPath:unzippedFolderPath + error:&nonFailingError]; + if (nonFailingError) { + NSLog(@"Error deleting downloaded file: %@", nonFailingError); + nonFailingError = nil; + } + + NSString *relativeBundlePath = [CodePushUpdateUtils findMainBundleInFolder:newUpdateFolderPath + expectedFileName:expectedBundleFileName + error:&error]; + + if (error) { + failCallback(error); + return; + } + + if (relativeBundlePath) { + [mutableUpdatePackage setValue:relativeBundlePath forKey:RelativeBundlePathKey]; + } else { + error = [CodePushErrorUtils errorWithMessage:@"Update is invalid - no files with extension .jsbundle or .bundle were found in the update package."]; + + failCallback(error); + return; + } + + if ([[NSFileManager defaultManager] fileExistsAtPath:newUpdateMetadataPath]) { + [[NSFileManager defaultManager] removeItemAtPath:newUpdateMetadataPath + error:&error]; + if (error) { + failCallback(error); + return; + } + } + + if (isDiffUpdate && ![CodePushUpdateUtils verifyHashForDiffUpdate:newUpdateFolderPath + expectedHash:newUpdateHash + error:&error]) { + if (error) { + failCallback(error); + return; + } + + error = [CodePushErrorUtils errorWithMessage:@"The update contents failed the data integrity check."]; + + failCallback(error); + return; + } + } else { + [[NSFileManager defaultManager] createDirectoryAtPath:newUpdateFolderPath + withIntermediateDirectories:YES + attributes:nil + error:&error]; + [[NSFileManager defaultManager] moveItemAtPath:downloadFilePath + toPath:bundleFilePath + error:&error]; + if (error) { + failCallback(error); + return; + } + } + + NSData *updateSerializedData = [NSJSONSerialization dataWithJSONObject:mutableUpdatePackage + options:0 + error:&error]; + NSString *packageJsonString = [[NSString alloc] initWithData:updateSerializedData + encoding:NSUTF8StringEncoding]; + + [packageJsonString writeToFile:newUpdateMetadataPath + atomically:YES + encoding:NSUTF8StringEncoding + error:&error]; + if (error) { + failCallback(error); + } else { + doneCallback(); + } + } + + failCallback:failCallback]; + + [downloadHandler download:updatePackage[@"downloadUrl"]]; +} + (NSString *)getBinaryAssetsPath { @@ -28,77 +286,29 @@ NSString * const UnzippedFolderName = @"unzipped"; return codePushPath; } -+ (NSString *)getDownloadFilePath ++ (NSDictionary *)getCurrentPackage:(NSError **)error { - return [[self getCodePushPath] stringByAppendingPathComponent:DownloadFileName]; -} - -+ (NSString *)getUnzippedFolderPath -{ - return [[self getCodePushPath] stringByAppendingPathComponent:UnzippedFolderName]; -} - -+ (NSString *)getStatusFilePath -{ - return [[self getCodePushPath] stringByAppendingPathComponent:StatusFile]; -} - -+ (NSMutableDictionary *)getCurrentPackageInfo:(NSError **)error -{ - NSString *statusFilePath = [self getStatusFilePath]; - if (![[NSFileManager defaultManager] fileExistsAtPath:statusFilePath]) { - return [NSMutableDictionary dictionary]; + NSString *folderPath = [CodePushPackage getCurrentPackageFolderPath:error]; + if (!*error) { + if (!folderPath) { + return nil; + } + + NSString *packagePath = [folderPath stringByAppendingPathComponent:@"app.json"]; + NSString *content = [NSString stringWithContentsOfFile:packagePath + encoding:NSUTF8StringEncoding + error:error]; + if (!*error) { + NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary* jsonDict = [NSJSONSerialization JSONObjectWithData:data + options:kNilOptions + error:error]; + + return jsonDict; + } } - NSString *content = [NSString stringWithContentsOfFile:statusFilePath - encoding:NSUTF8StringEncoding - error:error]; - if (*error) { - return NULL; - } - - NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding]; - NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data - options:kNilOptions - error:error]; - if (*error) { - return NULL; - } - - return [json mutableCopy]; -} - -+ (void)updateCurrentPackageInfo:(NSDictionary *)packageInfo - error:(NSError **)error -{ - - NSData *packageInfoData = [NSJSONSerialization dataWithJSONObject:packageInfo - options:0 - error:error]; - - NSString *packageInfoString = [[NSString alloc] initWithData:packageInfoData - encoding:NSUTF8StringEncoding]; - [packageInfoString writeToFile:[self getStatusFilePath] - atomically:YES - encoding:NSUTF8StringEncoding - error:error]; -} - -+ (NSString *)getCurrentPackageFolderPath:(NSError **)error -{ - NSDictionary *info = [self getCurrentPackageInfo:error]; - - if (*error) { - return NULL; - } - - NSString *packageHash = info[@"currentPackage"]; - - if (!packageHash) { - return NULL; - } - - return [self getPackageFolderPath:packageHash]; + return nil; } + (NSString *)getCurrentPackageBundlePath:(NSError **)error @@ -133,39 +343,51 @@ NSString * const UnzippedFolderName = @"unzipped"; return info[@"currentPackage"]; } -+ (NSString *)getPreviousPackageHash:(NSError **)error ++ (NSString *)getCurrentPackageFolderPath:(NSError **)error { NSDictionary *info = [self getCurrentPackageInfo:error]; + if (*error) { return NULL; } - return info[@"previousPackage"]; -} - -+ (NSDictionary *)getCurrentPackage:(NSError **)error -{ - NSString *folderPath = [CodePushPackage getCurrentPackageFolderPath:error]; - if (!*error) { - if (!folderPath) { - return nil; - } - - NSString *packagePath = [folderPath stringByAppendingPathComponent:@"app.json"]; - NSString *content = [NSString stringWithContentsOfFile:packagePath - encoding:NSUTF8StringEncoding - error:error]; - if (!*error) { - NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding]; - NSDictionary* jsonDict = [NSJSONSerialization JSONObjectWithData:data - options:kNilOptions - error:error]; - - return jsonDict; - } + NSString *packageHash = info[@"currentPackage"]; + + if (!packageHash) { + return NULL; } - return nil; + return [self getPackageFolderPath:packageHash]; +} + ++ (NSMutableDictionary *)getCurrentPackageInfo:(NSError **)error +{ + NSString *statusFilePath = [self getStatusFilePath]; + if (![[NSFileManager defaultManager] fileExistsAtPath:statusFilePath]) { + return [NSMutableDictionary dictionary]; + } + + NSString *content = [NSString stringWithContentsOfFile:statusFilePath + encoding:NSUTF8StringEncoding + error:error]; + if (*error) { + return NULL; + } + + NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data + options:kNilOptions + error:error]; + if (*error) { + return NULL; + } + + return [json mutableCopy]; +} + ++ (NSString *)getDownloadFilePath +{ + return [[self getCodePushPath] stringByAppendingPathComponent:DownloadFileName]; } + (NSDictionary *)getPackage:(NSString *)packageHash @@ -199,249 +421,24 @@ NSString * const UnzippedFolderName = @"unzipped"; return [[self getCodePushPath] stringByAppendingPathComponent:packageHash]; } -+ (BOOL)isCodePushError:(NSError *)err ++ (NSString *)getPreviousPackageHash:(NSError **)error { - return err != nil && [CodePushErrorDomain isEqualToString:err.domain]; + NSDictionary *info = [self getCurrentPackageInfo:error]; + if (*error) { + return NULL; + } + + return info[@"previousPackage"]; } -+ (void)downloadPackage:(NSDictionary *)updatePackage - expectedBundleFileName:(NSString *)expectedBundleFileName - progressCallback:(void (^)(long long, long long))progressCallback - doneCallback:(void (^)())doneCallback - failCallback:(void (^)(NSError *err))failCallback ++ (NSString *)getStatusFilePath { - NSString *newUpdateHash = updatePackage[@"packageHash"]; - NSString *newUpdateFolderPath = [self getPackageFolderPath:newUpdateHash]; - NSString *newUpdateMetadataPath = [newUpdateFolderPath stringByAppendingPathComponent:@"app.json"]; - NSError *error; - - if ([[NSFileManager defaultManager] fileExistsAtPath:newUpdateFolderPath]) { - // This removes any stale data in newUpdateFolderPath that could have been left - // uncleared due to a crash or error during the download or install process. - [[NSFileManager defaultManager] removeItemAtPath:newUpdateFolderPath - error:&error]; - } else if (![[NSFileManager defaultManager] fileExistsAtPath:[self getCodePushPath]]) { - [[NSFileManager defaultManager] createDirectoryAtPath:[self getCodePushPath] - withIntermediateDirectories:YES - attributes:nil - error:&error]; - } - - if (error) { - return failCallback(error); - } - - NSString *downloadFilePath = [self getDownloadFilePath]; - NSString *bundleFilePath = [newUpdateFolderPath stringByAppendingPathComponent:UpdateBundleFileName]; - - CodePushDownloadHandler *downloadHandler = [[CodePushDownloadHandler alloc] - init:downloadFilePath - progressCallback:progressCallback - doneCallback:^(BOOL isZip) { - NSError *error = nil; - NSString * unzippedFolderPath = [CodePushPackage getUnzippedFolderPath]; - NSMutableDictionary * mutableUpdatePackage = [updatePackage mutableCopy]; - if (isZip) { - if ([[NSFileManager defaultManager] fileExistsAtPath:unzippedFolderPath]) { - // This removes any unzipped download data that could have been left - // uncleared due to a crash or error during the download process. - [[NSFileManager defaultManager] removeItemAtPath:unzippedFolderPath - error:&error]; - if (error) { - failCallback(error); - return; - } - } - - NSError *nonFailingError = nil; - [SSZipArchive unzipFileAtPath:downloadFilePath - toDestination:unzippedFolderPath]; - [[NSFileManager defaultManager] removeItemAtPath:downloadFilePath - error:&nonFailingError]; - if (nonFailingError) { - NSLog(@"Error deleting downloaded file: %@", nonFailingError); - nonFailingError = nil; - } - - NSString *diffManifestFilePath = [unzippedFolderPath stringByAppendingPathComponent:DiffManifestFileName]; - BOOL isDiffUpdate = [[NSFileManager defaultManager] fileExistsAtPath:diffManifestFilePath]; - - if (isDiffUpdate) { - // Copy the current package to the new package. - NSString *currentPackageFolderPath = [self getCurrentPackageFolderPath:&error]; - if (error) { - failCallback(error); - return; - } - - if (currentPackageFolderPath == nil) { - // Currently running the binary version, copy files from the bundled resources - NSString *newUpdateCodePushPath = [newUpdateFolderPath stringByAppendingPathComponent:[CodePushUpdateUtils manifestFolderPrefix]]; - [[NSFileManager defaultManager] createDirectoryAtPath:newUpdateCodePushPath - withIntermediateDirectories:YES - attributes:nil - error:&error]; - if (error) { - failCallback(error); - return; - } - - [[NSFileManager defaultManager] copyItemAtPath:[self getBinaryAssetsPath] - toPath:[newUpdateCodePushPath stringByAppendingPathComponent:[CodePushUpdateUtils assetsFolderName]] - error:&error]; - if (error) { - failCallback(error); - return; - } - - [[NSFileManager defaultManager] copyItemAtPath:[[CodePush binaryBundleURL] path] - toPath:[newUpdateCodePushPath stringByAppendingPathComponent:[[CodePush binaryBundleURL] lastPathComponent]] - error:&error]; - if (error) { - failCallback(error); - return; - } - } else { - [[NSFileManager defaultManager] copyItemAtPath:currentPackageFolderPath - toPath:newUpdateFolderPath - error:&error]; - if (error) { - failCallback(error); - return; - } - } - - // Delete files mentioned in the manifest. - NSString *manifestContent = [NSString stringWithContentsOfFile:diffManifestFilePath - encoding:NSUTF8StringEncoding - error:&error]; - if (error) { - failCallback(error); - return; - } - - NSData *data = [manifestContent dataUsingEncoding:NSUTF8StringEncoding]; - NSDictionary *manifestJSON = [NSJSONSerialization JSONObjectWithData:data - options:kNilOptions - error:&error]; - NSArray *deletedFiles = manifestJSON[@"deletedFiles"]; - for (NSString *deletedFileName in deletedFiles) { - NSString *absoluteDeletedFilePath = [newUpdateFolderPath stringByAppendingPathComponent:deletedFileName]; - if ([[NSFileManager defaultManager] fileExistsAtPath:absoluteDeletedFilePath]) { - [[NSFileManager defaultManager] removeItemAtPath:absoluteDeletedFilePath - error:&error]; - if (error) { - failCallback(error); - return; - } - } - } - - [[NSFileManager defaultManager] removeItemAtPath:diffManifestFilePath - error:&error]; - if (error) { - failCallback(error); - return; - } - } - - [CodePushUpdateUtils copyEntriesInFolder:unzippedFolderPath - destFolder:newUpdateFolderPath - error:&error]; - if (error) { - failCallback(error); - return; - } - - [[NSFileManager defaultManager] removeItemAtPath:unzippedFolderPath - error:&nonFailingError]; - if (nonFailingError) { - NSLog(@"Error deleting downloaded file: %@", nonFailingError); - nonFailingError = nil; - } - - NSString *relativeBundlePath = [CodePushUpdateUtils findMainBundleInFolder:newUpdateFolderPath - expectedFileName:expectedBundleFileName - error:&error]; - - if (error) { - failCallback(error); - return; - } - - if (relativeBundlePath) { - [mutableUpdatePackage setValue:relativeBundlePath forKey:RelativeBundlePathKey]; - } else { - error = [[NSError alloc] initWithDomain:CodePushErrorDomain - code:CodePushErrorCode - userInfo:@{ - NSLocalizedDescriptionKey: - NSLocalizedString(@"Update is invalid - no files with extension .jsbundle or .bundle were found in the update package.", nil) - }]; - failCallback(error); - return; - } - - if ([[NSFileManager defaultManager] fileExistsAtPath:newUpdateMetadataPath]) { - [[NSFileManager defaultManager] removeItemAtPath:newUpdateMetadataPath - error:&error]; - if (error) { - failCallback(error); - return; - } - } - - if (isDiffUpdate && ![CodePushUpdateUtils verifyHashForDiffUpdate:newUpdateFolderPath - expectedHash:newUpdateHash - error:&error]) { - if (error) { - failCallback(error); - return; - } - - error = [[NSError alloc] initWithDomain:CodePushErrorDomain - code:CodePushErrorCode - userInfo:@{ - NSLocalizedDescriptionKey: - NSLocalizedString(@"The update contents failed the data integrity check.", nil) - }]; - failCallback(error); - return; - } - } else { - [[NSFileManager defaultManager] createDirectoryAtPath:newUpdateFolderPath - withIntermediateDirectories:YES - attributes:nil - error:&error]; - [[NSFileManager defaultManager] moveItemAtPath:downloadFilePath - toPath:bundleFilePath - error:&error]; - if (error) { - failCallback(error); - return; - } - } - - NSData *updateSerializedData = [NSJSONSerialization dataWithJSONObject:mutableUpdatePackage - options:0 - error:&error]; - NSString *packageJsonString = [[NSString alloc] initWithData:updateSerializedData - encoding:NSUTF8StringEncoding]; - - [packageJsonString writeToFile:newUpdateMetadataPath - atomically:YES - encoding:NSUTF8StringEncoding - error:&error]; - if (error) { - failCallback(error); - } else { - doneCallback(); - } - } + return [[self getCodePushPath] stringByAppendingPathComponent:StatusFile]; +} - failCallback:failCallback]; - - [downloadHandler download:updatePackage[@"downloadUrl"]]; ++ (NSString *)getUnzippedFolderPath +{ + return [[self getCodePushPath] stringByAppendingPathComponent:UnzippedFolderName]; } + (void)installPackage:(NSDictionary *)updatePackage @@ -482,7 +479,7 @@ NSString * const UnzippedFolderName = @"unzipped"; } [info setValue:packageHash forKey:@"currentPackage"]; - + [self updateCurrentPackageInfo:info error:error]; } @@ -513,29 +510,20 @@ NSString * const UnzippedFolderName = @"unzipped"; [self updateCurrentPackageInfo:info error:&error]; } -+ (void)downloadAndReplaceCurrentBundle:(NSString *)remoteBundleUrl ++ (void)updateCurrentPackageInfo:(NSDictionary *)packageInfo + error:(NSError **)error { - NSURL *urlRequest = [NSURL URLWithString:remoteBundleUrl]; - NSError *error = nil; - NSString *downloadedBundle = [NSString stringWithContentsOfURL:urlRequest - encoding:NSUTF8StringEncoding - error:&error]; - if (error) { - NSLog(@"Error downloading from URL %@", remoteBundleUrl); - } else { - NSString *currentPackageBundlePath = [self getCurrentPackageBundlePath:&error]; - [downloadedBundle writeToFile:currentPackageBundlePath - atomically:YES - encoding:NSUTF8StringEncoding - error:&error]; - } + NSData *packageInfoData = [NSJSONSerialization dataWithJSONObject:packageInfo + options:0 + error:error]; + + NSString *packageInfoString = [[NSString alloc] initWithData:packageInfoData + encoding:NSUTF8StringEncoding]; + [packageInfoString writeToFile:[self getStatusFilePath] + atomically:YES + encoding:NSUTF8StringEncoding + error:error]; } -+ (void)clearUpdates -{ - [[NSFileManager defaultManager] removeItemAtPath:[self getCodePushPath] error:nil]; - [[NSFileManager defaultManager] removeItemAtPath:[self getStatusFilePath] error:nil]; -} - -@end +@end \ No newline at end of file