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). 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) — lower your
    player volume when enabled is true and restore it when false; 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 —
    StreamLayer.setAnonymousAuth() for guest / demo playback, or your documented
    bypass-token flow for logged-in users. The SDK API Key is a public,
    client-side
    value from StreamLayer Studio
    — a constant is fine; don't add .env scaffolding. 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.
  • Left-ducked audio. Always restore player volume in
    streamLayerDelegateUpdateDuckingState(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