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

Commit 79e4c50

Browse files
committed
Merge pull request #43 from Microsoft/applyImmediately
Adding new restartImmediately flag to the apply method
2 parents 7638487 + 0e2defd commit 79e4c50

File tree

3 files changed

+75
-19
lines changed

3 files changed

+75
-19
lines changed

CodePush.m

Lines changed: 68 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ @implementation CodePush
1111
BOOL usingTestFolder = NO;
1212
BOOL didUpdate = NO;
1313

14-
NSString * const FailedUpdatesKey = @"FAILED_UPDATES";
14+
NSString * const FailedUpdatesKey = @"CODE_PUSH_FAILED_UPDATES";
15+
NSString * const PendingUpdateKey = @"CODE_PUSH_PENDING_UPDATE";
1516
NSString * const UpdateBundleFileName = @"app.jsbundle";
1617

1718
@synthesize bridge = _bridge;
@@ -57,6 +58,51 @@ - (void)cancelRollbackTimer
5758
});
5859
}
5960

61+
- (CodePush *)init
62+
{
63+
self = [super init];
64+
65+
if (self) {
66+
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
67+
NSDictionary *pendingUpdate = [preferences objectForKey:PendingUpdateKey];
68+
69+
if (pendingUpdate)
70+
{
71+
NSError *error;
72+
NSString *pendingHash = pendingUpdate[@"hash"];
73+
NSString *currentHash = [CodePushPackage getCurrentPackageHash:&error];
74+
75+
// If the current hash is equivalent to the pending hash, then the app
76+
// restart "picked up" the new update, but we need to kick off the
77+
// rollback timer and ensure that the necessary state is setup.
78+
if ([pendingHash isEqualToString:currentHash]) {
79+
int rollbackTimeout = [pendingUpdate[@"rollbackTimeout"] intValue];
80+
[self initializeUpdateWithRollbackTimeout:rollbackTimeout needsRestart:NO];
81+
82+
// Clear the pending update and sync
83+
[preferences removeObjectForKey:PendingUpdateKey];
84+
[preferences synchronize];
85+
}
86+
}
87+
}
88+
89+
return self;
90+
}
91+
92+
- (void)initializeUpdateWithRollbackTimeout:(int)rollbackTimeout needsRestart:(BOOL)needsRestart {
93+
didUpdate = YES;
94+
95+
if (needsRestart) {
96+
[self loadBundle];
97+
}
98+
99+
if (0 != rollbackTimeout) {
100+
dispatch_async(dispatch_get_main_queue(), ^{
101+
[self startRollbackTimer:rollbackTimeout];
102+
});
103+
}
104+
}
105+
60106
- (BOOL)isFailedHash:(NSString*)packageHash {
61107
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
62108
NSMutableArray *failedUpdates = [preferences objectForKey:FailedUpdatesKey];
@@ -101,6 +147,19 @@ - (void)saveFailedUpdate:(NSString *)packageHash {
101147
[preferences synchronize];
102148
}
103149

150+
- (void)savePendingUpdate:(NSString *)packageHash
151+
rollbackTimeout:(int)rollbackTimeout {
152+
// Since we're not restarting, we need to store the fact that the update
153+
// was applied, but hasn't yet become "active".
154+
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
155+
NSDictionary *pendingUpdate = [[NSDictionary alloc] initWithObjectsAndKeys:
156+
packageHash,@"hash",
157+
rollbackTimeout,@"rollbackTimeout", nil];
158+
159+
[preferences setObject:pendingUpdate forKey:PendingUpdateKey];
160+
[preferences synchronize];
161+
}
162+
104163
- (void)startRollbackTimer:(int)rollbackTimeout
105164
{
106165
double timeoutInSeconds = rollbackTimeout / 1000;
@@ -113,11 +172,11 @@ - (void)startRollbackTimer:(int)rollbackTimeout
113172

114173
// JavaScript-exported module methods
115174
RCT_EXPORT_METHOD(applyUpdate:(NSDictionary*)updatePackage
116-
rollbackTimeout:(int)rollbackTimeout
117-
resolver:(RCTPromiseResolveBlock)resolve
118-
rejecter:(RCTPromiseRejectBlock)reject)
175+
rollbackTimeout:(int)rollbackTimeout
176+
restartImmediately:(BOOL)restartImmediately
177+
resolver:(RCTPromiseResolveBlock)resolve
178+
rejecter:(RCTPromiseRejectBlock)reject)
119179
{
120-
121180
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
122181
NSError *error;
123182
[CodePushPackage applyPackage:updatePackage
@@ -126,14 +185,10 @@ - (void)startRollbackTimer:(int)rollbackTimeout
126185
if (error) {
127186
reject(error);
128187
} else {
129-
didUpdate = YES;
130-
131-
[self loadBundle];
132-
133-
if (0 != rollbackTimeout) {
134-
dispatch_async(dispatch_get_main_queue(), ^{
135-
[self startRollbackTimer:rollbackTimeout];
136-
});
188+
if (restartImmediately) {
189+
[self initializeUpdateWithRollbackTimeout:rollbackTimeout needsRestart:YES];
190+
} else {
191+
[self savePendingUpdate:updatePackage[@"packageHash"] rollbackTimeout:rollbackTimeout];
137192
}
138193
}
139194
});

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,11 @@ Contains details about an update package that has been downloaded locally or alr
248248
- __isFirstRun__: Flag indicating whether this is the first time the package has been run after being applied. (Boolean) This is useful for determining whether you would like to show a "What's New?" UI to the end-user after applying an update.
249249

250250
##### Methods
251-
- __apply(rollbackTimeout): Promise__: Applies this package to the application. The application will be reloaded with this package and on every application launch this package will be loaded.
252-
If the rollbackTimeout parameter is provided, the application will wait for a `notifyApplicationReady` for the given number of milliseconds.
253-
If `notifyApplicationReady` is called before the time period specified by rollbackTimeout, the apply operation is considered a success.
254-
Otherwise, the apply operation will be marked as failed, and the application is reverted to its previous version.
251+
- __apply(rollbackTimeout: Number = 0, restartImmediately: Boolean = true): Promise<void>__: Applies this package to the application by unzipping its contents (e.g. the JS bundle) and saving it to the location on disk where the runtime expects to find the latest version of the app. If the `restartImmediately` parameter is set to `false`, the apply will complete, but it won't take effect until the next time that the app is restarted. Otherwise, the app will be immediately restarted after performing the apply, so that the end-user sees the changes.
252+
<br /><br />
253+
If a value greater than zero is provided to the `rollbackTimeout` parameter, the application will wait for the `notifyApplicationReady` method to be called for the given number of milliseconds.
254+
<br /><br />
255+
Note: The "rollback timer" doesn't start until the update has actually become active. If you pass a truthy value to the `restartImmediately` parameter, then the rollback timer will also start immediately. However, if you pass a falsey value, then the rollback timer will start the next time the app starts, not at the point that you called `apply`.
255256

256257
#### RemotePackage
257258

package-mixins.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ module.exports = (NativeCodePush) => {
2020
};
2121

2222
var local = {
23-
apply: function apply(rollbackTimeout = 0) {
24-
return NativeCodePush.applyUpdate(this, rollbackTimeout);
23+
apply: function apply(rollbackTimeout = 0, restartImmediately = true) {
24+
return NativeCodePush.applyUpdate(this, rollbackTimeout, restartImmediately);
2525
}
2626
};
2727

0 commit comments

Comments
 (0)