A sample iOS application demonstrating the Gumlet Video Player SDK, including offline downloads and FairPlay DRM.
- HLS and MP4 playback
- FairPlay DRM (online)
- Offline downloads with progress tracking, pause and resume
- Offline DRM playback using persistent FairPlay keys
- A "My Downloads" screen with play / pause / resume / delete
- Player event callbacks via
GumletPlayerListener - Download event callbacks via
GumletDownloadListener - Background-session completion handling
- Live SDK debug log viewer
Every public SDK API is exercised somewhere in the demo:
| API | Where |
|---|---|
GumletInitParams, load(params:) |
PlayerViewWrapper |
setPlayerListener / GumletPlayerListener |
PlayerViewWrapper.Coordinator — errors shown as a banner |
setControlsEnabled |
PlayerViewWrapper.updateUIView |
onPause / onResume / onDestroy |
PlayerHolder, driven by scenePhase in PlayerScreen |
downloadVideo / removeDownload |
ContentView.startDownload, DownloadsView |
pauseDownload / resumeDownload |
DownloadsView row actions |
addDownloadListener / GumletDownloadListener |
DownloadsModel |
getAllDownloads / getDownloadState |
DownloadsModel.refresh, ContentView.startDownload |
getDrmLicenseUrl / getCertificateUrl |
DownloadsView.playOffline |
getPersistentKeyUrl |
"Offline key" badge on each download row |
handleBackgroundEvents |
AppDelegate |
GumletLogger + isDebugLoggingEnabled |
DebugLogView, app init() |
- Xcode 13.2+
- iOS 17.6+ (the demo's deployment target; the SDK itself supports iOS 13+)
- A physical device — FairPlay DRM does not work on the Simulator
| File | Purpose |
|---|---|
gumletVideoPlayerDemoApp.swift |
App entry point; primes GumletDownloadManager, enables debug logging, forwards background-session events via AppDelegate |
ContentView.swift |
Configuration screen, DebugLogView, and PlayerScreen |
DownloadsView.swift |
DownloadsModel (listener-driven) and the "My Downloads" list |
PlayerViewWrapper.swift |
UIViewRepresentable bridge to GumletPlayerView, plus PlayerHolder |
The project consumes the published SDK from Swift Package Manager, pinned to an exact version:
https://github.com/gumlet/spm-releases — exact version 1.0.3
Package.resolved is committed so everyone builds against the same binary.
To iterate on the SDK itself without cutting a release, swap the remote reference for a local one:
- Select the
GumletVideoPlayerpackage in the Project Navigator and delete it. - File > Add Package Dependencies... > Add Local...
- Choose
../IOS-SDK/GumletVideoPlayer. - Add
GumletVideoPlayerto thegumletVideoPlayerDemotarget.
Note: the SDK's
Package.swiftdeclares a static library. A local package built astype: .dynamicfails to embed and sign correctly for device and the app dies at launch in dyld. The release script flips it to dynamic only while building the XCFramework.
Remember to switch back to the pinned remote version before committing.
If you hit package resolution errors, use File > Packages > Reset Package Caches and Product > Clean Build Folder (
⇧⌘K).
- Launch the app.
- Leave Enable DRM off.
- Tap ▶ Play Online.
- Turn Enable DRM on.
- Fill in the DRM License URL and Certificate URL.
- Tap ▶ Play Online.
The DRM fields only apply when the toggle is on. This prevents a leftover license URL from a previous test silently hijacking plain playback.
- Enable DRM (if the content is protected) and enter the URLs.
- Tap ⬇ Download for Offline.
- Open 📁 My Downloads and wait for ✓ Downloaded.
- Confirm the row shows a green 🔒 Offline key badge. Without it, playback will still need the network for the license — see the backend section below.
- Turn on Airplane Mode.
- Tap ▶ Play on the entry.
Airplane Mode matters: on Wi-Fi the SDK silently falls back to streaming, so an offline bug looks like success.
Downloads in progress can be paused and resumed from the same row.
- Configuration (URLs, toggles) is persisted with
@AppStorage, so signed FairPlay URLs survive relaunches. - The video URL doubles as the
videoId, matching the Android demo. - Deleting asks for confirmation and removes both the media and its offline DRM key.
For true offline DRM the license URL must request a persistable key. See the SDK README for the full details, but in short:
https://fairplay.gumlet.com/licence/<org_id>/<asset_id>
?expires=<ms_timestamp>
&storage_duration=2592000
&playback_duration=86400
&token=<signature>
storage_duration and playback_duration must be present in both the URL and the string your backend signs. Without them Gumlet returns a streaming-only key and offline playback falls back to needing the network.
Tap Show Debug Logs on the main screen for live SDK output — certificate fetch, SPC/CKC exchange, persistent key storage, resolved offline path, and downloaded package size. Copy All puts the whole session on the clipboard, which is the fastest way to hand a failure to someone else.
Verbose logging is off by default in the SDK; this demo turns it on for debug builds in gumletVideoPlayerDemoApp.swift:
#if DEBUG
GumletLogger.shared.isDebugLoggingEnabled = true
#endifWithout it you'll still see errors and playback mode, but not the DRM payloads or package inspection.
-
"No such module 'GumletVideoPlayer'" Confirm the package is in the target's Frameworks, Libraries, and Embedded Content, then Clean Build Folder (
⇧⌘K). -
App crashes at launch with a dyld error Usually a stale build artifact after switching between local and remote packages. Clean Build Folder, File > Packages > Reset Package Caches, then delete
~/Library/Developer/Xcode/DerivedData/gumletVideoPlayerDemo-*. -
DRM playback fails Verify the license and certificate URLs, and check the token has not expired. Note the certificate URL must not have a trailing slash. Check the Debug Logs for the exact server response.
-
Offline playback falls back to streaming Delete the download and re-download — a video first downloaded without DRM will not have a persistent key, and the stale entry blocks the key flow from running.
Copyright © 2026 Gumlet. All rights reserved.