Mobile Development 21 min read

How We Cut iOS Live‑Stream Power Use by Tuning Animation Frame Rates

This article details how the WeChat client team identified excessive GPU usage caused by like‑animation frames in iOS video‑channel live streams and applied iOS 15's preferredFrameRateRange API along with custom animation handling to lower frame rates, reduce power consumption, and maintain user experience.

WeChat Client Technology Team
WeChat Client Technology Team
WeChat Client Technology Team
How We Cut iOS Live‑Stream Power Use by Tuning Animation Frame Rates

Background

Power consumption has long been a pain point in app performance optimization, especially for long‑duration live‑stream scenarios. This article presents an unconventional solution to reduce iOS video‑channel live‑stream power usage without affecting the primary user experience.

Problem

Testing revealed that live streams with like animations doubled GPU usage and caused FPS to jump to 60 fps, even though the video stream itself is only 25–30 fps. The extra frames originated from the like animation driving the render loop at a higher rate.

Normally most video‑channel streams run at ≤30 fps, so rendering at that rate is sufficient. The like animation caused the Render Server to submit duplicate frames, inflating GPU load without improving visual quality.

Knowledge Base

This section introduces basic iOS animation concepts.

Animation Types

iOS animations can be classified based on the underlying API:

UIView block animation

Driven by +[UIView animateWithDuration:delay:options:animations:completion:] . All animations inside the block are triggered synchronously.

[UIView animateWithDuration:duration
        delay:0
        options:option
        animations:^{
            view.top -= offsetY;
            view.left -= offsetX;
        }
        completion:completion];

CAAnimation

Uses the Core Animation API directly.

CABasicAnimation *ani_position = [CABasicAnimation animationWithKeyPath:@"position"];
ani_position.fromValue = @(val.position.from);
ani_position.toValue = @(val.position.to);
[view.layer addAnimation:group forKey:key];

Timer

Animations driven by NSTimer/GCD or CADisplayLink . CADisplayLink is synchronized with the screen refresh rate, providing smoother results.

UIViewPropertyAnimator

Introduced in iOS 10, offers more flexible control over animation progress.

[UIViewPropertyAnimator runningPropertyAnimatorWithDuration:duration
        delay:0
        options:option
        animations:^{
            view.top -= offsetY;
            view.left -= offsetX;
        }
        completion:completion];

Animation Rendering

iOS UI updates and animations go through Core Animation and UIKit, both built on QuartzCore. UI changes are packaged into CA::Transaction and CAAnimation objects and sent to the Render Server, which finally invokes GPU APIs to draw on the screen.

App processes events (touch, display‑link timer, etc.).

App completes layout, image decode, and submits a transaction.

Render Server receives the transaction, accesses bitmap memory, and triggers GPU calls.

GPU finishes rendering and presents the frame.

The final screen update is performed by the Render Server (backboardd process).

In iOS, the Render Server (backboardd) works alongside SpringBoard to handle touch event distribution, animation submission, and UI updates. It can be observed in Time Profiler where backboardd processes image‑submission operations.

Frame‑Rate Reduction

iOS 15 introduced CAAnimation preferredFrameRateRange , which accepts minimum, maximum, and preferred frame rates. Apple recommends several frame‑rate tiers (see Figure 7).

Both CAAnimation and CADisplayLink share the same underlying driver ( CA::Display::DisplayLinkItem). By setting preferredFrameRateRange, the system can limit the number of frames submitted to the Render Server, reducing unnecessary GPU work.

Example: setContentOffset:animated

When [scrollView setContentOffset:animated:] is called, a UIScrollViewAnimation instance is created and registered with the UIUpdateCycle. The cycle decides whether to run at 120 Hz or 60 Hz based on device refresh rate and dynamic frame‑rate settings.

Each UIUpdateSequenceRun queries the animation for the current fraction of time, updates the content offset, and repeats until the target offset is reached.

Optimization Plan

Starting with iOS 15’s preferredFrameRateRange, we refactored four animation scenarios:

4.1 UIView block animation

