tvOS Integration Skill

Integration conventions for the StreamLayer tvOS SDK that keep an AI agent's diff small and correct — where to initialize, the tvOS-specific createOverlay, delegate wiring, focus/remote, and ad breaks.

StreamLayer tvOS SDK Integration

How to wire StreamLayer into an existing tvOS app cleanly. Follow the rules —
they prevent the common over-integration mistakes.

This page is the human-readable form of the streamlayer-tvos-integration agent
skill. Reference it from your AI agent alongside the streamlayer-docs MCP — see
Integrate with an AI Agent.

📘

The tvOS SDK shares the iOS SDK

tvOS ships in the same StreamLayer package as iOS. For anything not called out
as tvOS-specific below, follow the iOS Integration Guide.

Pick the package

  • StreamLayer — the SDK, distributed as a dynamic framework via Swift
    Package Manager ([email protected]:StreamLayer/sdk-ios.git, product
    StreamLayer). Add the package, then import StreamLayerSDKTVOS (the tvOS
    module — not StreamLayerSDK).
  • Main UI element: the StreamLayer Element, created with
    StreamLayer.createOverlay(containerViewController:contentView:delegate:) and
    rendered on top of your player.
  • Requirements: Xcode 16+, Swift 6, tvOS 18+.

Rules (do this)

  1. Initialize once at launch; create the overlay in the player screen. Call
    StreamLayer.initSDK(with: key) exactly once at app launch (AppDelegate),
    then start your event with StreamLayer.createSession(for: eventId) after
    authentication completes. Build the
    Element in the view controller that owns the video — via
    createOverlay(containerViewController:contentView:delegate:). Note the tvOS
    signature differs from iOS: you pass your content view (the video
    container) and a StreamLayerTVOSDelegate, not the iOS overlay-delegate set.

    • ❌ Copying the iOS createOverlay(mainContainerViewController:overlayDelegate:…) call shape.
    • ✅ createOverlay(containerViewController: self, contentView: playerView, delegate: self).
  2. Implement StreamLayerTVOSDelegate for the player bridge. It has three
    methods: streamLayerDelegateUpdateDuckingState(_ enabled: Bool, fullyMuteHost: Bool)
    — lower your player volume when enabled is true (to zero when
    fullyMuteHost is true) and restore it when false. It has a default
    implementation, so a one-argument version compiles but is never called; the
    required streamLayerDelegateAdDidFinish(_ info: SLRAdInfo) — resume playback
    when info.isPausedAd is true; and the optional
    streamLayerDelegateAdDidStart(_ info: SLRAdInfo). Keep a strong owner of the
    delegate so callbacks keep firing.

  3. Let the SDK own focus and the remote. On tvOS the SDK handles Apple TV
    remote navigation and the focus engine for its Element automatically. Don't
    fight it — don't trap focus, don't intercept remote presses meant for the
    overlay while it's active, and keep your own focus guides outside the Element's
    region. Restore your normal focus environment after the Element dismisses.

  4. Drive ad breaks and the stream timeline. Call StreamLayer.startADBreak()
    / StreamLayer.stopADBreak() around your ad breaks, and
    StreamLayer.setStreamTimelineEnabled(_:player:) to feed stream time for
    spoiler-safe and timed units. For server-side ad insertion, set
    StreamLayer.shared.ssaiHostDelegate to react to willBeginAdBreak /
    didFinishAdBreak. Wire only what your app actually uses.

  5. Auth + credentials. Authenticate once after init —
    try await StreamLayer.setAnonymousAuth(), then createSession. The tvOS
    module has no bypass-token call — don't copy the iOS
    setAuthorizationBypass(token:schema:) or useAnonymousAuth(). The SDK API
    Key is a public, client-side value from StreamLayer Studio
    — a constant is fine; don't add .env scaffolding. User tokens are different:
    never hardcode them. Keep the diff minimal: fit
    the Element around your existing player screen instead of restructuring it.

Gotchas

  • createOverlay signature is different from iOS. tvOS takes contentView +
    StreamLayerTVOSDelegate; don't copy the iOS overlay-delegate call.
  • Wrong import. Use import StreamLayerSDKTVOS, not StreamLayerSDK.
  • initSDK called twice traps — it's a one-time call.
  • createOverlay before initSDK crashes. It dereferences the SDK
    singleton, so a lazy overlay property touched before init brings the app down.
  • Left-ducked audio. Always restore player volume when
    streamLayerDelegateUpdateDuckingState is called with enabled == false; forgetting to leaves the stream
    quiet after an ad or voice segment.
  • Focus traps. The most common tvOS pitfall — don't override
    preferredFocusEnvironments in a way that steals focus from the active Element.
  • Shared SDK. For dependencies, SDK API Key, and initialization mechanics not
    covered here, follow the iOS Integration Guide.
  • Authoritative API details: the streamlayer-docs MCP (search / fetch) and
    the tvOS docs.

Related