@@ -13,9 +13,9 @@ @implementation CodePush {
1313
1414RCT_EXPORT_MODULE ()
1515
16- static NSTimer *_timer;
1716static BOOL usingTestFolder = NO;
1817
18+ // These keys represent the names we use to store data in NSUserDefaults
1919static NSString *const FailedUpdatesKey = @" CODE_PUSH_FAILED_UPDATES" ;
2020static NSString *const PendingUpdateKey = @" CODE_PUSH_PENDING_UPDATE" ;
2121
@@ -24,6 +24,11 @@ @implementation CodePush {
2424static NSString *const PendingUpdateHashKey = @" hash" ;
2525static NSString *const PendingUpdateIsLoadingKey = @" isLoading" ;
2626
27+ // These keys are used to inspect/augment the metadata
28+ // that is associated with an update's package.
29+ static NSString *const PackageHashKey = @" packageHash" ;
30+ static NSString *const PackageIsPendingKey = @" isPending" ;
31+
2732@synthesize bridge = _bridge;
2833
2934// Public Obj-C API (see header for method comments)
@@ -141,6 +146,25 @@ - (BOOL)isFailedHash:(NSString*)packageHash
141146 return (failedUpdates != nil && [failedUpdates containsObject: packageHash]);
142147}
143148
149+ /*
150+ * This method checks to see whether a specific package hash
151+ * represents a downloaded and installed update, that hasn't
152+ * been applied yet via an app restart.
153+ */
154+ - (BOOL )isPendingUpdate : (NSString *)packageHash
155+ {
156+ NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults ];
157+ NSDictionary *pendingUpdate = [preferences objectForKey: PendingUpdateKey];
158+
159+ // If there is a pending update, whose hash is equal to the one
160+ // specified, and its "state" isn't loading, then we consider it "pending".
161+ BOOL updateIsPending = pendingUpdate &&
162+ [pendingUpdate[PendingUpdateIsLoadingKey] boolValue ] == NO &&
163+ [pendingUpdate[PendingUpdateHashKey] isEqualToString: packageHash];
164+
165+ return updateIsPending;
166+ }
167+
144168/*
145169 * This method updates the React Native bridge's bundle URL
146170 * to point at the latest CodePush update, and then restarts
@@ -259,7 +283,7 @@ - (void)savePendingUpdate:(NSString *)packageHash
259283 // The download completed
260284 doneCallback: ^{
261285 NSError *err;
262- NSDictionary *newPackage = [CodePushPackage getPackage: updatePackage[@" packageHash " ] error: &err];
286+ NSDictionary *newPackage = [CodePushPackage getPackage: updatePackage[PackageHashKey ] error: &err];
263287
264288 if (err) {
265289 return reject (err);
@@ -293,12 +317,18 @@ - (void)savePendingUpdate:(NSString *)packageHash
293317{
294318 dispatch_async (dispatch_get_main_queue (), ^{
295319 NSError *error;
296- NSDictionary *package = [CodePushPackage getCurrentPackage: &error];
320+ NSMutableDictionary *package = [[CodePushPackage getCurrentPackage: &error] mutableCopy ];
321+
297322 if (error) {
298323 reject (error);
299- } else {
300- resolve (package);
301324 }
325+
326+ // Add the "isPending" virtual property to the package at this point, so that
327+ // the script-side doesn't need to immediately call back into native to populate it.
328+ BOOL isPendingUpdate = [self isPendingUpdate: [package objectForKey: PackageHashKey]];
329+ [package setObject: @(isPendingUpdate) forKey: PackageIsPendingKey];
330+
331+ resolve (package);
302332 });
303333}
304334
@@ -318,7 +348,7 @@ - (void)savePendingUpdate:(NSString *)packageHash
318348 if (error) {
319349 reject (error);
320350 } else {
321- [self savePendingUpdate: updatePackage[@" packageHash " ]
351+ [self savePendingUpdate: updatePackage[PackageHashKey ]
322352 isLoading: NO ];
323353
324354 if (installMode == CodePushInstallModeImmediate) {
@@ -393,4 +423,4 @@ - (void)savePendingUpdate:(NSString *)packageHash
393423 usingTestFolder = shouldUseTestFolder;
394424}
395425
396- @end
426+ @end
0 commit comments