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

Commit a20e4a2

Browse files
committed
Adding comments to CodePush class
1 parent 6aab2a5 commit a20e4a2

File tree

2 files changed

+158
-44
lines changed

2 files changed

+158
-44
lines changed

CodePush.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
#import "RCTBridgeModule.h"
22

3-
@interface CodePush : NSObject<RCTBridgeModule>
4-
3+
@interface CodePush : NSObject <RCTBridgeModule>
4+
5+
/*
6+
* This method is used to retreive the URL for the most recent
7+
* version of the JavaScript bundle. This could be either the
8+
* bundle that was packaged with the app binary, or the bundle
9+
* that was downloaded as part of a CodePush update. The value returned
10+
* should be used to "bootstrap" the React Native bridge.
11+
*
12+
* This method assumes that your JS bundle is named "main.jsbundle"
13+
* and therefore, if it isn't, you should use either the bundleURLForResource:
14+
* or bundleURLForResource:withExtension: methods to override thsat behavior.
15+
*/
516
+ (NSURL *)bundleURL;
617

718
+ (NSURL *)bundleURLForResource:(NSString *)resourceName;
@@ -25,7 +36,7 @@
2536

2637
@end
2738

28-
@interface CodePushDownloadHandler : NSObject<NSURLConnectionDelegate>
39+
@interface CodePushDownloadHandler : NSObject <NSURLConnectionDelegate>
2940

3041
@property (strong) NSOutputStream *outputFileStream;
3142
@property long expectedContentLength;

CodePush.m

Lines changed: 144 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
#import "RCTBridgeModule.h"
2-
#import "RCTEventDispatcher.h"
32
#import "RCTConvert.h"
3+
#import "RCTEventDispatcher.h"
44
#import "RCTRootView.h"
55
#import "RCTUtils.h"
6+
67
#import "CodePush.h"
78

89
@implementation CodePush {
@@ -15,16 +16,17 @@ @implementation CodePush {
1516
static NSTimer *_timer;
1617
static BOOL usingTestFolder = NO;
1718

18-
static NSString * const FailedUpdatesKey = @"CODE_PUSH_FAILED_UPDATES";
19-
static NSString * const PendingUpdateKey = @"CODE_PUSH_PENDING_UPDATE";
19+
static NSString *const FailedUpdatesKey = @"CODE_PUSH_FAILED_UPDATES";
20+
static NSString *const PendingUpdateKey = @"CODE_PUSH_PENDING_UPDATE";
2021

2122
// These keys are already "namespaced" by the PendingUpdateKey, so
2223
// their values don't need to be obfuscated to prevent collision with app data
23-
static NSString * const PendingUpdateHashKey = @"hash";
24-
static NSString * const PendingUpdateRollbackTimeoutKey = @"rollbackTimeout";
24+
static NSString *const PendingUpdateHashKey = @"hash";
25+
static NSString *const PendingUpdateRollbackTimeoutKey = @"rollbackTimeout";
2526

2627
@synthesize bridge = _bridge;
2728

29+
// Public Obj-C API (see header for method comments)
2830
+ (NSURL *)bundleURL
2931
{
3032
return [self bundleURLForResource:@"main"];
@@ -43,8 +45,7 @@ + (NSURL *)bundleURLForResource:(NSString *)resourceName
4345
NSString *packageFile = [CodePushPackage getCurrentPackageBundlePath:&error];
4446
NSURL *binaryJsBundleUrl = [[NSBundle mainBundle] URLForResource:resourceName withExtension:resourceExtension];
4547

46-
if (error || !packageFile)
47-
{
48+
if (error || !packageFile) {
4849
return binaryJsBundleUrl;
4950
}
5051

@@ -61,21 +62,36 @@ + (NSURL *)bundleURLForResource:(NSString *)resourceName
6162
}
6263
}
6364

64-
// Public Obj-C API
6565
+ (NSString *)getDocumentsDirectory
6666
{
6767
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
6868
return documentsDirectory;
6969
}
7070

71-
// Internal API methods
71+
// Private API methods
72+
73+
/*
74+
* This method cancels the currently running rollback
75+
* timer, which has the effect of stopping an automatic
76+
* rollback from occuring.
77+
*
78+
* Note: This method is safe to call from any thread.
79+
*/
7280
- (void)cancelRollbackTimer
7381
{
7482
dispatch_async(dispatch_get_main_queue(), ^{
7583
[_timer invalidate];
7684
});
7785
}
7886

87+
/*
88+
* This method checks to see whether a "pending udpate" has been applied
89+
* (e.g. install was called with a non-immediate mode), but the app hasn't
90+
* yet been restarted (either naturally or synthentically). If there is one,
91+
* it will restart the app (if specified), and start the rollback timer.
92+
*
93+
* Note: This method is safe to call from any thread.
94+
*/
7995
- (void)checkForPendingUpdate:(BOOL)needsRestart
8096
{
8197
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@@ -93,15 +109,24 @@ - (void)checkForPendingUpdate:(BOOL)needsRestart
93109
if ([pendingHash isEqualToString:currentHash]) {
94110
int rollbackTimeout = [pendingUpdate[PendingUpdateRollbackTimeoutKey] intValue];
95111
[self initializeUpdateWithRollbackTimeout:rollbackTimeout needsRestart:needsRestart];
96-
97-
// Clear the pending update and sync
98-
[preferences removeObjectForKey:PendingUpdateKey];
99-
[preferences synchronize];
112+
} else {
113+
// NOTE: We shouldn't ever reach here
100114
}
115+
116+
// Clear the pending update and sync
117+
[preferences removeObjectForKey:PendingUpdateKey];
118+
[preferences synchronize];
101119
}
102120
});
103121
}
104122

