diff --git a/CodePush.h b/CodePush.h index c147beb..f92158f 100644 --- a/CodePush.h +++ b/CodePush.h @@ -33,9 +33,15 @@ + (NSString *)getPackageFolderPath:(NSString *)packageHash; ++ (NSDictionary *)getCurrentPackage:(NSError **)error; + ++ (NSDictionary *)getPackage:(NSString *)packageHash + error:(NSError **)error; + + (void)downloadPackage:(NSDictionary *)updatePackage error:(NSError **)error; -+ (void)applyPackage:(NSString *)packageHash; ++ (void)applyPackage:(NSDictionary *)updatePackage + error:(NSError **)error; @end \ No newline at end of file diff --git a/CodePush.ios.js b/CodePush.ios.js index 373e5e3..3147b8c 100644 --- a/CodePush.ios.js +++ b/CodePush.ios.js @@ -69,7 +69,11 @@ function checkForUpdate() { return new Promise((resolve, reject) => { sdk.queryUpdateWithCurrentPackage(queryPackage, (err, update) => { if (err) return reject(err); - resolve(extend({}, update, packageMixins.remote)); + if (update) { + resolve(extend({}, update, packageMixins.remote)); + } else { + resolve(update); + } }); }); }); diff --git a/CodePush.m b/CodePush.m index 960700e..a7d2b1c 100644 --- a/CodePush.m +++ b/CodePush.m @@ -51,7 +51,6 @@ BOOL usingTestFolder = NO; return [packageFolderPath stringByAppendingPathComponent:appPackageName]; } - + (NSURL *) getNativeBundleURL { return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; @@ -59,21 +58,22 @@ BOOL usingTestFolder = NO; + (NSURL *) getBundleUrl { - NSFileManager *fileManager = [NSFileManager defaultManager]; - - NSString *bundlePath = [self getBundlePath]; - if ([fileManager fileExistsAtPath:bundlePath]) { - return [[NSURL alloc] initFileURLWithPath:bundlePath]; - } else { - return [self getNativeBundleURL]; + NSError *error; + NSString *packageFolder = [CodePushPackage getCurrentPackageFolderPath:&error]; + + if (error || !packageFolder) { + [self getNativeBundleURL]; } + + NSString *packageFile = [packageFolder stringByAppendingPathComponent:@"app.jsbundle"]; + return [[NSURL alloc] initFileURLWithPath:packageFile]; } -+ (void) loadBundle:(NSString*)rootComponent ++ (void) loadBundle { dispatch_async(dispatch_get_main_queue(), ^{ RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:[self getBundleUrl] - moduleName:rootComponent + moduleName:[CodePushConfig getRootComponent] launchOptions:nil]; UIViewController *rootViewController = [[UIViewController alloc] init]; @@ -103,10 +103,17 @@ RCT_EXPORT_METHOD(downloadUpdate:(NSDictionary*)updatePackage error:&err]; if (err) { - reject(err); - } else { - resolve([NSNull null]); + return reject(err); } + + NSDictionary *newPackage = [CodePushPackage getPackage:updatePackage[@"packageHash"] + error:&err]; + + if (err) { + return reject(err); + } + + resolve(newPackage); }); } @@ -114,75 +121,32 @@ RCT_EXPORT_METHOD(applyUpdate:(NSDictionary*)updatePackage resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - [CodePush loadBundle:[CodePushConfig getRootComponent]]; - resolve([NSNull null]); + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + NSError *error; + [CodePushPackage applyPackage:updatePackage + error:&error]; + + if (error) { + reject(error); + } + + [CodePush loadBundle]; + + //resolve([NSNull null]); + }); } -RCT_EXPORT_METHOD(writeToLocalPackage:(NSString*)packageJsonString - callback:(RCTResponseSenderBlock)callback) -{ - NSError *saveError; - - // Save the package info too. - NSString *packageFolderPath = [CodePush getPackageFolderPath]; - if (![[NSFileManager defaultManager] fileExistsAtPath:packageFolderPath]) { - [[NSFileManager defaultManager] createDirectoryAtPath:packageFolderPath withIntermediateDirectories:YES attributes:nil error:&saveError]; - } - - [packageJsonString writeToFile:[CodePush getPackagePath] - atomically:YES - encoding:NSUTF8StringEncoding - error:&saveError]; - - if (saveError) { - callback(@[RCTMakeError(@"Error saving file", saveError, [[NSDictionary alloc] initWithObjectsAndKeys:[CodePush getPackagePath],@"packagePath", nil])]); - } else { - callback(@[[NSNull null]]); - } - -} - -RCT_EXPORT_METHOD(removeLocalPackage: (RCTResponseSenderBlock)callback) -{ - NSError *error; - - // Save the package info too. - NSString *packagePath = [CodePush getPackagePath]; - if ([[NSFileManager defaultManager] fileExistsAtPath:packagePath]) { - [[NSFileManager defaultManager] removeItemAtPath:packagePath error: &error]; - } - - if (error) { - callback(@[RCTMakeError(@"Error saving file", error, [[NSDictionary alloc] initWithObjectsAndKeys:[CodePush getPackagePath],@"packagePath", nil])]); - } else { - callback(@[[NSNull null]]); - } -} - - RCT_EXPORT_METHOD(getCurrentPackage:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { - - NSString *path = [CodePush getPackagePath]; - dispatch_async(dispatch_get_main_queue(), ^{ - - NSError* readError; - NSString *content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&readError]; - if (readError) { - reject(readError); + NSError *error; + NSDictionary *package = [CodePushPackage getCurrentPackage:&error]; + if (error) { + reject(error); } else { - NSError * parseError; - NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding]; - NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data - options:kNilOptions - error:&parseError]; - if (parseError) { - reject(parseError); - } else { - resolve(json); - } + resolve(package); } }); } diff --git a/CodePushPackage.m b/CodePushPackage.m index 66e1f29..445fa56 100644 --- a/CodePushPackage.m +++ b/CodePushPackage.m @@ -2,21 +2,26 @@ @implementation CodePushPackage -NSString * const PackageInfoFile = @"packages.json"; +NSString * const StatusFile = @"codepush.json"; + (NSString *)getCodePushPath { return [NSHomeDirectory() stringByAppendingPathComponent:@"CodePush"]; } -+ (NSString *)getCurrentPackageInfoPath ++ (NSString *)getStatusFilePath { - return [[self getCodePushPath] stringByAppendingPathComponent:PackageInfoFile]; + return [[self getCodePushPath] stringByAppendingPathComponent:StatusFile]; } -+ (NSDictionary *)getCurrentPackageInfo:(NSError **)error ++ (NSMutableDictionary *)getCurrentPackageInfo:(NSError **)error { - NSString *content = [NSString stringWithContentsOfFile:[self getCurrentPackageInfoPath] + NSString *statusFilePath = [self getStatusFilePath]; + if (![[NSFileManager defaultManager] fileExistsAtPath:statusFilePath]) { + return [NSMutableDictionary dictionary]; + } + + NSString *content = [NSString stringWithContentsOfFile:statusFilePath encoding:NSUTF8StringEncoding error:error]; if (*error) { @@ -31,7 +36,7 @@ NSString * const PackageInfoFile = @"packages.json"; return NULL; } - return json; + return [json mutableCopy]; } + (void)updateCurrentPackageInfo:(NSDictionary *)packageInfo @@ -44,7 +49,7 @@ NSString * const PackageInfoFile = @"packages.json"; NSString *packageInfoString = [[NSString alloc] initWithData:packageInfoData encoding:NSUTF8StringEncoding]; - [packageInfoString writeToFile:[self getCurrentPackageInfoPath] + [packageInfoString writeToFile:[self getStatusFilePath] atomically:YES encoding:NSUTF8StringEncoding error:error]; @@ -58,7 +63,65 @@ NSString * const PackageInfoFile = @"packages.json"; return NULL; } - return [self getPackageFolderPath:info[@"currentPackage"]]; + NSString *packageHash = info[@"currentPackage"]; + + if (!packageHash) { + return NULL; + } + + return [self getPackageFolderPath:packageHash]; +} + + ++ (NSDictionary *)getCurrentPackage:(NSError **)error +{ + NSString *folderPath = [CodePushPackage getCurrentPackageFolderPath:error]; + if (!*error) { + if (!folderPath) { + return [NSDictionary dictionary]; + } + + 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; + } + } + + return NULL; +} + ++ (NSDictionary *)getPackage:(NSString *)packageHash + error:(NSError **)error +{ + NSString *folderPath = [self getPackageFolderPath:packageHash]; + + if (!folderPath) { + return [NSDictionary dictionary]; + } + + NSString *packageFilePath = [folderPath stringByAppendingPathComponent:@"app.json"]; + + NSString *content = [NSString stringWithContentsOfFile:packageFilePath + encoding:NSUTF8StringEncoding + error:error]; + if (!*error) { + NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary* jsonDict = [NSJSONSerialization JSONObjectWithData:data + options:kNilOptions + error:error]; + + return jsonDict; + } + + return NULL; } + (NSString *)getPackageFolderPath:(NSString *)packageHash @@ -78,7 +141,7 @@ NSString * const PackageInfoFile = @"packages.json"; error:error]; } - if (error) { + if (*error) { return; } @@ -86,7 +149,7 @@ NSString * const PackageInfoFile = @"packages.json"; NSString *updateContents = [[NSString alloc] initWithContentsOfURL:url encoding:NSUTF8StringEncoding error:error]; - if (error) { + if (*error) { return; } @@ -94,7 +157,7 @@ NSString * const PackageInfoFile = @"packages.json"; atomically:YES encoding:NSUTF8StringEncoding error:error]; - if (error) { + if (*error) { return; } @@ -102,7 +165,7 @@ NSString * const PackageInfoFile = @"packages.json"; options:0 error:error]; - if (error) { + if (*error) { return; } @@ -113,12 +176,13 @@ NSString * const PackageInfoFile = @"packages.json"; error:error]; } -+ (void)applyPackage:(NSString *)packageHash ++ (void)applyPackage:(NSDictionary *)updatePackage error:(NSError **)error { - NSDictionary *info = [self getCurrentPackageInfo:error]; + NSString *packageHash = updatePackage[@"packageHash" ]; + NSMutableDictionary *info = [self getCurrentPackageInfo:error]; - if (error) { + if (*error) { return; } diff --git a/Examples/CodePushDemoApp/index.ios.js b/Examples/CodePushDemoApp/index.ios.js index fc8cfbb..1845d7a 100644 --- a/Examples/CodePushDemoApp/index.ios.js +++ b/Examples/CodePushDemoApp/index.ios.js @@ -30,7 +30,7 @@ var CodePushDemoApp = React.createClass({ return { update: false }; }, handlePress: function() { - this.state.update.download((localPackage) => { + this.state.update.download().then((localPackage) => { localPackage.apply().done(); }); }, diff --git a/package-mixins.js b/package-mixins.js index e1dc94f..57afb5a 100644 --- a/package-mixins.js +++ b/package-mixins.js @@ -1,13 +1,28 @@ +var extend = require("extend"); + module.exports = (NativeCodePush) => { - return { - remote: { - download: function download() { - // Use the downloaded package info. Native code will save the package info - // so that the client knows what the current package version is. - return NativeCodePush.downloadUpdate(this); - } + var remote = { + download: function download() { + // Use the downloaded package info. Native code will save the package info + // so that the client knows what the current package version is. + return NativeCodePush.downloadUpdate(this) + .then((downloadedPackage) => { + return extend({}, downloadedPackage, local); + }); }, - local: { + abortDownload: function abortDownload() { + return NativeCodePush.abortDownload(this); } }; + + var local = { + apply: function apply(rollbackTimeout) { + return NativeCodePush.applyUpdate(this); + } + }; + + return { + remote: remote, + local: local + }; };