Skip to content

Commit

Permalink
Timing: Fixes timer when app get into background (facebook#24649)
Browse files Browse the repository at this point in the history
Summary:
Related facebook#23674, in that PR, we imported background timer support, but it's not sufficient, I think the reason that works is because it enable the `Background Modes` and do some background tasks, for the users who don't enable it, timer would pause immediately before goes into background.

To fix it, we can mark a background task when goes into background, it can keep app active for minutes, try best to support timing when in background.

cc. cpojer .

## Changelog

[iOS] [Fixed] - Timing: Fixes timer when app get into background
Pull Request resolved: facebook#24649

Differential Revision: D15554451

Pulled By: cpojer

fbshipit-source-id: a33f7afe6b63d1a4fefcb7098459aee0c09145da
  • Loading branch information
zhongwuzw authored and facebook-github-bot committed May 30, 2019
1 parent e8037cb commit 3382984
Showing 1 changed file with 30 additions and 0 deletions.
30 changes: 30 additions & 0 deletions React/Modules/RCTTiming.m
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ @implementation RCTTiming
NSTimer *_sleepTimer;
BOOL _sendIdleEvents;
BOOL _inBackground;
UIBackgroundTaskIdentifier _backgroundTaskIdentifier;
}

@synthesize bridge = _bridge;
Expand All @@ -112,6 +113,7 @@ - (void)setBridge:(RCTBridge *)bridge
_paused = YES;
_timers = [NSMutableDictionary new];
_inBackground = NO;
_backgroundTaskIdentifier = UIBackgroundTaskInvalid;

for (NSString *name in @[UIApplicationWillResignActiveNotification,
UIApplicationDidEnterBackgroundNotification,
Expand All @@ -135,10 +137,35 @@ - (void)setBridge:(RCTBridge *)bridge

- (void)dealloc
{
[self markEndOfBackgroundTaskIfNeeded];
[_sleepTimer invalidate];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)markStartOfBackgroundTaskIfNeeded
{
if (_backgroundTaskIdentifier == UIBackgroundTaskInvalid) {
__weak typeof(self) weakSelf = self;
// Marks the beginning of a new long-running background task. We can run the timer in the background.
_backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
typeof(self) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
// Mark the end of background task
[strongSelf markEndOfBackgroundTaskIfNeeded];
}];
}
}

- (void)markEndOfBackgroundTaskIfNeeded
{
if (_backgroundTaskIdentifier != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier];
_backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}
}

- (dispatch_queue_t)methodQueue
{
return RCTJSThread;
Expand All @@ -163,6 +190,7 @@ - (void)appDidMoveToBackground

- (void)appDidMoveToForeground
{
[self markEndOfBackgroundTaskIfNeeded];
_inBackground = NO;
[self startTimers];
}
Expand Down Expand Up @@ -260,6 +288,7 @@ - (void)didUpdateFrame:(RCTFrameUpdate *)update
}
if (_inBackground) {
if (timerCount) {
[self markStartOfBackgroundTaskIfNeeded];
[self scheduleSleepTimer:nextScheduledTarget];
}
} else if (!_sendIdleEvents && timersToCall.count == 0) {
Expand Down Expand Up @@ -338,6 +367,7 @@ - (void)timerDidFire
}

if (_inBackground) {
[self markStartOfBackgroundTaskIfNeeded];
[self scheduleSleepTimer:timer.target];
} else if (_paused) {
if ([timer.target timeIntervalSinceNow] > kMinimumSleepInterval) {
Expand Down

0 comments on commit 3382984

Please sign in to comment.