From bitmovin-player-web
Integrate and troubleshoot the Bitmovin Player SDK for iOS, tvOS, and visionOS in Swift, SwiftUI, UIKit, and existing Objective-C apps, including playback setup, player lifecycle, source loading, DRM, ads, AirPlay, Google Cast / Chromecast, PiP, platform-specific UX, logs, network diagnostics, and stream validation.
How this skill is triggered — by the user, by Claude, or both
Slash command
/bitmovin-player-web:bitmovin-player-iosThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Use the versioned Bitmovin Player Apple SDK markdown manifest as the authoritative reference for API behavior, class names, method signatures, setup steps, availability, and feature integration:
Use the versioned Bitmovin Player Apple SDK markdown manifest as the authoritative reference for API behavior, class names, method signatures, setup steps, availability, and feature integration:
https://cdn.bitmovin.com/player/ios/3/BitmovinPlayer-markdown-manifest.json
Version policy: if the app already uses a specific Bitmovin Player SDK version, prefer the matching versioned manifest when available. If the user has not specified a version or the matching manifest is unavailable, use the pinned manifest above until a newer source of truth is provided.
Lookup workflow:
documents[] by title or identifier for the API symbol/article.identifier, lowercase the full path, prefix it with /data, and append .md.Example:
identifier: /documentation/BitmovinPlayerCore/PlayerEventsApi
markdown: https://cdn.bitmovin.com/player/ios/3/data/documentation/bitmovinplayercore/playereventsapi.md
If a markdown file is unavailable, fall back to the corresponding DocC JSON at the same /data/...json path and state that the answer is derived from DocC JSON rather than markdown.
Use the samples repository as the implementation companion reference for wiring examples and end-to-end app setup:
https://github.com/bitmovin/bitmovin-player-ios-samples
Use iOS/tvOS/visionOS release notes to determine available versions, recent changes, migration notes, and the latest Bitmovin Player Apple SDK version:
https://developer.bitmovin.com/playback/docs/release-notes-ios.md
If examples, local source, cached snippets, or prior assumptions conflict with the manifest-backed markdown docs, follow the markdown docs.
Use this skill when the task involves Bitmovin Player SDK integration or troubleshooting in an Apple-platform app:
Unless the user or project explicitly requires a higher baseline, preserve these minimum deployment versions:
Use Swift Package Manager for new integrations.
In Xcode, add the Bitmovin Player SDK through Project > Package Dependencies with this package URL:
https://github.com/bitmovin/player-ios.git
For Package.swift based projects, add the package dependency and use the BitmovinPlayer product:
dependencies: [
.package(url: "https://github.com/bitmovin/player-ios.git", exact: "Version Number")
],
targets: [
.target(
name: "<NAME_OF_YOUR_PACKAGE>",
dependencies: [
.product(name: "BitmovinPlayer", package: "player-ios")
]
)
]
Replace Version Number with the desired SDK version. If a user has not requested a specific version, verify the current recommended/latest version before choosing one.
Note: command-line swift build is currently not supported for packages depending on BitmovinPlayer; open the package in Xcode instead.
CocoaPods is deprecated for this SDK and discouraged for new integrations. Only keep CocoaPods when maintaining an existing Podfile-based integration and the user explicitly wants to avoid migration. Prefer moving new work to Swift Package Manager.
The analytics / observability collector version can be updated independently from the player version. Do not force a Bitmovin Player SDK upgrade only to update the collector, as long as the selected collector satisfies the minimum version required by the installed player version.
Verify APIs before editing
Use one stable playback pipeline
Respect Apple lifecycle boundaries
Do not bypass the SDK
AVPlayer instance from the Bitmovin Player instance.AVPlayer access, treat that as a design roadblock and look for an SDK-supported API or escalate the missing capability to the user.Start troubleshooting from evidence
Derive roadblock-lifting guidance
Before code changes, inspect:
https://github.com/bitmovin/player-ios.git through Swift Package Manager and depend on the BitmovinPlayer product.The SwiftUI VideoPlayerView wrapper is suitable for inline playback, but SDK fullscreen is not supported through that SwiftUI wrapper yet because it does not expose the underlying PlayerView / fullscreenHandler surface.
If a SwiftUI app needs Bitmovin SDK fullscreen, wrap UIKit PlayerView in UIViewRepresentable, keep one stable PlayerView instance in the coordinator, set playerView.fullscreenHandler, and reparent that same view into a full-screen UIViewController on enter/exit. Do not create a second Player or replace the playback pipeline for fullscreen.
For fullscreen orientation behavior, check the app's supported interface orientations and make the presented fullscreen controller participate in rotation explicitly when needed.
For iOS Picture in Picture and background playback, wire all required layers together instead of setting only the SDK flag:
playerConfig.playbackConfig.isBackgroundPlaybackEnabled = true.playerViewConfig.pictureInPictureConfig.isEnabled = true.playerViewConfig.pictureInPictureConfig.shouldEnterOnBackground = true.AVAudioSession with a playback category such as .playback before playback starts.UIBackgroundModes with audio to the app's Info.plist or target configuration.UIBackgroundModes is actually present as an array containing audio; generated Info.plist build settings may not preserve this correctly in every project setup.Google Cast support is not just an SDK flag. Wire all three layers: Bitmovin Cast API, Google Cast sender SDK dependency, and iOS local-network discovery configuration.
Before editing:
Package.resolved, the project file, or the local package checkout.BitmovinCastManager.initializeCasting(...), PlayerConfig.remoteControlConfig.isCastEnabled, and, for custom controls, player.castVideo() / player.castStop().BitmovinPlayer SPM product includes the Google Cast sender SDK.For an SPM-based setup with the Google Cast binary SDK:
GoogleCastSPMProxy/Package.swift or mirror the user's existing sample path. The package should expose a product named GoogleCast backed by a binary target named GoogleCast.GoogleCastSDK-ios-4.8.4_dynamic.zip with checksum c9c3a794e8585198b59c6bb7da5418a3194ffa1ffa6f9a1cbdf4dc0ea26dc6cf, but verify the current URL/checksum before choosing a new version.GoogleCast product into every app target that enables casting. Prefer Xcode/package tooling when available; if manually patching project.pbxproj, follow the file's existing XCLocalSwiftPackageReference, XCSwiftPackageProductDependency, PBXBuildFile, packageReferences, and packageProductDependencies patterns exactly.Subproject commit ..., run git ls-files --stage <proxy-path> .gitmodules; mode 160000 means SwiftPM files inside the folder will not be visible as normal repo files.Typical app-side wiring:
import BitmovinPlayer
import SwiftUI
@main
struct PlaybackApp: App {
init() {
BitmovinCastManager.initializeCasting()
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Enable casting where the player config is created, keeping it near the existing playback configuration:
let playerConfig = PlayerConfig()
playerConfig.key = licenseKey
playerConfig.remoteControlConfig.isCastEnabled = true
let player = PlayerFactory.createPlayer(playerConfig: playerConfig)
For iOS 14+ local-network discovery, add Info.plist entries for Google Cast Bonjour services. For the default Bitmovin Cast receiver, include both the generic service and the receiver-specific service:
<key>NSBonjourServices</key>
<array>
<string>_googlecast._tcp</string>
<string>_FFE417E5._googlecast._tcp</string>
</array>
<key>NSLocalNetworkUsageDescription</key>
<string>This app uses the local network to discover Google Cast devices.</string>
If the app uses a custom receiver app id, replace FFE417E5 with that app id in the receiver-specific Bonjour entry after verifying the Bitmovin Cast initialization API for custom receivers.
After wiring:
plutil -lint on edited plist files.Package.resolved: local packages may not add pins, so absence of a Google Cast pin is not automatically a failure.The Apple SDK supports two client-side advertising module paths:
AdSource(..., ofType: .bitmovin). Prefer this path unless the user explicitly asks for IMA or the existing app already uses IMA.AdSource(..., ofType: .ima). This requires the Google IMA SDK to be linked by the app target in addition to the Bitmovin Player SDK; do not assume the BitmovinPlayer SPM product alone provides Google IMA.Before adding ads, identify the ad module, the ad tag type (VAST, VMAP, or another supported setup), and whether existing catalog metadata is placement-only. Fields such as ad_markers_json can describe where ads should appear, but they are not themselves VAST/VMAP ad supply unless the referenced payload contains an actual ad tag/config.
For a BAM pre-roll, keep the setup close to player construction:
let adSource = AdSource(tag: vastOrVmapTagUrl, ofType: .bitmovin)
let preRoll = AdItem(adSources: [adSource], atPosition: "pre")
playerConfig.advertisingConfig = AdvertisingConfig(schedule: [preRoll])
For IMA, first verify the current Google IMA installation instructions and the exact package/product or framework used by the project. Then add the Google IMA dependency to the same app target that links BitmovinPlayer, use .ima ad sources, and build the target after package resolution. If the user did not ask for IMA, do not add Google IMA.
Treat public sample VAST tags as placeholders only. Prefer product-owned ad tags/configuration when available, and make placeholder tags obvious in code or configuration.
Prefer the modern Combine-based event API for Swift integrations:
Swift files that use ObservableObject, @Published, AnyCancellable, or player.events.on(...) publishers need import Combine explicitly. Do not assume SwiftUI or Foundation imports make those symbols available in every file.
import Combine
final class PlaybackObserver {
private var cancellables = Set<AnyCancellable>()
func bind(to player: Player) {
player.events.on(ReadyEvent.self)
.sink { event in
// Handle player readiness.
}
.store(in: &cancellables)
player.events.on(PlayerErrorEvent.self)
.sink { event in
// Handle player errors.
}
.store(in: &cancellables)
player.events.on(SourceEvent.self)
.sink { event in
// Handle events emitted by the current source through the player.
}
.store(in: &cancellables)
}
}
SwiftUI can subscribe directly with onReceive when the subscription lifetime matches the view:
VideoPlayerView(player: player, playerViewConfig: playerViewConfig)
.onReceive(player.events.on(PlayerEvent.self)) { event in
// Observe all player events.
}
.onReceive(player.events.on(SourceEvent.self)) { event in
// Observe source events emitted through the player.
}
Event API guidance:
player.events.on(SomePlayerEvent.self) for player events.player.events.on(PlayerEvent.self) and player.events.on(SourceEvent.self).player.events.on(SourceEvent.self) for events from the current source as seen through the player.source.events.on(SomeSourceEvent.self) when observing a specific Source instance directly.playerView.events.on(SomePlayerViewEvent.self) for Swift-only PlayerView UI events.AnyCancellables for as long as observation should remain active.AVPlayer.Legacy and Objective-C guidance:
PlayerListener, SourceListener, and UserInterfaceListener through add(listener:) / remove(listener:).When diagnosing or integrating a non-trivial flow:
If the agent is stuck:
For unexpected HLS playback behavior, run mediastreamvalidator against the sample stream when it is installed:
mediastreamvalidator "https://example.com/path/to/master.m3u8"
AVPlayer instance instead of using Bitmovin Player APIsremoteControlConfig.isCastEnabled without linking the Google Cast sender SDK to the app targetSubproject commit ... instead of Package.swiftNSBonjourServices and NSLocalNetworkUsageDescription for Cast discovery on iOS 14+.ima ad sources without linking the Google IMA SDK to the affected app targetmediastreamvalidator, Charles, or log findings from the user because they are "only warnings"After integration changes, verify each applicable item:
Build/compile
Playback smoke test
Log health
Network evidence
Stream validity
mediastreamvalidator has been run for suspicious HLS streams when available, and results are summarized to the user.Lifecycle resilience
Platform UX
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.
npx claudepluginhub bitmovin/skills --plugin bitmovin-encoding-live