Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.

Commit e0b9266

Browse files
committed
Merge pull request #244 from Microsoft/bundle_message
Checking for null binary bundle
2 parents dfc2222 + 87e15c7 commit e0b9266

File tree

4 files changed

+450
-399
lines changed

4 files changed

+450
-399
lines changed

ios/CodePush/CodePush.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ failCallback:(void (^)(NSError *err))failCallback;
6767

6868
@end
6969

70+
@interface CodePushErrorUtils : NSObject
71+
72+
+ (NSError *)errorWithMessage:(NSString *)errorMessage;
73+
+ (BOOL)isCodePushError:(NSError *)error;
74+
75+
@end
76+
7077
@interface CodePushPackage : NSObject
7178

7279
+ (void)downloadPackage:(NSDictionary *)updatePackage
@@ -90,7 +97,6 @@ failCallback:(void (^)(NSError *err))failCallback;
9097
removePendingUpdate:(BOOL)removePendingUpdate
9198
error:(NSError **)error;
9299

93-
+ (BOOL)isCodePushError:(NSError *)err;
94100
+ (void)rollbackPackage;
95101

96102
// The below methods are only used during tests.

ios/CodePush/CodePush.m

Lines changed: 81 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#import "RCTAssert.h"
12
#import "RCTBridgeModule.h"
23
#import "RCTConvert.h"
34
#import "RCTEventDispatcher.h"
@@ -75,12 +76,15 @@ + (NSURL *)bundleURLForResource:(NSString *)resourceName
7576
{
7677
bundleResourceName = resourceName;
7778
bundleResourceExtension = resourceExtension;
79+
80+
[self ensureBinaryBundleExists];
81+
82+
NSString *logMessageFormat = @"Loading JS bundle from %@";
83+
7884
NSError *error;
7985
NSString *packageFile = [CodePushPackage getCurrentPackageBundlePath:&error];
8086
NSURL *binaryBundleURL = [self binaryBundleURL];
8187

82-
NSString *logMessageFormat = @"Loading JS bundle from %@";
83-
8488
if (error || !packageFile) {
8589
NSLog(logMessageFormat, binaryBundleURL);
8690
isRunningBinaryVersion = YES;
@@ -126,6 +130,23 @@ + (NSString *)getApplicationSupportDirectory
126130
return applicationSupportDirectory;
127131
}
128132

133+
+ (void)setDeploymentKey:(NSString *)deploymentKey
134+
{
135+
[CodePushConfig current].deploymentKey = deploymentKey;
136+
}
137+
138+
#pragma mark - Test-only methods
139+
140+
/*
141+
* WARNING: This cleans up all downloaded and pending updates.
142+
*/
143+
+ (void)clearUpdates
144+
{
145+
[CodePushPackage clearUpdates];
146+
[self removePendingUpdate];
147+
[self removeFailedUpdates];
148+
}
149+
129150
/*
130151
* This returns a boolean value indicating whether CodePush has
131152
* been set to run under a test configuration.
@@ -135,11 +156,6 @@ + (BOOL)isUsingTestConfiguration
135156
return testConfigurationFlag;
136157
}
137158

138-
+ (void)setDeploymentKey:(NSString *)deploymentKey
139-
{
140-
[CodePushConfig current].deploymentKey = deploymentKey;
141-
}
142-
143159
/*
144160
* This is used to enable an environment in which tests can be run.
145161
* Specifically, it flips a boolean flag that causes bundles to be
@@ -151,16 +167,6 @@ + (void)setUsingTestConfiguration:(BOOL)shouldUseTestConfiguration
151167
testConfigurationFlag = shouldUseTestConfiguration;
152168
}
153169

154-
/*
155-
* WARNING: This cleans up all downloaded and pending updates.
156-
*/
157-
+ (void)clearUpdates
158-
{
159-
[CodePushPackage clearUpdates];
160-
[self removePendingUpdate];
161-
[self removeFailedUpdates];
162-
}
163-
164170
#pragma mark - Private API methods
165171

166172
@synthesize bridge = _bridge;
@@ -190,6 +196,35 @@ - (void)dealloc
190196
[[NSNotificationCenter defaultCenter] removeObserver:self];
191197
}
192198

