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

Commit 54351db

Browse files
installModes: implement new ON_NEXT_SUSPEND install mode (#770)
Restart the app _while_ it is in the background, but only after it has been in the background for "minimumBackgroundDuration" seconds (0 by default), so that user context isn't lost unless the app suspension is long enough to not matter.
1 parent 068a9b8 commit 54351db

File tree

6 files changed

+47
-6
lines changed

6 files changed

+47
-6
lines changed

CodePush.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,10 @@ if (NativeCodePush) {
497497
InstallMode: {
498498
IMMEDIATE: NativeCodePush.codePushInstallModeImmediate, // Restart the app immediately
499499
ON_NEXT_RESTART: NativeCodePush.codePushInstallModeOnNextRestart, // Don't artificially restart the app. Allow the update to be "picked up" on the next app restart
500-
ON_NEXT_RESUME: NativeCodePush.codePushInstallModeOnNextResume // Restart the app the next time it is resumed from the background
500+
ON_NEXT_RESUME: NativeCodePush.codePushInstallModeOnNextResume, // Restart the app the next time it is resumed from the background
501+
ON_NEXT_SUSPEND: NativeCodePush.codePushInstallModeOnNextSuspend // Restart the app _while_ it is in the background,
502+
// but only after it has been in the background for "minimumBackgroundDuration" seconds (0 by default),
503+
// so that user context isn't lost unless the app suspension is long enough to not matter
501504
},
502505
SyncStatus: {
503506
UP_TO_DATE: 0, // The running app is up-to-date

android/app/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
public enum CodePushInstallMode {
44
IMMEDIATE(0),
55
ON_NEXT_RESTART(1),
6-
ON_NEXT_RESUME(2);
6+
ON_NEXT_RESUME(2),
7+
ON_NEXT_SUSPEND(3);
78

89
private final int value;
910
CodePushInstallMode(int value) {

android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ public Map<String, Object> getConstants() {
6767
constants.put("codePushInstallModeImmediate", CodePushInstallMode.IMMEDIATE.getValue());
6868
constants.put("codePushInstallModeOnNextRestart", CodePushInstallMode.ON_NEXT_RESTART.getValue());
6969
constants.put("codePushInstallModeOnNextResume", CodePushInstallMode.ON_NEXT_RESUME.getValue());
70+
constants.put("codePushInstallModeOnNextSuspend", CodePushInstallMode.ON_NEXT_SUSPEND.getValue());
7071

7172
constants.put("codePushUpdateStateRunning", CodePushUpdateState.RUNNING.getValue());
7273
constants.put("codePushUpdateStatePending", CodePushUpdateState.PENDING.getValue());
@@ -438,7 +439,8 @@ protected Void doInBackground(Void... params) {
438439
// We also add the resume listener if the installMode is IMMEDIATE, because
439440
// if the current activity is backgrounded, we want to reload the bundle when
440441
// it comes back into the foreground.
441-
installMode == CodePushInstallMode.IMMEDIATE.getValue()) {
442+
installMode == CodePushInstallMode.IMMEDIATE.getValue() ||
443+
installMode == CodePushInstallMode.ON_NEXT_SUSPEND.getValue()) {
442444

443445
// Store the minimum duration on the native module as an instance
444446
// variable instead of relying on a closure below, so that any
@@ -449,9 +451,18 @@ protected Void doInBackground(Void... params) {
449451
// Ensure we do not add the listener twice.
450452
mLifecycleEventListener = new LifecycleEventListener() {
451453
private Date lastPausedDate = null;
454+
private Handler appSuspendHandler = new Handler(Looper.getMainLooper());
455+
private Runnable loadBundleRunnable = new Runnable() {
456+
@Override
457+
public void run() {
458+
CodePushUtils.log("Loading bundle on suspend");
459+
loadBundle();
460+
}
461+
};
452462

453463
@Override
454464
public void onHostResume() {
465+
appSuspendHandler.removeCallbacks(loadBundleRunnable);
455466
// As of RN 36, the resume handler fires immediately if the app is in
456467
// the foreground, so explicitly wait for it to be backgrounded first
457468
if (lastPausedDate != null) {
@@ -469,6 +480,10 @@ public void onHostPause() {
469480
// Save the current time so that when the app is later
470481
// resumed, we can detect how long it was in the background.
471482
lastPausedDate = new Date();
483+
484+
if (installMode == CodePushInstallMode.ON_NEXT_SUSPEND.getValue() && mSettingsManager.isPendingUpdate(null)) {
485+
appSuspendHandler.postDelayed(loadBundleRunnable, minimumBackgroundDuration * 1000);
486+
}
472487
}
473488

474489
@Override

ios/CodePush/CodePush.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,8 @@ void CPLog(NSString *formatString, ...);
187187
typedef NS_ENUM(NSInteger, CodePushInstallMode) {
188188
CodePushInstallModeImmediate,
189189
CodePushInstallModeOnNextRestart,
190-
CodePushInstallModeOnNextResume
190+
CodePushInstallModeOnNextResume,
191+
CodePushInstallModeOnNextSuspend
191192
};
192193

193194
typedef NS_ENUM(NSInteger, CodePushUpdateState) {

ios/CodePush/CodePush.m

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ @implementation CodePush {
2424
BOOL _isFirstRunAfterUpdate;
2525
int _minimumBackgroundDuration;
2626
NSDate *_lastResignedDate;
27+
CodePushInstallMode *_installMode;
28+
NSTimer *_appSuspendTimer;
2729

2830
// Used to coordinate the dispatching of download progress events to JS.
2931
long long _latestExpectedContentLength;
@@ -292,6 +294,7 @@ - (NSDictionary *)constantsToExport
292294
@"codePushInstallModeOnNextRestart":@(CodePushInstallModeOnNextRestart),
293295
@"codePushInstallModeImmediate": @(CodePushInstallModeImmediate),
294296
@"codePushInstallModeOnNextResume": @(CodePushInstallModeOnNextResume),
297+
@"codePushInstallModeOnNextSuspend": @(CodePushInstallModeOnNextSuspend),
295298

296299
@"codePushUpdateStateRunning": @(CodePushUpdateStateRunning),
297300
@"codePushUpdateStatePending": @(CodePushUpdateStatePending),
@@ -559,6 +562,10 @@ - (void)savePendingUpdate:(NSString *)packageHash
559562
// a resume-based update still pending installation.
560563
- (void)applicationWillEnterForeground
561564
{
565+
if (_appSuspendTimer) {
566+
[_appSuspendTimer invalidate];
567+
_appSuspendTimer = nil;
568+
}
562569
// Determine how long the app was in the background and ensure
563570
// that it meets the minimum duration amount of time.
564571
int durationInBackground = 0;
@@ -576,6 +583,18 @@ - (void)applicationWillResignActive
576583
// Save the current time so that when the app is later
577584
// resumed, we can detect how long it was in the background.
578585
_lastResignedDate = [NSDate date];
586+
587+
if (_installMode == CodePushInstallModeOnNextSuspend && [[self class] isPendingUpdate:nil]) {
588+
_appSuspendTimer = [NSTimer scheduledTimerWithTimeInterval:_minimumBackgroundDuration
589+
target:self
590+
selector:@selector(loadBundleOnTick:)
591+
userInfo:nil
592+
repeats:NO];
593+
}
594+
}
595+
596+
-(void)loadBundleOnTick:(NSTimer *)timer {
597+
[self loadBundle];
579598
}
580599

581600
#pragma mark - JavaScript-exported module methods (Public)
@@ -749,7 +768,8 @@ - (void)applicationWillResignActive
749768
[self savePendingUpdate:updatePackage[PackageHashKey]
750769
isLoading:NO];
751770

752-
if (installMode == CodePushInstallModeOnNextResume) {
771+
_installMode = installMode;
772+
if (_installMode == CodePushInstallModeOnNextResume || _installMode == CodePushInstallModeOnNextSuspend) {
753773
_minimumBackgroundDuration = minimumBackgroundDuration;
754774

755775
if (!_hasResumeListener) {

ios/CodePush/RCTConvert+CodePushInstallMode.m

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ @implementation RCTConvert (CodePushInstallMode)
1212

1313
RCT_ENUM_CONVERTER(CodePushInstallMode, (@{ @"codePushInstallModeImmediate": @(CodePushInstallModeImmediate),
1414
@"codePushInstallModeOnNextRestart": @(CodePushInstallModeOnNextRestart),
15-
@"codePushInstallModeOnNextResume": @(CodePushInstallModeOnNextResume) }),
15+
@"codePushInstallModeOnNextResume": @(CodePushInstallModeOnNextResume),
16+
@"codePushInstallModeOnNextSuspend": @(CodePushInstallModeOnNextSuspend) }),
1617
CodePushInstallModeImmediate, // Default enum value
1718
integerValue)
1819

0 commit comments

Comments
 (0)