Add an option to skip Native Animated frames while the app is inactive - #58295
Open
zeyap wants to merge 1 commit into
Open
Add an option to skip Native Animated frames while the app is inactive#58295zeyap wants to merge 1 commit into
zeyap wants to merge 1 commit into
Conversation
Summary: On iOS, Native Animated drives frames from a `CADisplayLink` on the main run loop. While the app is inactive — which includes the whole `UIApplicationWillEnterForeground` → `UIApplicationDidBecomeActive` transition — it is not presenting, so a frame rendered then is never seen. Its commit and synchronous per-view updates still run on the main thread though, competing with the work the app must complete to become responsive. Adds `initWithSkipFramesDuringForegroundTransition:` to `RCTAnimatedModuleProvider`. When YES, `_onDisplayLinkTick` returns early while `applicationState == UIApplicationStateInactive`. Defaults to NO, so `init` and `new` are unchanged for existing callers; the host app decides, and can gate the decision however it likes. Two properties worth being explicit about: - **The clock is not stopped, only the frame is skipped.** `AnimationDriver` computes progress from a timestamp (`timeDeltaMs = frameTimeMs - startFrameTimeMs_`), so the first frame after activation resolves to the value the animation should have reached rather than resuming from where it was suspended. - **Frames are not skipped while backgrounded** — `Background` is not `Inactive`. Completion handlers, and any app logic they drive, are therefore delayed by at most the length of the transition, not by the time spent in the background. Reading `applicationState` rather than tracking lifecycle notifications also avoids a failure mode: a mirrored flag must be cleared on every path out of the transition, including an abandoned foregrounding (a `willEnterForeground` with no following `didBecomeActive`), or frames are skipped indefinitely. There is no such state to get stuck here. `UIApplicationStateInactive` also covers other non-presenting moments — Control Center, the app switcher, an incoming call banner. Skipping frames there is harmless for the same reason: the clock keeps running and the first frame after activation is correct. The check is inside the file's existing `TARGET_OS_OSX` guard, since `UIApplication` is iOS-only and this translation unit also builds for macOS. Changelog: [iOS][Added] - Add `initWithSkipFramesDuringForegroundTransition:` to `RCTAnimatedModuleProvider` Differential Revision: D118188111
|
@zeyap has exported this pull request. If you are a Meta employee, you can view the originating Diff in D118188111. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary:
On iOS, Native Animated drives frames from a
CADisplayLinkon the main runloop. While the app is inactive — which includes the whole
UIApplicationWillEnterForeground→UIApplicationDidBecomeActivetransition— it is not presenting, so a frame rendered then is never seen. Its commit and
synchronous per-view updates still run on the main thread though, competing
with the work the app must complete to become responsive.
Adds
initWithSkipFramesDuringForegroundTransition:toRCTAnimatedModuleProvider. When YES,_onDisplayLinkTickreturns early whileapplicationState == UIApplicationStateInactive. Defaults to NO, soinitandneware unchanged for existing callers; the host app decides, and can gate thedecision however it likes.
Two properties worth being explicit about:
AnimationDrivercomputes progress from a timestamp
(
timeDeltaMs = frameTimeMs - startFrameTimeMs_), so the first frame afteractivation resolves to the value the animation should have reached rather
than resuming from where it was suspended.
Backgroundis notInactive. Completion handlers, and any app logic they drive, are thereforedelayed by at most the length of the transition, not by the time spent in the
background.
Reading
applicationStaterather than tracking lifecycle notifications alsoavoids a failure mode: a mirrored flag must be cleared on every path out of the
transition, including an abandoned foregrounding (a
willEnterForegroundwithno following
didBecomeActive), or frames are skipped indefinitely. There is nosuch state to get stuck here.
UIApplicationStateInactivealso covers other non-presenting moments — ControlCenter, the app switcher, an incoming call banner. Skipping frames there is
harmless for the same reason: the clock keeps running and the first frame after
activation is correct.
The check is inside the file's existing
TARGET_OS_OSXguard, sinceUIApplicationis iOS-only and this translation unit also builds for macOS.Changelog:
[iOS][Added] - Add
initWithSkipFramesDuringForegroundTransition:toRCTAnimatedModuleProviderDifferential Revision: D118188111