199+
/*
200+
* This method ensures that the app was packaged with a JS bundle
201+
* file, and if not, it throws the appropriate exception.
202+
*/
203+
+ (void)ensureBinaryBundleExists
204+
{
205+
if (![self binaryBundleURL]) {
206+
NSString *errorMessage;
207+
208+
#if TARGET_IPHONE_SIMULATOR
209+
errorMessage = @"React Native doesn't generate your app's JS bundle by default when deploying to the simulator. "
210+
"If you'd like to test CodePush using the simulator, you can do one of three things depending on your React "
211+
"Native version and/or preferred workflow:\n\n"
212+
213+
"1. Update your AppDelegate.m file to load the JS bundle from the packager instead of from CodePush. "
214+
"You can still test your CodePush update experience using this workflow (debug builds only).\n\n"
215+
216+
"2. Force the JS bundle to be generated in simulator builds by removing the if block that echoes "
217+
"\"Skipping bundling for Simulator platform\" in the \"node_modules/react-native/packager/react-native-xcode.sh\" file.\n\n"
218+
219+
"3. Deploy a release build to the simulator, which unlike debug builds, will generate the JS bundle (React Native >=0.22.0 only).";
220+
#else
221+
errorMessage = [NSString stringWithFormat:@"The specified JS bundle file wasn't found within the app's binary. Is \"%@\" the correct file name?", [bundleResourceName stringByAppendingPathExtension:bundleResourceExtension]];
222+
#endif
223+
224+
RCTFatal([CodePushErrorUtils errorWithMessage:errorMessage]);
225+
}
226+
}
227+
193228
- (instancetype)init
194229
{
195230
self = [super init];
@@ -403,7 +438,7 @@ - (void)applicationWillResignActive
403438
_lastResignedDate = [NSDate date];
404439
}
405440

406-
#pragma mark - JavaScript-exported module methods
441+
#pragma mark - JavaScript-exported module methods (Public)
407442

408443
/*
409444
* This is native-side of the RemotePackage.download method
@@ -450,7 +485,7 @@ - (void)applicationWillResignActive
450485
// The download failed
451486
failCallback:^(NSError *err) {
452487
dispatch_async(_methodQueue, ^{
453-
if ([CodePushPackage isCodePushError:err]) {
488+
if ([CodePushErrorUtils isCodePushError:err]) {
454489
[self saveFailedUpdate:mutableUpdatePackage];
455490
}
456491

@@ -613,6 +648,33 @@ - (void)applicationWillResignActive
613648
resolve(nil);
614649
}
615650

651+
/*
652+
* This method is the native side of the CodePush.restartApp() method.
653+
*/
654+
RCT_EXPORT_METHOD(restartApp:(BOOL)onlyIfUpdateIsPending)
655+
{
656+
// If this is an unconditional restart request, or there
657+
// is current pending update, then reload the app.
658+
if (!onlyIfUpdateIsPending || [self isPendingUpdate:nil]) {
659+
[self loadBundle];
660+
}
661+
}
662+
663+
#pragma mark - JavaScript-exported module methods (Private)
664+
665+
/*
666+
* This method is the native side of the CodePush.downloadAndReplaceCurrentBundle()
667+
* method, which replaces the current bundle with the one downloaded from
668+
* removeBundleUrl. It is only to be used during tests and no-ops if the test
669+
* configuration flag is not set.
670+
*/
671+
RCT_EXPORT_METHOD(downloadAndReplaceCurrentBundle:(NSString *)remoteBundleUrl)
672+
{
673+
if ([CodePush isUsingTestConfiguration]) {
674+
[CodePushPackage downloadAndReplaceCurrentBundle:remoteBundleUrl];
675+
}
676+
}
677+
616678
/*
617679
* This method is checks if a new status update exists (new version was installed,
618680
* or an update failed) and return its details (version label, status).
@@ -647,29 +709,4 @@ - (void)applicationWillResignActive
647709
resolve(nil);
648710
}
649711

650-
/*
651-
* This method is the native side of the CodePush.restartApp() method.
652-
*/
653-
RCT_EXPORT_METHOD(restartApp:(BOOL)onlyIfUpdateIsPending)
654-
{
655-
// If this is an unconditional restart request, or there
656-
// is current pending update, then reload the app.
657-
if (!onlyIfUpdateIsPending || [self isPendingUpdate:nil]) {
658-
[self loadBundle];
659-
}
660-
}
661-
662-
/*
663-
* This method is the native side of the CodePush.downloadAndReplaceCurrentBundle()
664-
* method, which replaces the current bundle with the one downloaded from
665-
* removeBundleUrl. It is only to be used during tests and no-ops if the test
666-
* configuration flag is not set.
667-
*/
668-
RCT_EXPORT_METHOD(downloadAndReplaceCurrentBundle:(NSString *)remoteBundleUrl)
669-
{
670-
if ([CodePush isUsingTestConfiguration]) {
671-
[CodePushPackage downloadAndReplaceCurrentBundle:remoteBundleUrl];
672-
}
673-
}
674-
675712
@end

ios/CodePush/CodePushErrorUtils.m

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#import "CodePush.h"
2+
3+
@implementation CodePushErrorUtils
4+
5+
static NSString *const CodePushErrorDomain = @"CodePushError";
6+
static const int CodePushErrorCode = -1;
7+
8+
+ (NSError *)errorWithMessage:(NSString *)errorMessage
9+
{
10+
return [NSError errorWithDomain:CodePushErrorDomain
11+
code:CodePushErrorCode
12+
userInfo:@{ NSLocalizedDescriptionKey: NSLocalizedString(errorMessage, nil) }];
13+
}
14+
15+
+ (BOOL)isCodePushError:(NSError *)err
16+
{
17+
return err != nil && [CodePushErrorDomain isEqualToString:err.domain];
18+
}
19+
20+
@end

0 commit comments

Comments
 (0)