One Video Player, Two Ecosystems, Forty-One Differences Closed

Every platform team was building its own video player and the implementations drifted apart. One codebase now ships to React Native and Unity on the same native engines, with 41 parity differences closed.

Start your project

The build

Iris Video Player is a drop-in HLS streaming player, engine and full interface, shipped as two packages from one codebase: a React Native package and a Unity package.

Both sit on the same native engines, Media3 and ExoPlayer on Android and AVPlayer on iOS. Aipxperts built it with reference applications for native Android, native iOS, React Native and Unity alongside. Its users are developers, not viewers. The people ultimately watching are families and children.

The problem

Every platform team was building its own video player, and the results diverged. That is a predictable outcome rather than a failure of care. A React Native team reaches for one library, a Unity team for another, and each solves the same twenty problems slightly differently. The cost shows up in three places:

Behaviour drifts

A gesture works one way in one app and another way somewhere else, and nobody notices until a user does.

Fixes do not travel

A bug found in the React Native player has to be found again, understood again and fixed again in Unity.

Playback stability suffers when a cross-platform abstraction sits between the app and the operating system's own decoder.

That last point rules out the obvious shortcut. Writing the player once in JavaScript or in C# would have given identical behaviour instantly and worse playback everywhere, which for a video product is the wrong trade.

What we built

We kept the decoders native and shared everything above them.

Adaptive HLS streaming

Automatic and manual quality selection, so the player adapts to the connection and the viewer can override it.

Full control overlay

Transport controls, scrub bar, playback speed and audio language selection.

Gesture controls

Volume and brightness swipe, plus pinch-to-zoom for aspect switching.

Child lock

Accidental-touch protection, which matters because the end viewers here are small children holding the device.

Playlists

Autoplay, next and previous, a carousel sheet and an end screen.

Offline downloads

Download progress and storage management through Media3's DownloadService.

Chromecast and AirPlay

Casting on both ecosystems, wired to the native implementations rather than reimplemented.

Picture-in-Picture

System PiP on both platforms, with the Unity build's post-processor patching the manifest and PiP configuration automatically at build time.

Layout and polish

Orientation handling, safe-area awareness, tablet-aware layout, haptics, and five theme presets including a Kids theme.

Unity editor tooling

A menu item that builds the entire player hierarchy in the editor, with the package distributed as an embedded folder so integrating teams can edit it directly.

The outcome

The engineering result is that a fix now happens once. The product result is that a child gets the same video experience whether the screen they are holding was built in React Native or in Unity.

Before
every platform team rebuilt the same player interface, and the implementations drifted apart in behaviour and appearance.
After
one player shipping as a React Native package and a Unity package, both on native decoders, with 41 parity findings identified and closed across overlay behaviour, sheets, playlist, casting, Picture-in-Picture, gestures and tablet scaling.

Tools and Technologies

Kotlin
Media3 / ExoPlayer
Swift
AVPlayer
React Native
TypeScript
Unity
C#
Chromecast
AirPlay
Picture-in-Picture

Planning something similar?

If several of your teams are maintaining their own version of the same component, the duplication is usually costing more than the rewrite would.

Start the conversation