123+
/*
124+
* This method is meant as a handler for the global app
125+
* resume notification, and therefore, should not be called
126+
* directly. It simply checks to see whether there is a pending
127+
* update that is meant to be installed on resume, and if so
128+
* it applies it and restarts the app.
129+
*/
105130
- (void)checkForPendingUpdateDuringResume
106131
{
107132
// In order to ensure that CodePush doesn't impact the app's
@@ -112,6 +137,12 @@ - (void)checkForPendingUpdateDuringResume
112137
}
113138
}
114139

140+
/*
141+
* This method is used by the React Native bridge to allow
142+
* our plugin to expose constants to the JS-side. In our case
143+
* we're simply exporting enum values so that the JS and Native
144+
* sides of the plugin can be in sync.
145+
*/
115146
- (NSDictionary *)constantsToExport
116147
{
117148
// Export the values of the CodePushInstallMode enum
@@ -151,6 +182,14 @@ - (instancetype)init
151182
return self;
152183
}
153184

185+
/*
186+
* This method performs the actual initialization work for a update
187+
* to ensure that the neccessary state is setup, including:
188+
* --------------------------------------------------------
189+
* 1. Updating the current bundle URL to point at the latest update on disk
190+
* 2. Optionally restarting the app to load the new bundle
191+
* 3. Optionally starting the rollback protection timer
192+
*/
154193
- (void)initializeUpdateWithRollbackTimeout:(int)rollbackTimeout
155194
needsRestart:(BOOL)needsRestart
156195
{
@@ -167,13 +206,22 @@ - (void)initializeUpdateWithRollbackTimeout:(int)rollbackTimeout
167206
}
168207
}
169208

209+
/*
210+
* This method checks to see whether a specific package hash
211+
* has previously failed installation.
212+
*/
170213
- (BOOL)isFailedHash:(NSString*)packageHash
171214
{
172215
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
173216
NSMutableArray *failedUpdates = [preferences objectForKey:FailedUpdatesKey];
174217
return (failedUpdates != nil && [failedUpdates containsObject:packageHash]);
175218
}
176219

220+
/*
221+
* This method updates the React Native bridge's bundle URL
222+
* to point at the latest CodePush update, and then restarts
223+
* the bridge. This isn't meant to be called directly.
224+
*/
177225
- (void)loadBundle
178226
{
179227
// If the current bundle URL is using http(s), then assume the dev
@@ -187,6 +235,13 @@ - (void)loadBundle
187235
[_bridge reload];
188236
}
189237

238+
/*
239+
* This method is used when an update has failed installation
240+
* and the app needs to be rolled back to the previous bundle.
241+
* This method is automatically called when the rollback timer
242+
* expires without the app indicating whether the update succeeded,
243+
* and therefore, it shouldn't be called directly.
244+
*/
190245
- (void)rollbackPackage
191246
{
192247
NSError *error;
@@ -201,6 +256,11 @@ - (void)rollbackPackage
201256
[self loadBundle];
202257
}
203258

259+
/*
260+
* When an update failed to apply, this method can be called
261+
* to store its hash so that it can be ignored on future
262+
* attempts to check the server for an update.
263+
*/
204264
- (void)saveFailedUpdate:(NSString *)packageHash
205265
{
206266
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
@@ -218,6 +278,11 @@ - (void)saveFailedUpdate:(NSString *)packageHash
218278
[preferences synchronize];
219279
}
220280

281+
/*
282+
* When an update is installed whose mode isn't IMMEDIATE, this method
283+
* can be called to store the pending update's metadata (e.g. rollbackTimeout)
284+
* so that it can be used when the actual update application occurs at a later point.
285+
*/
221286
- (void)savePendingUpdate:(NSString *)packageHash
222287
rollbackTimeout:(int)rollbackTimeout
223288
{
@@ -232,6 +297,10 @@ - (void)savePendingUpdate:(NSString *)packageHash
232297
[preferences synchronize];
233298
}
234299

300+
/*
301+
* This method handles starting the actual rollback timer
302+
* after an update has been installed.
303+
*/
235304
- (void)startRollbackTimer:(int)rollbackTimeout
236305
{
237306
double timeoutInSeconds = rollbackTimeout / 1000;
@@ -243,42 +312,57 @@ - (void)startRollbackTimer:(int)rollbackTimeout
243312
}
244313

245314
// JavaScript-exported module methods
315+
316+
/*
317+
* This is native-side of the RemotePackage.download method
318+
*/
246319
RCT_EXPORT_METHOD(downloadUpdate:(NSDictionary*)updatePackage
247320
resolver:(RCTPromiseResolveBlock)resolve
248321
rejecter:(RCTPromiseRejectBlock)reject)
249322
{
250323
[CodePushPackage downloadPackage:updatePackage
251-
progressCallback:^(long expectedContentLength, long receivedContentLength) {
252-
[self.bridge.eventDispatcher
253-
sendAppEventWithName:@"CodePushDownloadProgress"
254-
body:@{
255-
@"totalBytes":[NSNumber numberWithLong:expectedContentLength],
256-
@"receivedBytes":[NSNumber numberWithLong:receivedContentLength]
257-
}];
258-
}
259-
doneCallback:^{
260-
NSError *err;
261-
NSDictionary *newPackage = [CodePushPackage
262-
getPackage:updatePackage[@"packageHash"]
263-
error:&err];
264-
265-
if (err) {
266-
return reject(err);
267-
}
268-
269-
resolve(newPackage);
270-
}
271-
failCallback:^(NSError *err) {
272-
reject(err);
273-
}];
324+
// The download is progressing forward
325+
progressCallback:^(long expectedContentLength, long receivedContentLength) {
326+
// Notify the script-side about the progress
327+
[self.bridge.eventDispatcher
328+
sendAppEventWithName:@"CodePushDownloadProgress"
329+
body:@{
330+
@"totalBytes":[NSNumber numberWithLong:expectedContentLength],
331+
@"receivedBytes":[NSNumber numberWithLong:receivedContentLength]
332+
}];
333+
}
334+
// The download completed
335+
doneCallback:^{
336+
NSError *err;
337+
NSDictionary *newPackage = [CodePushPackage getPackage:updatePackage[@"packageHash"] error:&err];
338+
339+
if (err) {
340+
return reject(err);
341+
}
342+
343+
resolve(newPackage);
344+
}
345+
// The download failed
346+
failCallback:^(NSError *err) {
347+
reject(err);
348+
}];
274349
}
275350

