@@ -76,32 +76,32 @@ + (NSURL *)bundleURLForResource:(NSString *)resourceName
7676{
7777 bundleResourceName = resourceName;
7878 bundleResourceExtension = resourceExtension;
79-
79+
8080 [self ensureBinaryBundleExists ];
81-
81+
8282 NSString *logMessageFormat = @" Loading JS bundle from %@ " ;
83-
83+
8484 NSError *error;
8585 NSString *packageFile = [CodePushPackage getCurrentPackageBundlePath: &error];
8686 NSURL *binaryBundleURL = [self binaryBundleURL ];
87-
87+
8888 if (error || !packageFile) {
8989 NSLog (logMessageFormat, binaryBundleURL);
9090 isRunningBinaryVersion = YES ;
9191 return binaryBundleURL;
9292 }
93-
93+
9494 NSString *binaryAppVersion = [[CodePushConfig current ] appVersion ];
9595 NSDictionary *currentPackageMetadata = [CodePushPackage getCurrentPackage: &error];
9696 if (error || !currentPackageMetadata) {
9797 NSLog (logMessageFormat, binaryBundleURL);
9898 isRunningBinaryVersion = YES ;
9999 return binaryBundleURL;
100100 }
101-
101+
102102 NSString *packageDate = [currentPackageMetadata objectForKey: BinaryBundleDateKey];
103103 NSString *packageAppVersion = [currentPackageMetadata objectForKey: AppVersionKey];
104-
104+
105105 if ([[CodePushUpdateUtils modifiedDateStringOfFileAtURL: binaryBundleURL] isEqualToString: packageDate] && ([CodePush isUsingTestConfiguration ] ||[binaryAppVersion isEqualToString: packageAppVersion])) {
106106 // Return package file because it is newer than the app store binary's JS bundle
107107 NSURL *packageUrl = [[NSURL alloc ] initFileURLWithPath: packageFile];
@@ -113,11 +113,11 @@ + (NSURL *)bundleURLForResource:(NSString *)resourceName
113113#ifndef DEBUG
114114 isRelease = YES ;
115115#endif
116-
116+
117117 if (isRelease || ![binaryAppVersion isEqualToString: packageAppVersion]) {
118118 [CodePush clearUpdates ];
119119 }
120-
120+
121121 NSLog (logMessageFormat, binaryBundleURL);
122122 isRunningBinaryVersion = YES ;
123123 return binaryBundleURL;
@@ -172,6 +172,29 @@ + (void)setUsingTestConfiguration:(BOOL)shouldUseTestConfiguration
172172@synthesize bridge = _bridge;
173173@synthesize methodQueue = _methodQueue;
174174
175+ /*
176+ * This method is used to clear updates that are installed
177+ * under a different app version and hence don't apply anymore,
178+ * during a debug run configuration and when the bridge is
179+ * running the JS bundle from the dev server.
180+ */
181+ - (void )clearDebugUpdates
182+ {
183+ dispatch_async (dispatch_get_main_queue (), ^{
184+ if ([_bridge.bundleURL.scheme hasPrefix: @" http" ]) {
185+ NSError *error;
186+ NSString *binaryAppVersion = [[CodePushConfig current ] appVersion ];
187+ NSDictionary *currentPackageMetadata = [CodePushPackage getCurrentPackage: &error];
188+ if (currentPackageMetadata) {
189+ NSString *packageAppVersion = [currentPackageMetadata objectForKey: AppVersionKey];
190+ if (![binaryAppVersion isEqualToString: packageAppVersion]) {
191+ [CodePush clearUpdates ];
192+ }
193+ }
194+ }
195+ });
196+ }
197+
175198/*
176199 * This method is used by the React Native bridge to allow
177200 * our plugin to expose constants to the JS-side. In our case
@@ -186,7 +209,7 @@ - (NSDictionary *)constantsToExport
186209 @" codePushInstallModeOnNextRestart" :@(CodePushInstallModeOnNextRestart),
187210 @" codePushInstallModeImmediate" : @(CodePushInstallModeImmediate),
188211 @" codePushInstallModeOnNextResume" : @(CodePushInstallModeOnNextResume),
189-
212+
190213 @" codePushUpdateStateRunning" : @(CodePushUpdateStateRunning),
191214 @" codePushUpdateStatePending" : @(CodePushUpdateStatePending),
192215 @" codePushUpdateStateLatest" : @(CodePushUpdateStateLatest)
@@ -208,35 +231,35 @@ + (void)ensureBinaryBundleExists
208231{
209232 if (![self binaryBundleURL ]) {
210233 NSString *errorMessage;
211-
234+
212235#if TARGET_IPHONE_SIMULATOR
213236 errorMessage = @" React Native doesn't generate your app's JS bundle by default when deploying to the simulator. "
214237 " If you'd like to test CodePush using the simulator, you can do one of three things depending on your React "
215238 " Native version and/or preferred workflow:\n\n "
216-
239+
217240 " 1. Update your AppDelegate.m file to load the JS bundle from the packager instead of from CodePush. "
218241 " You can still test your CodePush update experience using this workflow (debug builds only).\n\n "
219-
242+
220243 " 2. Force the JS bundle to be generated in simulator builds by removing the if block that echoes "
221244 " \" Skipping bundling for Simulator platform\" in the \" node_modules/react-native/packager/react-native-xcode.sh\" file.\n\n "
222-
245+
223246 " 3. Deploy a release build to the simulator, which unlike debug builds, will generate the JS bundle (React Native >=0.22.0 only)." ;
224247#else
225248 errorMessage = [NSString stringWithFormat: @" The specified JS bundle file wasn't found within the app's binary. Is \" %@ \" the correct file name?" , [bundleResourceName stringByAppendingPathExtension: bundleResourceExtension]];
226249#endif
227-
250+
228251 RCTFatal ([CodePushErrorUtils errorWithMessage: errorMessage]);
229252 }
230253}
231254
232255- (instancetype )init
233256{
234257 self = [super init ];
235-
258+
236259 if (self) {
237260 [self initializeUpdateAfterRestart ];
238261 }
239-
262+
240263 return self;
241264}
242265
@@ -247,6 +270,10 @@ - (instancetype)init
247270 */
248271- (void )initializeUpdateAfterRestart
249272{
273+ #ifdef DEBUG
274+ [self clearDebugUpdates ];
275+ #endif
276+
250277 NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults ];
251278 NSDictionary *pendingUpdate = [preferences objectForKey: PendingUpdateKey];
252279 if (pendingUpdate) {
@@ -291,7 +318,7 @@ - (BOOL)isFailedHash:(NSString*)packageHash
291318 }
292319 }
293320 }
294-
321+
295322 return NO ;
296323 }
297324}
@@ -305,13 +332,13 @@ - (BOOL)isPendingUpdate:(NSString*)packageHash
305332{
306333 NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults ];
307334 NSDictionary *pendingUpdate = [preferences objectForKey: PendingUpdateKey];
308-
335+
309336 // If there is a pending update whose "state" isn't loading, then we consider it "pending".
310337 // Additionally, if a specific hash was provided, we ensure it matches that of the pending update.
311338 BOOL updateIsPending = pendingUpdate &&
312339 [pendingUpdate[PendingUpdateIsLoadingKey] boolValue ] == NO &&
313340 (!packageHash || [pendingUpdate[PendingUpdateHashKey] isEqualToString: packageHash]);
314-
341+
315342 return updateIsPending;
316343}
317344
@@ -332,7 +359,7 @@ - (void)loadBundle
332359 if ([CodePush isUsingTestConfiguration ] || ![_bridge.bundleURL.scheme hasPrefix: @" http" ]) {
333360 [_bridge setValue: [CodePush bundleURL ] forKey: @" bundleURL" ];
334361 }
335-
362+
336363 [_bridge reload ];
337364 });
338365}
@@ -348,10 +375,10 @@ - (void)rollbackPackage
348375{
349376 NSError *error;
350377 NSDictionary *failedPackage = [CodePushPackage getCurrentPackage: &error];
351-
378+
352379 // Write the current package's metadata to the "failed list"
353380 [self saveFailedUpdate: failedPackage];
354-
381+
355382 // Rollback to the previous version and de-register the new update
356383 [CodePushPackage rollbackPackage ];
357384 [CodePush removePendingUpdate ];
@@ -374,7 +401,7 @@ - (void)saveFailedUpdate:(NSDictionary *)failedPackage
374401 // objects, regardless if you stored something mutable.
375402 failedUpdates = [failedUpdates mutableCopy ];
376403 }
377-
404+
378405 [failedUpdates addObject: failedPackage];
379406 [preferences setObject: failedUpdates forKey: FailedUpdatesKey];
380407 [preferences synchronize ];
@@ -416,7 +443,7 @@ - (void)savePendingUpdate:(NSString *)packageHash
416443 NSDictionary *pendingUpdate = [[NSDictionary alloc ] initWithObjectsAndKeys:
417444 packageHash,PendingUpdateHashKey,
418445 [NSNumber numberWithBool: isLoading],PendingUpdateIsLoadingKey, nil ];
419-
446+
420447 [preferences setObject: pendingUpdate forKey: PendingUpdateKey];
421448 [preferences synchronize ];
422449}
@@ -457,7 +484,7 @@ - (void)applicationWillResignActive
457484 [mutableUpdatePackage setValue: [CodePushUpdateUtils modifiedDateStringOfFileAtURL: binaryBundleURL]
458485 forKey: BinaryBundleDateKey];
459486 }
460-
487+
461488 [CodePushPackage
462489 downloadPackage: mutableUpdatePackage
463490 expectedBundleFileName: [bundleResourceName stringByAppendingPathExtension: bundleResourceExtension]
@@ -478,11 +505,11 @@ - (void)applicationWillResignActive
478505 dispatch_async (_methodQueue, ^{
479506 NSError *err;
480507 NSDictionary *newPackage = [CodePushPackage getPackage: mutableUpdatePackage[PackageHashKey] error: &err];
481-
508+
482509 if (err) {
483510 return reject ([NSString stringWithFormat: @" %lu " , (long )err.code], err.localizedDescription , err);
484511 }
485-
512+
486513 resolve (newPackage);
487514 });
488515 }
@@ -492,7 +519,7 @@ - (void)applicationWillResignActive
492519 if ([CodePushErrorUtils isCodePushError: err]) {
493520 [self saveFailedUpdate: mutableUpdatePackage];
494521 }
495-
522+
496523 reject ([NSString stringWithFormat: @" %lu " , (long )err.code], err.localizedDescription , err);
497524 });
498525 }];
@@ -517,21 +544,21 @@ - (void)applicationWillResignActive
517544 resolve (configuration);
518545 return ;
519546 }
520-
547+
521548 if (binaryHash == nil ) {
522549 // The hash was not generated either due to a previous unknown error or the fact that
523550 // the React Native assets were not bundled in the binary (e.g. during dev/simulator)
524551 // builds.
525552 resolve (configuration);
526553 return ;
527554 }
528-
555+
529556 NSMutableDictionary *mutableConfiguration = [configuration mutableCopy ];
530557 [mutableConfiguration setObject: binaryHash forKey: PackageHashKey];
531558 resolve (mutableConfiguration);
532559 return ;
533560 }
534-
561+
535562 resolve (configuration);
536563}
537564
@@ -553,10 +580,10 @@ - (void)applicationWillResignActive
553580 // wanted to retrieve the pending or running update.
554581 return resolve (nil );
555582 }
556-
583+
557584 // We have a CodePush update, so let's see if it's currently in a pending state.
558585 BOOL currentUpdateIsPending = [self isPendingUpdate: [package objectForKey: PackageHashKey]];
559-
586+
560587 if (updateState == CodePushUpdateStatePending && !currentUpdateIsPending) {
561588 // The caller wanted a pending update
562589 // but there isn't currently one.
@@ -576,7 +603,7 @@ - (void)applicationWillResignActive
576603 // disk that is not actually running.
577604 [package setObject: @(YES ) forKey: @" _isDebugOnly" ];
578605 }
579-
606+
580607 // Enable differentiating pending vs. non-pending updates
581608 [package setObject: @(currentUpdateIsPending) forKey: PackageIsPendingKey];
582609 resolve (package);
@@ -596,16 +623,16 @@ - (void)applicationWillResignActive
596623 [CodePushPackage installPackage: updatePackage
597624 removePendingUpdate: [self isPendingUpdate: nil ]
598625 error: &error];
599-
626+
600627 if (error) {
601628 reject ([NSString stringWithFormat: @" %lu " , (long )error.code], error.localizedDescription , error);
602629 } else {
603630 [self savePendingUpdate: updatePackage[PackageHashKey]
604631 isLoading: NO ];
605-
632+
606633 if (installMode == CodePushInstallModeOnNextResume) {
607634 _minimumBackgroundDuration = minimumBackgroundDuration;
608-
635+
609636 if (!_hasResumeListener) {
610637 // Ensure we do not add the listener twice.
611638 // Register for app resume notifications so that we
@@ -614,16 +641,16 @@ - (void)applicationWillResignActive
614641 selector: @selector (applicationWillEnterForeground )
615642 name: UIApplicationWillEnterForegroundNotification
616643 object: [UIApplication sharedApplication ]];
617-
644+
618645 [[NSNotificationCenter defaultCenter ] addObserver: self
619646 selector: @selector (applicationWillResignActive )
620647 name: UIApplicationWillResignActiveNotification
621648 object: [UIApplication sharedApplication ]];
622-
649+
623650 _hasResumeListener = YES ;
624651 }
625652 }
626-
653+
627654 // Signal to JS that the update has been applied.
628655 resolve (nil );
629656 }
@@ -654,7 +681,7 @@ - (void)applicationWillResignActive
654681 && nil != packageHash
655682 && [packageHash length ] > 0
656683 && [packageHash isEqualToString: [CodePushPackage getCurrentPackageHash: &error]];
657-
684+
658685 resolve (@(isFirstRun));
659686}
660687
@@ -701,7 +728,7 @@ - (void)applicationWillResignActive
701728 */
702729RCT_EXPORT_METHOD (getNewStatusReport:(RCTPromiseResolveBlock)resolve
703730 rejecter:(RCTPromiseRejectBlock)reject)
704- {
731+ {
705732 if (needToReportRollback) {
706733 needToReportRollback = NO ;
707734 NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults ];
@@ -725,7 +752,7 @@ - (void)applicationWillResignActive
725752 resolve ([CodePushTelemetryManager getBinaryUpdateReport: appVersion]);
726753 return ;
727754 }
728-
755+
729756 resolve (nil );
730757}
731758
0 commit comments