mirror of
https://github.com/zhigang1992/react-native-code-push.git
synced 2026-06-20 11:58:43 +08:00
Refactoring error creation
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
20
ios/CodePush/CodePushErrorUtils.m
Normal file
20
ios/CodePush/CodePushErrorUtils.m
Normal file
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user