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

Commit af2a5c6

Browse files
committed
iOS implementation of minimumBackgroundDuration
1 parent 5200325 commit af2a5c6

File tree

4 files changed

+59
-18
lines changed

4 files changed

+59
-18
lines changed

CodePush.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ async function syncInternal(options = {}, syncStatusChangeCallback, downloadProg
239239
ignoreFailedUpdates: true,
240240
installMode: CodePush.InstallMode.ON_NEXT_RESTART,
241241
mandatoryInstallMode: CodePush.InstallMode.IMMEDIATE,
242+
minimumBackgroundDuration: 0,
242243
updateDialog: null,
243244
...options
244245
};
@@ -273,7 +274,11 @@ async function syncInternal(options = {}, syncStatusChangeCallback, downloadProg
273274
if (resolvedInstallMode == CodePush.InstallMode.ON_NEXT_RESTART) {
274275
log("Update is installed and will be run on the next app restart.");
275276
} else {
276-
log("Update is installed and will be run when the app next resumes.");
277+
if (syncOptions.minimumBackgroundDuration > 0) {
278+
log(`Update is installed and will be run after the app has been in the background for at least ${syncOptions.minimumBackgroundDuration} seconds.`);
279+
} else {
280+
log("Update is installed and will be run when the app next resumes.");
281+
}
277282
}
278283
break;
279284
case CodePush.SyncStatus.UNKNOWN_ERROR:
@@ -302,7 +307,7 @@ async function syncInternal(options = {}, syncStatusChangeCallback, downloadProg
302307
resolvedInstallMode = localPackage.isMandatory ? syncOptions.mandatoryInstallMode : syncOptions.installMode;
303308

304309
syncStatusChangeCallback(CodePush.SyncStatus.INSTALLING_UPDATE);
305-
await localPackage.install(resolvedInstallMode, () => {
310+
await localPackage.install(resolvedInstallMode, syncOptions.minimumBackgroundDuration, () => {
306311
syncStatusChangeCallback(CodePush.SyncStatus.UPDATE_INSTALLED);
307312
});
308313

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,8 @@ While the `sync` method tries to make it easy to perform silent and active updat
567567

568568
* __mandatoryInstallMode__ *(codePush.InstallMode)* - Specifies when you would like to install updates which are marked as mandatory. Defaults to `codePush.InstallMode.IMMEDIATE`. Refer to the [`InstallMode`](#installmode) enum reference for a description of the available options and what they do.
569569

570+
* __minimumBackgroundDuration__ *(Number)* - Specifies the minimum number of seconds that the app needs to have been in the background before restarting the app to apply the udpate. This property only applies to updates which are installed using `InstallMode.ON_NEXT_RESUME`, and can be useful for getting your update in front of end users sooner, without being too obtrusive. Defaults to `0`, which has the effect of applying the update immediately after a resume, regardless how long it was in the background.
571+
570572
* __updateDialog__ *(UpdateDialogOptions)* - An "options" object used to determine whether a confirmation dialog should be displayed to the end user when an update is available, and if so, what strings to use. Defaults to `null`, which has the effect of disabling the dialog completely. Setting this to any truthy value will enable the dialog with the default strings, and passing an object to this parameter allows enabling the dialog as well as overriding one or more of the default strings. Before enabling this option within an App Store-distributed app, please refer to [this note](#user-content-apple-note).
571573

572574
The following list represents the available options and their defaults:
@@ -595,10 +597,10 @@ Example Usage:
595597
// in the Info.plist file
596598
codePush.sync({ deploymentKey: "KEY" });
597599
598-
// Download the update silently
599-
// but install is on the next resume
600-
// instead of waiting until the app is restarted
601-
codePush.sync({ installMode: codePush.InstallMode.ON_NEXT_RESUME });
600+
// Download the update silently, but install it on
601+
// the next resume, as long as at least 5 minutes
602+
// has passed since the app was put into the background.
603+
codePush.sync({ installMode: codePush.InstallMode.ON_NEXT_RESUME, minimumBackgroundDuration: 60 * 5 });
602604
603605
// Download the update silently, and install optional updates
604606
// on the next restart, but install mandatory updates on the next resume.
@@ -681,7 +683,7 @@ Contains details about an update that has been downloaded locally or already ins
681683
- __packageSize__: The size of the code contained within the update, in bytes. *(Number)*
682684
683685
###### Methods
684-
- __install(installMode: codePush.InstallMode = codePush.InstallMode.ON_NEXT_RESTART): Promise<void>__: Installs the update by saving it to the location on disk where the runtime expects to find the latest version of the app. The `installMode` parameter controls when the changes are actually presented to the end user. The default value is to wait until the next app restart to display the changes, but you can refer to the [`InstallMode`](#installmode) enum reference for a description of the available options and what they do.
686+
- __install(installMode: codePush.InstallMode = codePush.InstallMode.ON_NEXT_RESTART, minimumBackgroundDuration = 0): Promise<void>__: Installs the update by saving it to the location on disk where the runtime expects to find the latest version of the app. The `installMode` parameter controls when the changes are actually presented to the end user. The default value is to wait until the next app restart to display the changes, but you can refer to the [`InstallMode`](#installmode) enum reference for a description of the available options and what they do. If the `installMode` parameter is set to `InstallMode.ON_NEXT_RESUME`, then the `minimumBackgroundDuration` parameter allows you to control how long the app must have been in the background before forcing the install after it is resumed.
685687
686688
##### RemotePackage
687689

ios/CodePush/CodePush.m

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ @interface CodePush () <RCTBridgeModule>
1212
@implementation CodePush {
1313
BOOL _hasResumeListener;
1414
BOOL _isFirstRunAfterUpdate;
15+
int _minimumBackgroundDuration;
16+
NSDate * _lastResignedDate;
1517
}
1618

1719
RCT_EXPORT_MODULE()
@@ -380,6 +382,27 @@ - (void)savePendingUpdate:(NSString *)packageHash
380382
[preferences synchronize];
381383
}
382384

385+
#pragma mark - Application lifecycle event handlers
386+
387+
// These two handlers will only be registered when there is
388+
// a resume-based update still pending installation.
389+
- (void)applicationWillEnterForeground
390+
{
391+
// Determine how long the app was in the background and ensure
392+
// that it meets the minimum amount of time requsted.
393+
int durationInBackground = [[NSDate date] timeIntervalSinceDate:_lastResignedDate];
394+
if (durationInBackground >= _minimumBackgroundDuration) {
395+
[self loadBundle];
396+
}
397+
}
398+
399+
- (void)applicationWillResignActive
400+
{
401+
// Save the current time so that when the app is later
402+
// resumed, we can detect how long it was in the background.
403+
_lastResignedDate = [NSDate date];
404+
}
405+
383406
#pragma mark - JavaScript-exported module methods
384407

385408
/*
@@ -522,16 +545,27 @@ - (void)savePendingUpdate:(NSString *)packageHash
522545
[self savePendingUpdate:updatePackage[PackageHashKey]
523546
isLoading:NO];
524547

525-
if (installMode == CodePushInstallModeOnNextResume && !_hasResumeListener) {
526-
// Ensure we do not add the listener twice.
527-
// Register for app resume notifications so that we
528-
// can check for pending updates which support "restart on resume"
529-
[[NSNotificationCenter defaultCenter] addObserver:self
530-
selector:@selector(loadBundle)
531-
name:UIApplicationWillEnterForegroundNotification
532-
object:[UIApplication sharedApplication]];
533-
_hasResumeListener = YES;
548+
if (installMode == CodePushInstallModeOnNextResume) {
549+
_minimumBackgroundDuration = minimumBackgroundDuration;
550+
551+
if (!_hasResumeListener) {
552+
// Ensure we do not add the listener twice.
553+
// Register for app resume notifications so that we
554+
// can check for pending updates which support "restart on resume"
555+
[[NSNotificationCenter defaultCenter] addObserver:self
556+
selector:@selector(applicationWillEnterForeground)
557+
name:UIApplicationWillEnterForegroundNotification
558+
object:[UIApplication sharedApplication]];
559+
560+
[[NSNotificationCenter defaultCenter] addObserver:self
561+
selector:@selector(applicationWillResignActive)
562+
name:UIApplicationWillResignActiveNotification
563+
object:[UIApplication sharedApplication]];
564+
565+
_hasResumeListener = YES;
566+
}
534567
}
568+
535569
// Signal to JS that the update has been applied.
536570
resolve(nil);
537571
}

package-mixins.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ module.exports = (NativeCodePush) => {
3737
};
3838

3939
const local = {
40-
async install(installMode = NativeCodePush.codePushInstallModeOnNextRestart, updateInstalledCallback) {
40+
async install(installMode = NativeCodePush.codePushInstallModeOnNextRestart, minimumBackgroundDuration = 0, updateInstalledCallback) {
4141
const localPackage = this;
42-
await NativeCodePush.installUpdate(this, installMode);
42+
await NativeCodePush.installUpdate(this, installMode, minimumBackgroundDuration);
4343
updateInstalledCallback && updateInstalledCallback();
4444
if (installMode == NativeCodePush.codePushInstallModeImmediate) {
4545
NativeCodePush.restartApp(false);

0 commit comments

Comments
 (0)