5
5
#import " RCTUtils.h"
6
6
#import " CodePush.h"
7
7
8
- @implementation CodePush
8
+ @implementation CodePush {
9
+ BOOL _resumablePendingUpdateAvailable;
10
+ }
9
11
10
12
RCT_EXPORT_MODULE ()
11
13
@@ -18,7 +20,6 @@ @implementation CodePush
18
20
19
21
// These keys are already "namespaced" by the PendingUpdateKey, so
20
22
// their values don't need to be obfuscated to prevent collision with app data
21
- NSString * const PendingUpdateAllowsRestartOnResumeKey = @" allowsRestartOnResume" ;
22
23
NSString * const PendingUpdateHashKey = @" hash" ;
23
24
NSString * const PendingUpdateRollbackTimeoutKey = @" rollbackTimeout" ;
24
25
@@ -63,14 +64,13 @@ - (void)cancelRollbackTimer
63
64
});
64
65
}
65
66
66
- - (void )checkForPendingUpdate : (BOOL )isAppStart
67
+ - (void )checkForPendingUpdate : (BOOL )needsRestart
67
68
{
68
69
dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{
69
70
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults ];
70
71
NSDictionary *pendingUpdate = [preferences objectForKey: PendingUpdateKey];
71
72
72
- if (pendingUpdate)
73
- {
73
+ if (pendingUpdate) {
74
74
NSError *error;
75
75
NSString *pendingHash = pendingUpdate[PendingUpdateHashKey];
76
76
NSString *currentHash = [CodePushPackage getCurrentPackageHash: &error];
@@ -79,29 +79,25 @@ - (void)checkForPendingUpdate:(BOOL)isAppStart
79
79
// restart "picked up" the new update, but we need to kick off the
80
80
// rollback timer and ensure that the necessary state is setup.
81
81
if ([pendingHash isEqualToString: currentHash]) {
82
- // We only want to initialize the rollback timer in two scenarios:
83
- // 1) The app has been restarted, and therefore, the pending update is already applied
84
- // 2) The app has been resumed, and the pending update indicates it supports being restarted on resume, so we need to restart the app and the kickoff the rollback timer
85
- if (isAppStart || (!isAppStart && [pendingUpdate[PendingUpdateAllowsRestartOnResumeKey] boolValue ]))
86
- {
87
- int rollbackTimeout = [pendingUpdate[PendingUpdateRollbackTimeoutKey] intValue ];
88
-
89
- // If the app wasn't restarted "naturally", then we need to restart it manually
90
- BOOL needsRestart = !isAppStart;
91
- [self initializeUpdateWithRollbackTimeout: rollbackTimeout needsRestart: needsRestart];
92
-
93
- // Clear the pending update and sync
94
- [preferences removeObjectForKey: PendingUpdateKey];
95
- [preferences synchronize ];
96
- }
82
+ int rollbackTimeout = [pendingUpdate[PendingUpdateRollbackTimeoutKey] intValue ];
83
+ [self initializeUpdateWithRollbackTimeout: rollbackTimeout needsRestart: needsRestart];
84
+
85
+ // Clear the pending update and sync
86
+ [preferences removeObjectForKey: PendingUpdateKey];
87
+ [preferences synchronize ];
97
88
}
98
89
}
99
90
});
100
91
}
101
92
102
93
- (void )checkForPendingUpdateDuringResume
103
94
{
104
- [self checkForPendingUpdate: NO ];
95
+ // In order to ensure that CodePush doesn't impact the app's
96
+ // resume experience, we're using a simple boolean check to
97
+ // check whether we need to restart, before reading the defaults store
98
+ if (_resumablePendingUpdateAvailable) {
99
+ [self checkForPendingUpdate: YES ];
100
+ }
105
101
}
106
102
107
103
- (NSDictionary *)constantsToExport
@@ -111,11 +107,13 @@ - (NSDictionary *)constantsToExport
111
107
return @{ @" codePushRestartModeNone" : @(CodePushRestartModeNone),
112
108
@" codePushRestartModeImmediate" : @(CodePushRestartModeImmediate),
113
109
@" codePushRestartModeOnNextResume" : @(CodePushRestartModeOnNextResume)
114
- };
110
+ };
115
111
};
116
112
117
113
- (void )dealloc
118
114
{
115
+ // Ensure the global resume handler is cleared, so that
116
+ // this object isn't kept alive unneccesarily
119
117
[[NSNotificationCenter defaultCenter ] removeObserver: self ];
120
118
}
121
119
@@ -124,7 +122,10 @@ - (CodePush *)init
124
122
self = [super init ];
125
123
126
124
if (self) {
127
- [self checkForPendingUpdate: YES ];
125
+ // Do an async check to see whether
126
+ // we need to start the rollback timer
127
+ // due to a pending update being applied at start
128
+ [self checkForPendingUpdate: NO ];
128
129
129
130
// Register for app resume notifications so that we
130
131
// can check for pending updates which support "restart on resume"
@@ -201,16 +202,13 @@ - (void)saveFailedUpdate:(NSString *)packageHash
201
202
202
203
- (void )savePendingUpdate : (NSString *)packageHash
203
204
rollbackTimeout : (int )rollbackTimeout
204
- allowRestartOnResume : (BOOL )allowRestartOnResume
205
205
{
206
206
// Since we're not restarting, we need to store the fact that the update
207
207
// was applied, but hasn't yet become "active".
208
208
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults ];
209
209
NSDictionary *pendingUpdate = [[NSDictionary alloc ] initWithObjectsAndKeys:
210
210
packageHash,PendingUpdateHashKey,
211
- [NSNumber numberWithInt: rollbackTimeout],PendingUpdateRollbackTimeoutKey,
212
- [NSNumber numberWithBool: allowRestartOnResume],PendingUpdateAllowsRestartOnResumeKey,
213
- nil ];
211
+ [NSNumber numberWithInt: rollbackTimeout],PendingUpdateRollbackTimeoutKey, nil ];
214
212
215
213
[preferences setObject: pendingUpdate forKey: PendingUpdateKey];
216
214
[preferences synchronize ];
@@ -228,10 +226,10 @@ - (void)startRollbackTimer:(int)rollbackTimeout
228
226
229
227
// JavaScript-exported module methods
230
228
RCT_EXPORT_METHOD (applyUpdate:(NSDictionary *)updatePackage
231
- rollbackTimeout:(int )rollbackTimeout
229
+ rollbackTimeout:(int )rollbackTimeout
232
230
restartMode:(CodePushRestartMode)restartMode
233
- resolver:(RCTPromiseResolveBlock)resolve
234
- rejecter:(RCTPromiseRejectBlock)reject)
231
+ resolver:(RCTPromiseResolveBlock)resolve
232
+ rejecter:(RCTPromiseRejectBlock)reject)
235
233
{
236
234
dispatch_async (dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{
237
235
NSError *error;
@@ -244,18 +242,17 @@ - (void)startRollbackTimer:(int)rollbackTimeout
244
242
if (restartMode == CodePushRestartModeImmediate) {
245
243
[self initializeUpdateWithRollbackTimeout: rollbackTimeout needsRestart: YES ];
246
244
} else {
247
- BOOL allowsRestartOnResume = (restartMode == CodePushRestartModeOnNextResume);
245
+ _resumablePendingUpdateAvailable = (restartMode == CodePushRestartModeOnNextResume);
248
246
[self savePendingUpdate: updatePackage[@" packageHash" ]
249
- rollbackTimeout: rollbackTimeout
250
- allowRestartOnResume: allowsRestartOnResume];
247
+ rollbackTimeout: rollbackTimeout];
251
248
}
252
249
}
253
250
});
254
251
}
255
252
256
253
RCT_EXPORT_METHOD (downloadUpdate:(NSDictionary *)updatePackage
257
- resolver:(RCTPromiseResolveBlock)resolve
258
- rejecter:(RCTPromiseRejectBlock)reject)
254
+ resolver:(RCTPromiseResolveBlock)resolve
255
+ rejecter:(RCTPromiseRejectBlock)reject)
259
256
{
260
257
[CodePushPackage downloadPackage: updatePackage
261
258
progressCallback: ^(long expectedContentLength, long receivedContentLength) {
@@ -284,13 +281,13 @@ - (void)startRollbackTimer:(int)rollbackTimeout
284
281
}
285
282
286
283
RCT_EXPORT_METHOD (getConfiguration:(RCTPromiseResolveBlock)resolve
287
- rejecter:(RCTPromiseRejectBlock)reject)
284
+ rejecter:(RCTPromiseRejectBlock)reject)
288
285
{
289
286
resolve ([CodePushConfig getConfiguration ]);
290
287
}
291
288
292
289
RCT_EXPORT_METHOD (getCurrentPackage:(RCTPromiseResolveBlock)resolve
293
- rejecter:(RCTPromiseRejectBlock)reject)
290
+ rejecter:(RCTPromiseRejectBlock)reject)
294
291
{
295
292
dispatch_async (dispatch_get_main_queue (), ^{
296
293
NSError *error;
@@ -304,16 +301,16 @@ - (void)startRollbackTimer:(int)rollbackTimeout
304
301
}
305
302
306
303
RCT_EXPORT_METHOD (isFailedUpdate:(NSString *)packageHash
307
- resolve:(RCTPromiseResolveBlock)resolve
308
- reject:(RCTPromiseRejectBlock)reject)
304
+ resolve:(RCTPromiseResolveBlock)resolve
305
+ reject:(RCTPromiseRejectBlock)reject)
309
306
{
310
307
BOOL isFailedHash = [self isFailedHash: packageHash];
311
308
resolve (@(isFailedHash));
312
309
}
313
310
314
311
RCT_EXPORT_METHOD (isFirstRun:(NSString *)packageHash
315
- resolve:(RCTPromiseResolveBlock)resolve
316
- rejecter:(RCTPromiseRejectBlock)reject)
312
+ resolve:(RCTPromiseResolveBlock)resolve
313
+ rejecter:(RCTPromiseRejectBlock)reject)
317
314
{
318
315
NSError *error;
319
316
BOOL isFirstRun = didUpdate
@@ -325,7 +322,7 @@ - (void)startRollbackTimer:(int)rollbackTimeout
325
322
}
326
323
327
324
RCT_EXPORT_METHOD (notifyApplicationReady:(RCTPromiseResolveBlock)resolve
328
- rejecter:(RCTPromiseRejectBlock)reject)
325
+ rejecter:(RCTPromiseRejectBlock)reject)
329
326
{
330
327
[self cancelRollbackTimer ];
331
328
resolve ([NSNull null ]);
0 commit comments