App icon for Peacock

Peacock

August 17, 2023

Peacock, NBCUniversal’s streaming app, was initially built with React Native (RN) but recently switched to native. We observed this migration in April 2023 — v4.5.13 for Android and v4.4.22 for iOS.

RN is a framework developed by Facebook that lets you create mobile apps for Android and iOS using JavaScript. Some of the reasons to use RN include:

  • Reduced complexity of 1 codebase providing multiple apps
  • Robust tooling set (Expo, Hermes, etc)
  • Active and engaged developer community

Below we'll look at how Peacock was built with RN and what happened when it switched to native.

React Native Builds

Peacock's RN builds share several frameworks and js files across platforms, although with some differences. Below you can see Emerge's X-Ray for iOS and Android, showing how the apps are built.

In both platforms, imports include Yoga, a React Native UI framework, and folly, a C++ utility package used by React Native. There are also a handful of libraries for image handling, animations, text, and more. Despite this, the project wasn't apparently using React Native to render UI (more on this below). Of note, we see that Peacock was not using Hermes, a popular RN framework used to improve RN performance.

X-Ray of Peacock iOS
X-Ray of Peacock iOS (interactive on larger screens)
X-Ray of Peacock iOS
Emerge X-Ray of Peacock Android
X-Ray of Peacock Android (interactive on larger screens)
X-Ray of Peacock Android

Switching to Native

Peacock switched to native in April. This let them rip out all React-related code, resulting in a 26% size decrease (-7.6 MB) on Android and 13% decrease (-12.6 MB) on iOS. Below is our X-Ray diff, showing how the apps changed between builds. The nodes in red were shrunk or completely removed:

iOS X-Ray diff from RN → Native. Shows many deleted files.
iOS X-Ray diff from RN → Native
iOS X-Ray diff from RN → Native

Android X-Ray diff from RN → Native. Shows many deleted files.
Android X-Ray diff from RN → Native
Android X-Ray diff from RN → Native

From the X-ray views you can see that the majority of the files that were removed were either precompiled binaries (.framework, .so) or js files. React Native imported utilites can now be replaced by native functionality if needed.

For example, RCTAnimation → CoreAnimation, RCTImage → UIImage/CoreImage RCTText → UIKit/CoreText, etc. Those native libraries don't take up space of your app, since they are provided by system frameworks, resulting in size reductions.

Impact on App Launch

Android

Android Performance Analysis

As observed in the report above, the Android app launch improved by roughly 18.2%. When switching to the base build (which used React Native), we can see the app takes ~400ms to initialize com.facebook.soLoader.init, based on our benchmarks done on Pixel 3 running Android 12:

Differential flamechart showing the improvement in startup between Android versions. When looking at the React Native build, the stack trace has a significant number of spans related to libraries loading RN. The version using native code has no such spans
Differential flamechart showing the improvement in startup between Android versions. When looking at the React Native build, the stack trace has a significant number of spans related to libraries loading RN. The version using native code has no such spans.

If we toggle the "invert" view, it shows that the functions taking the longest to run also happen to be the ones from Facebook:

Differential flamechart showing the improvement in startup between Android versions. When looking at the react native build, the stack trace has a significant number of spans related to libraries loading RN. The version using native code has no such spans
Differential flamechart highlighting React Native functions from Facebook.

These functions are completely removed when you switch to native as the libraries required for running React Native are no longer needed. So here's where they get back that precious launch time!

React Native vs. Native

Comparing hybrid frameworks (React Native, Flutter, Xamarin, etc.) with native ones is often a heated debate, as both sides have valid arguments. One of the main arguments in favor of RN is the ability to have a unified codebase, enabling multiple platforms to share code and potentially be more cost effective. On the native end, one of the strongest arguments is superior performance. React Native has come a long way and KPIs like launch time has been greatly improved by frameworks like Hermes, but native code will usually be more performant.

We heard from @nunovieira_dev, who previously worked at Peacock, and he shared that the UI was already native prior to these changes, as they were using React Native just to share the business logic. When they made these changes, they moved the business logic to JavaScriptCore (which basically consists of js files containing the business logic and runtime interpretation of those files using native code). However, they still intend to move away from this approach and implement 2 separate codebases, using native code for the business logic, as there are still performance issues with using JavaScriptCore.

TL;DR

When Peacock made the switch from React Native to Native, both iOS and Android saw a size decrease from removing a number of RN-related resources. We were also able to measure a significant app launch improvement for Android.

There are many good reasons to use React Native, from code reusability to community support, familiarity with js, ease of finding hires, etc. However, if the business app performance is paramount, native is usually superior, especially the more complex your app gets.

Sign up for our newsletter 🛸

Never miss a post or product update

Related articles



2024 © Emerge Tools, Inc. All rights reserved.