Developing a Video Streaming Mobile App
A video streaming app isn't just "AVPlayer + video list." It's CDN integration, adaptive bitrate, DRM, quality-of-experience analytics (QoE), offline loading, and catalog with search. Each major component has non-trivial technical solutions.
Adaptive Streaming: HLS and DASH
HLS (HTTP Live Streaming)—Apple standard, native support on iOS and macOS. On Android supported via ExoPlayer (Media3). DASH (Dynamic Adaptive Streaming over HTTP)—open standard, better Android support, iOS via ExoPlayer in WKWebView or third-party players.
For cross-platform—HLS as primary: native on iOS, ExoPlayer handles it on Android without extra setup.
Server transcodes to multiple renditions: 360p/500kbps, 720p/2.5Mbps, 1080p/5Mbps, 4K/15Mbps. ABR (Adaptive Bitrate) on client—ExoPlayer uses AdaptiveTrackSelection with DefaultBandwidthMeter. AVPlayer on iOS—built-in algorithm, adjusted via AVPlayerItem.preferredForwardBufferDuration and AVPlayerItem.preferredMaximumResolution.
// Android ExoPlayer — ABR and buffering setup
val trackSelector = DefaultTrackSelector(context).apply {
setParameters(
buildUponParameters()
.setMaxVideoSizeSd() // limit to 480p on weak networks
.setMinVideoBitrate(500_000)
.setForceHighestSupportedBitrate(false)
)
}
val loadControl = DefaultLoadControl.Builder()
.setBufferDurationsMs(
DefaultLoadControl.DEFAULT_MIN_BUFFER_MS,
30_000, // max buffer 30 seconds
1500, // startup buffer
3000 // resume after underrun
).build()
val player = ExoPlayer.Builder(context)
.setTrackSelector(trackSelector)
.setLoadControl(loadControl)
.build()
DRM: Protecting Paid Content
FairPlay (iOS) and Widevine (Android)—mandatory for monetized VOD. Scheme: on playback start, client gets license challenge → sends to DRM license server → gets license → decrypts stream.
Widevine Level 1 (L1) requires TEE—available on most modern Snapdragon/Exynos Android. L3—software protection, works everywhere, less reliable. Check level: MediaDrm.getPropertyString(MediaDrm.PROPERTY_SECURITY_LEVEL).
DRM license server: custom (Shaka Packager + Shaka Streamer), Axinom, BuyDRM, or cloud providers (AWS Elemental MediaConvert + AWS License Server, Azure Media Services).
Offline playback with DRM. iOS: AVAssetDownloadTask with FairPlay offline license (persistent). Android: ExoPlayer DownloadManager + offline Widevine license via OfflineLicenseHelper. License has expiry—account for when renewing subscription or canceling.
Catalog and Search
Catalog—Elasticsearch for full-text search with multi_match over title, description, cast. Faceted search: genres, year, rating via aggregations + filters. Autocomplete—edge_ngrams analyzer.
On mobile: lazy load posters via Glide/Coil (Android) or Kingfisher/Nuke (iOS) with DownsamplingImageProcessor—1920×1080 posters unnecessary in 3×3 grid.
Personalization: watch history, watchlist, "continue watching"—usually backend logic with Redis cache. On client—sync on app open + local state via CoreData/Room.
Quality of Experience (QoE)
QoE metrics—mandatory analytics for streaming:
- Buffering ratio: time buffering / playback time. Normal < 1%.
- Startup time: tap Play to first frame. Normal < 2 seconds.
- Bitrate switches: ABR changes. Frequent—unstable network or poorly tuned ABR.
- Error rate: 4xx/5xx from manifest/segment CDN.
Android: AnalyticsListener ExoPlayer—all events with timestamps. iOS: AVPlayerItemAccessLog, AVPlayerItemErrorLog. Aggregate via Firebase Analytics, Mixpanel, or custom pipeline.
Cast and AirPlay
Chromecast: Google Cast SDK on Android and iOS. GCKSessionManager + GCKRemoteMediaClient for TV playback control. Requires Google Cast Framework—adds ~1.5 MB.
AirPlay on iOS: out of the box via AVPlayer + MPNowPlayingInfoCenter. Ensure AVPlayerItem.externalPlaybackVideoGravity configured and allowsExternalPlayback = true.
Subtitles
WebVTT (preferred) or SRT—HLS subtitle formats. ExoPlayer supports both natively. iOS: AVAsset + AVMediaCharacteristicLegible track. Styling via AVTextStyleRule on iOS, SubtitleView styling on Android.
Multiple tracks: alternate audio via HLS EXT-X-MEDIA tags.
Timelines
MVP with HLS, catalog, basic search no DRM: 4–6 weeks. Full platform with DRM, offline, Cast/AirPlay, QoE analytics: 3–5 months. Cost calculated individually after analyzing requirements.







