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

Commit 55ac6e9

Browse files
committed
Merge pull request #300 from Microsoft/clear-updates-init
Check and clear updates if needed during init if running JS bundle from dev server
2 parents 9085a61 + ab059c3 commit 55ac6e9

File tree

2 files changed

+74
-47
lines changed

2 files changed

+74
-47
lines changed

ios/CodePush/CodePush.m

Lines changed: 71 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
702729
RCT_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

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-code-push",
3-
"version": "1.10.2-beta",
3+
"version": "1.10.3-beta",
44
"description": "React Native plugin for the CodePush service",
55
"main": "CodePush.js",
66
"homepage": "https://microsoft.github.io/code-push",
@@ -23,12 +23,12 @@
2323
"packageInstance": "new CodePush(${androidDeploymentKey}, this, BuildConfig.DEBUG)"
2424
},
2525
"ios": {
26-
"sharedLibraries": ["libz"]
26+
"sharedLibraries": ["libz"]
2727
},
2828
"params": [{
2929
"type": "input",
3030
"name": "androidDeploymentKey",
31-
"message": "What is your CodePush deployment key for Android (hit <ENTER> to ignore)"
31+
"message": "What is your CodePush deployment key for Android (hit <ENTER> to ignore)"
3232
}]
3333
}
3434
}

0 commit comments

Comments
 (0)