iOS Integration Skill

Integration conventions for the StreamLayer iOS SDK that keep an AI agent's diff small and correct — where to initialize, where to create the overlay, delegate wiring, and minimal-diff placement.

StreamLayer iOS SDK Integration

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

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

Pick the package

  • StreamLayer — the iOS SDK, distributed as a dynamic framework via Swift
    Package Manager ([email protected]:StreamLayer/sdk-ios.git, product
    StreamLayer). Add the package, then import StreamLayerSDK.
  • Main UI element: SLRWidgetsViewController — the StreamLayer Element,
    created with StreamLayer.createOverlay(...) and embedded over your player.
  • Optional plugins (separate package,
    github.com/StreamLayer/sdk-ios-plugins): StreamLayerSDKPluginsGooglePAL,
    StreamLayerSDKPluginsPermissions, StreamLayerSDKPluginsWatchParty — install
    only the ones you need.
  • Requirements: Xcode 16+, Swift 6, iOS 15+.

Rules (do this)

  1. Initialize once and high; create the overlay low. Call
    StreamLayer.initSDK(with:delegate:loggerDelegate:) exactly once at app launch
    (AppDelegate.application(_:didFinishLaunchingWithOptions:)), after setting any
    StreamLayer.config.* options. Create the StreamLayer Element
    (StreamLayer.createOverlay(...)) inside the player screen's view
    controller — the one that owns the video and its play/pause state — not in the
    app delegate, and not as a global singleton view.

    • initSDK inside the player view controller; ❌ createOverlay in the app delegate.
    • initSDK in AppDelegate; createOverlay lazily in the player view controller.
  2. Add the overlay as a child view controller, pinned over your player
    container.
    createOverlay returns an SLRWidgetsViewController. Add it with
    addChild / didMove(toParent:) and pin its view to the container that holds
    the video — not the whole window. Put your own content on a containerView you
    own and call containerView.addSubview(...), not view.addSubview(...), so the
    SDK can resize the container for sidebar / L-bar layouts. One overlay instance
    per player screen.

  3. Drive layout with setNeedsLayout(); wire only the delegates your features
    use.
    Call StreamLayer.setNeedsLayout() from viewDidLayoutSubviews() and
    after rotations / size transitions so the Element re-lays out. Implement
    SLROverlayDelegate for the player bridge (audio ducking, pauseVideo /
    playVideo, getPlayerVolume / setPlayerVolume, switchStream) — all
    methods are optional
    ; wire the ones your app needs and leave the rest. Add
    SLROverlayDataSource.overlayHeight() for vertical placement, and
    SLRSideBarDelegate only if you enable StreamLayer.config.overlayMode = .sidebar.

  4. Forward authentication after init. For logged-in users, call
    StreamLayer.setAuthorizationBypass(token:schema:) with a token from your
    backend; for demos or guests use StreamLayer.useAnonymousAuth(). Do it once,
    after initSDK. Follow the documented auth-forwarding flow rather than
    inventing a login screen. Start a session for your event with
    StreamLayer.createSession(for: eventId) in the player screen.

  5. Keep credentials and the diff simple. The SDK API Key is a public,
    client-side
    value from StreamLayer Studio
    — a constant or your existing config is fine; don't add .env scaffolding or
    dev-only warnings. Fit the overlay around your existing player and layout —
    don't restructure the app, add wrapper view controllers, or refactor unrelated
    view code. Register optional plugins (registerPALPlugin,
    registerPermissionsPlugin, registerWatchPartyPlugin) before use, and only
    the ones you need.

Gotchas

  • StreamLayer Element not showing. Almost always a missing
    StreamLayer.setNeedsLayout() after a layout / rotation change, or the widgets
    view added to view instead of the containerView the SDK resizes.
  • initSDK called twice traps — it's a one-time call. Guard against re-init
    across multiple scenes or SwiftUI previews.
  • Delegate methods not firing. The delegate / data source must be assigned
    when you call createOverlay, and must have a strong owner — a deallocated
    delegate silently stops callbacks.
  • iPad-only surfaces. Some paused-ad variants render on iPad only (see the
    Exposed Ads section of the API Reference); don't rely on
    them on iPhone.
  • Internal architecture is not your concern. VIPER, RxSwift, and the DI
    container are SDK internals — you only touch the StreamLayer facade, its
    delegates, and StreamLayer.config. Don't try to subclass or reach into them.
  • Authoritative API details: the streamlayer-docs MCP (search / fetch) and
    the API Reference.

Related