Skip to content

Commit 3382984

Browse files
zhongwuzwfacebook-github-bot
authored andcommitted
Timing: Fixes timer when app get into background (#24649)
Summary: Related #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: #24649 Differential Revision: D15554451 Pulled By: cpojer fbshipit-source-id: a33f7afe6b63d1a4fefcb7098459aee0c09145da
1 parent e8037cb commit 3382984

File tree

1 file changed

+30
-0
lines changed

1 file changed

+30
-0
lines changed

React/Modules/RCTTiming.m

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ @implementation RCTTiming
9797
NSTimer *_sleepTimer;
9898
BOOL _sendIdleEvents;
9999
BOOL _inBackground;
100+
UIBackgroundTaskIdentifier _backgroundTaskIdentifier;
100101
}
101102

102103
@synthesize bridge = _bridge;
@@ -112,6 +113,7 @@ - (void)setBridge:(RCTBridge *)bridge
112113
_paused = YES;
113114
_timers = [NSMutableDictionary new];
114115
_inBackground = NO;
116+
_backgroundTaskIdentifier = UIBackgroundTaskInvalid;
115117

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

136138
- (void)dealloc
137139
{
140+
[self markEndOfBackgroundTaskIfNeeded];
138141
[_sleepTimer invalidate];
139142
[[NSNotificationCenter defaultCenter] removeObserver:self];
140143
}
141144

145+
- (void)markStartOfBackgroundTaskIfNeeded
146+
{
147+
if (_backgroundTaskIdentifier == UIBackgroundTaskInvalid) {
148+
__weak typeof(self) weakSelf = self;
149+
// Marks the beginning of a new long-running background task. We can run the timer in the background.
150+
_backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
151+
typeof(self) strongSelf = weakSelf;
152+
if (!strongSelf) {
153+
return;
154+
}
155+
// Mark the end of background task
156+
[strongSelf markEndOfBackgroundTaskIfNeeded];
157+
}];
158+
}
159+
}
160+
161+
- (void)markEndOfBackgroundTaskIfNeeded
162+
{
163+
if (_backgroundTaskIdentifier != UIBackgroundTaskInvalid) {
164+
[[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier];
165+
_backgroundTaskIdentifier = UIBackgroundTaskInvalid;
166+
}
167+
}
168+
142169
- (dispatch_queue_t)methodQueue
143170
{
144171
return RCTJSThread;
@@ -163,6 +190,7 @@ - (void)appDidMoveToBackground
163190

164191
- (void)appDidMoveToForeground
165192
{
193+
[self markEndOfBackgroundTaskIfNeeded];
166194
_inBackground = NO;
167195
[self startTimers];
168196
}
@@ -260,6 +288,7 @@ - (void)didUpdateFrame:(RCTFrameUpdate *)update
260288
}
261289
if (_inBackground) {
262290
if (timerCount) {
291+
[self markStartOfBackgroundTaskIfNeeded];
263292
[self scheduleSleepTimer:nextScheduledTarget];
264293
}
265294
} else if (!_sendIdleEvents && timersToCall.count == 0) {
@@ -338,6 +367,7 @@ - (void)timerDidFire
338367
}
339368

340369
if (_inBackground) {
370+
[self markStartOfBackgroundTaskIfNeeded];
341371
[self scheduleSleepTimer:timer.target];
342372
} else if (_paused) {
343373
if ([timer.target timeIntervalSinceNow] > kMinimumSleepInterval) {

0 commit comments

Comments
 (0)