Skip to content

Add an option to skip Native Animated frames while the app is inactive - #58295

Open
zeyap wants to merge 1 commit into
react:mainfrom
zeyap:export-D118188111
Open

Add an option to skip Native Animated frames while the app is inactive#58295
zeyap wants to merge 1 commit into
react:mainfrom
zeyap:export-D118188111

Conversation

@zeyap

@zeyap zeyap commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary:
On iOS, Native Animated drives frames from a CADisplayLink on the main run
loop. While the app is inactive — which includes the whole
UIApplicationWillEnterForegroundUIApplicationDidBecomeActive 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 backgroundedBackground 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

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
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Sep 2, 2026
@meta-codesync

meta-codesync Bot commented Sep 2, 2026

Copy link
Copy Markdown

@zeyap has exported this pull request. If you are a Meta employee, you can view the originating Diff in D118188111.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. meta-exported p: Facebook Partner: Facebook Partner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant