SuperPlayer: A way to incorporate AVPlayer with The Composable Architecture

Tokopedia Play has become a demonstrative visual tour that showcases the looks and the benefits of the product listed on Tokopedia. Users can watch live or VOD content on Tokopedia Play. Other than Play, Tokopedia’s Feed and Product Detail Page also use videos to humanize the product experience.

In this article, we’re going to spill out a pinch of Tokopedia iOS’ secret recipe on how to built all video content and integrate it with many features in the app.

The Problem

In Tokopedia Play, AVPlayer and AVPlayerItem are used as a playback engine for streaming live and VOD content. However, since AVPlayer and AVPlayerItem use the Key-Value Observing (KVO) pattern to publish their playback states that force developers to write some tedious code to observe some properties such as timeControlStatus, reasonForWaitingToPlay, loadedTimeRanges, etc. Writing a pool of KVO patterns would even result in a messier code base.

Tokopedia iOS app is built on top of The Composable Architecture or TCA for short. Using plain AVPlayer to play a huge number of media displayed will lead to a messy codebase because it is not designed for effective integration with TCA. Every feature that plays videos needs to observe AVPlayer properties with inconsistent design patterns. This will take more development time and make the code hard to read and maintain. It’s also hard to collaborate when all developers built the features using different design patterns.

The Solution

SuperPlayer was created by Tokopedia’s iOS media team to wrap AVPlayer with composable business logic so it can be reused across any features built with TCA.

SuperPlayer includes,

  • Subscribing to all common playback states from AVFoundation in the intermediate object
  • Declaration of all the composable states, actions, and reducers for each playback state
  • Send the playback states to the store using defined actions and write any shared playback logic in the reducer

With SuperPlayer, developers don’t need to write any code inside the intermediate object and can directly plug it into their TCA environment. Moreover, any playback logic can be written fully in Reducer and can be tested later with all unit test tools provided by TCA.

Consistent design patterns used among features can increase the readability and maintainability of the code. Building features with less code leads to saving more development time.

Refer to this link to see how SuperPlayer works.

The Implementation

If the ParentViewController has another TCA Store, SuperPlayerState and SuperPlayerAction can be directly associated with the parent TCA State and Action, then pullback the SuperPlayerReducer to the parent Reducer. Only this time the SuperPlayer-scoped Store is the one that is going to be passed to the SuperPlayerViewController.

Based on the picture, developers do not have to worry about writing AVPlayer repetitive code like declaring playback state subscription that happens on the green column or writing the TCA representation of AVPlayer that is covered on the blue column. They just need to worry about their feature on the yellow column and how it integrates with the player.

Basic Architecture

The purpose of the architecture is to compose a player to any TCA component. Developers don’t need to worry about handling the property’s subscription code because components like AVPlayer and AVPlayerItem will be represented in state, action, and reducer.

ComposablePlayer

ComposablePlayerState
A struct that consists of AVPlayer subscribed properties. It also has an optional enum property named method of type ComposablePlayerMethod that is going to be subscribed in the intermediate object to call the actual AVPlayer methods.

ComposablePlayerMethod
An enum that consists of AVPlayer methods representation such as replaceCurrentItem(with: URL?), play, etc.

ComposablePlayerAction
An enum that consists of actions to be sent from the actual AVPlayer object.

ComposablePlayerReducer
A logic to assign values from the intermediate object sent as ComposablePlayerAction to ComposablePlayerState.

ComposablePlayerItem

The implementation of ComposablePlayerItem is very much similar to ComposablePlayer. The only difference is that ComposablePlayerItem represents the AVPlayerItem object.

SuperPlayer

SuperPlayerState
A struct that acts as a parent state that holds ComposablePlayerState and ComposablePlayerItemState. This is also the right place to extend other functionalities to the player.

SuperPlayerControlState
A struct that contains states for populating the playback control UI.

SuperPlayerAction
An enum that is used to modify SuperPlayerControlState and other extended states. It wraps ComposablePlayerAction and ComposablePlayerItemAction, and contains extended actions.

SuperPlayerReducer
This is where the pullback declared for both ComposablePlayerReducer and ComposablePlayerItemReducer. The logic inside can be executed when an intermediate object sent an action.

Basic API

In addition to declaring the TCA components above, an intermediate object needs to be created to accepts Store<SuperPlayerState, SuperPlayerAction>. SuperPlayerViewController will act as the intermediate object that performs the actual subscription to both store and the AVFoundation playback states.
SuperPlayerViewController is a UIViewController type that has AVPlayerLayer as its sublayer to display the video from AVPlayer.

How to use

You can refer to this article to set up SuperPlayer. Let’s start over there!

Summary

Most pages and features in Tokopedia are built with TCA as their architecture. TCA provides a way to break down business logic that feels like composing Lego blocks.
SuperPlayer helps create a new video player block, so developers can directly plug it into their TCA environment. Any playback logic can be written in the reducer and can be tested with tools provided by TCA. With this consistent design patterns used among features can increase the readability and maintainability of the code that leads to saving more development time.

Contribute🚨

Want to make a suggestion or feedback? SuperPlayer is open source and we’re excited to hear and learn from you. Your experiences will benefit others who use SuperPlayer. Let’s make it even better!

https://github.com/tokopedia/ios-superplayer

Credits

Thanks to Adityo Rancaka to make SuperPlayer happen. Also kudos to all developers who helped make this happen.

References

As always, we have an opening at Tokopedia.
We are an Indonesian technology company with a mission to democratize commerce through technology and help everyone achieve more.
Find your Dream Job with us in Tokopedia!
https://www.tokopedia.com/careers/

--

--

--

Story from people who build Tokopedia

Recommended from Medium

Default arguments in Swift

How to Use Xcode to Find Out the Shader Code Bug?

2021 Best Premium iOS App Templates written in SwiftUI

Recursion: A Swift story about recursion

Gatsby — Making sharp work with Apple M1

A Networking Manager with Alamofire

The Array in Swift

Storing Data in Core Data: UIImage

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Alvin Matthew Pratama

Alvin Matthew Pratama

More from Medium

Too Many Dependencies in iOS? Use the Composition Root Pattern

Distributing Binary Frameworks as Swift Packages

Error Handling with RxSwift

Warming Up To Havana: Accelerate iOS Builds With Binary Caching Using Tuist 2.x