351+
/*
352+
* This is the native side of the CodePush.getConfiguration method. It isn't
353+
* currently exposed via the "react-native-code-push" module, and is used
354+
* internally only by the CodePush.checkForUpdate method in order to get the
355+
* app version, as well as the deployment key that was configured in the Info.plist file.
356+
*/
276357
RCT_EXPORT_METHOD(getConfiguration:(RCTPromiseResolveBlock)resolve
277358
rejecter:(RCTPromiseRejectBlock)reject)
278359
{
279360
resolve([[CodePushConfig current] configuration]);
280361
}
281362

363+
/*
364+
* This method is the native side of the CodePush.getCurrentPackage method.
365+
*/
282366
RCT_EXPORT_METHOD(getCurrentPackage:(RCTPromiseResolveBlock)resolve
283367
rejecter:(RCTPromiseRejectBlock)reject)
284368
{
@@ -293,6 +377,9 @@ - (void)startRollbackTimer:(int)rollbackTimeout
293377
});
294378
}
295379

380+
/*
381+
* This method is the native side of the LocalPackage.install method.
382+
*/
296383
RCT_EXPORT_METHOD(installUpdate:(NSDictionary*)updatePackage
297384
rollbackTimeout:(int)rollbackTimeout
298385
installMode:(CodePushInstallMode)installMode
@@ -318,6 +405,10 @@ - (void)startRollbackTimer:(int)rollbackTimeout
318405
});
319406
}
320407

408+
/*
409+
* This method isn't publically exposed via the "react-native-code-push"
410+
* module, and is only used internally to populate the RemotePackage.failedApply property.
411+
*/
321412
RCT_EXPORT_METHOD(isFailedUpdate:(NSString *)packageHash
322413
resolve:(RCTPromiseResolveBlock)resolve
323414
reject:(RCTPromiseRejectBlock)reject)
@@ -326,33 +417,45 @@ - (void)startRollbackTimer:(int)rollbackTimeout
326417
resolve(@(isFailedHash));
327418
}
328419

420+
/*
421+
* This method isn't publically exposed via the "react-native-code-push"
422+
* module, and is only used internally to populate the LocalPackage.isFirstRun property.
423+
*/
329424
RCT_EXPORT_METHOD(isFirstRun:(NSString *)packageHash
330425
resolve:(RCTPromiseResolveBlock)resolve
331426
rejecter:(RCTPromiseRejectBlock)reject)
332427
{
333428
NSError *error;
334429
BOOL isFirstRun = didUpdate
335-
&& nil != packageHash
336-
&& [packageHash length] > 0
337-
&& [packageHash isEqualToString:[CodePushPackage getCurrentPackageHash:&error]];
430+
&& nil != packageHash
431+
&& [packageHash length] > 0
432+
&& [packageHash isEqualToString:[CodePushPackage getCurrentPackageHash:&error]];
338433

339434
resolve(@(isFirstRun));
340435
}
341436

437+
/*
438+
* This method is the native side of the CodePush.notifyApplicationReady() method.
439+
*/
342440
RCT_EXPORT_METHOD(notifyApplicationReady:(RCTPromiseResolveBlock)resolve
343441
rejecter:(RCTPromiseRejectBlock)reject)
344442
{
345443
[self cancelRollbackTimer];
346444
resolve([NSNull null]);
347445
}
348446

349-
// This function is exposed solely for immediately installed
350-
// update support, and shouldn't be consumed directly by user code.
447+
/*
448+
* This method isn't publically exposed via the "react-native-code-push"
449+
* module, and is only used internally to support immediately installed updates.
450+
*/
351451
RCT_EXPORT_METHOD(restartImmedidateUpdate:(int)rollbackTimeout)
352452
{
353453
[self initializeUpdateWithRollbackTimeout:rollbackTimeout needsRestart:YES];
354454
}
355455

456+
/*
457+
* This method is the native side of the CodePush.restartPendingUpdate() method.
458+
*/
356459
RCT_EXPORT_METHOD(restartPendingUpdate)
357460
{
358461
[self checkForPendingUpdate:YES];

0 commit comments

Comments
 (0)