By wrapping the original +[UIView animateWithDuration:…] call with a UIViewPropertyAnimator that sets the desired frame‑rate range, we can seamlessly lower the frame rate of any block animation.

if (@available(iOS 15.0, *)) {
    setFrameRateLevel(level);
    [UIViewPropertyAnimator runningPropertyAnimatorWithDuration:duration
                                                          delay:delay
                                                        options:options
                                                        animations:animations
                                                        completion:^(UIViewAnimatingPosition finalPosition) {
        if (completion) { completion(YES); }
    }];
    clearFrameRateLevel();
} else {
    if (level != MMAnimationFrameRateLevelNone) {
        if (level <= MMAnimationFrameRateLevelMedium)
            options |= UIViewAnimationOptionPreferredFramesPerSecond30;
    }
    [self animateWithDuration:duration delay:delay options:options animations:animations completion:completion];
}

4.2 UIScrollView animation

Implemented a custom animation using CADisplayLink with a configured preferredFrameRateRange to drive setContentOffset: manually.

- (void)tt_contentOffset:(CGPoint)contentOffset duration:(CFTimeInterval)duration {
    self.duration = duration;
    self.deltaContentOffset = CGPointMinus(contentOffset, self.scrollView.contentOffset);
    if (!self.displayLink) {
        self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateContentOffset:)];
        if (@available(iOS 15.0, *)) {
            self.displayLink.preferredFrameRateRange = CAFrameRateRangeMake(15, 24, 0);
        } else {
            self.displayLink.preferredFramesPerSecond = 30;
        }
        [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    } else {
        self.displayLink.paused = NO;
    }
}

4.3 NSTimer animation

Replaced NSTimer‑driven animations with CADisplayLink to keep animation callbacks in sync with the display refresh, avoiding extra frame submissions.

Optimization Results

Following Apple’s recommendation to lower FPS when the UI is static, we reduced the live‑stream FPS from 120 fps to 60 fps using UIViewAnimationOptionPreferredFramesPerSecond30 , and further limited block animations to 30–48 fps via UIViewPropertyAnimator . Overall GPU usage dropped 26 %–38 % and frame‑rate fell 16 % while visual quality remained unchanged.

Additional environment variables (e.g., QUARTZCORE_LOG_FILE, CA_PRINT_FRAME_INFO) were discovered to aid debugging.

setenv("QUARTZCORE_LOG_FILE", "stdout", 1) – output QuartzCore logs.

setenv("CA_PRINT_FRAME_INFO", "1", 1) – print frame info.

setenv("CA_LOG_MEMORY_USAGE", "1", 1) – log memory usage.

setenv("CA_PRINT_ANIMATIONS", "1", 1) – print animation details.

setenv("CA_ASSERT_MAIN_THREAD_TRANSACTIONS", "1", 1) – detect UI work on background threads.

Extended Discussion

For high‑frame‑rate streams we apply a subtle, lossless down‑sampling strategy: when the device overheats, we drop the 60 fps stream to 48 fps by uniformly discarding frames on the render side, achieving up to 28 % GPU reduction without perceptible visual impact.

Conclusion

By extending system interfaces and conducting thorough experiments, we implemented a complete UI‑animation frame‑rate tuning solution that:

Rapidly retrofits existing business animations with dynamic frame‑rate control.

Significantly reduces power consumption without affecting user experience.

Alleviates the workload for developers adapting to multiple iOS versions.

The solution has been widely deployed in the video‑channel live‑stream feature, delivering noticeable performance gains.

References

Optimize for variable refresh rate displays

Power down: Improve battery consumption

Explore UI animation hitches and the render loop

Demystify and eliminate hitches in the render phase

Advanced Graphics and Animations for iOS Apps

animationiOSFrame RatePower Optimization
WeChat Client Technology Team
Written by

WeChat Client Technology Team

Official account of the WeChat mobile client development team, sharing development experience, cutting‑edge tech, and little‑known stories across Android, iOS, macOS, Windows Phone, and Windows.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.