> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kontext.so/llms.txt
> Use this file to discover all available pages before exploring further.

# SwiftUI

> 在 SwiftUI 中通过 VideoAdHost 展示视频广告：设置广告即展示，设为 nil 即关闭。

SDK 用 UIKit 展示广告。`VideoAdHost` 是一个负责桥接的 SwiftUI 视图：把它放在播放器之上，设置它的 `ad`，广告就会展示。它属于 `KontextVideoSDK`，无需添加其他内容。

## 播放器页面

把播放器、`VideoAds` 和屏幕上的广告放在页面通过 `@StateObject` 持有的模型中：

```swift theme={null}
@MainActor
final class EpisodeModel: ObservableObject {
    let player: AVPlayer
    let ads: VideoAds
    @Published var adOnScreen: VideoAd?
    private var pauseAd: VideoAd?

    init(episode: Episode) {
        player = AVPlayer(url: episode.url)
        ads = VideoAds(content: episode.content)
        ads.track(player)
        Task { pauseAd = try? await prepare(.pause) }
    }

    func viewerPaused() {
        player.pause()
        adOnScreen = pauseAd           // VideoAdHost 展示它
    }

    func adEnded(_ ad: VideoAd, _ reason: VideoAd.EndReason) {
        adOnScreen = nil
        if reason == .resumed { player.play() }
        Task { pauseAd = try? await prepare(.pause) }   // 下一个，提前准备好
    }

    private func prepare(_ format: AdFormat) async throws -> VideoAd {
        let ad = try await ads.format(format)
        try await ad.load()
        return ad
    }
}

struct EpisodeScreen: View {
    @StateObject var model: EpisodeModel

    var body: some View {
        VideoPlayer(player: model.player)
            .overlay(VideoAdHost(ad: model.adOnScreen, onEnd: model.adEnded))
    }
}
```

## `VideoAdHost`

```swift theme={null}
VideoAdHost(
    ad: model.adOnScreen,
    insets: UIEdgeInsets(top: 0, left: 0, bottom: 80, right: 0),   // 避开你自己的控件
    onShowFailed: { ad, error in },     // 无法展示：没有展示任何内容，之后也不会有 onEnd
    onImpression: { ad in },
    onClick: { ad, click in },
    onEnd: { ad, reason in }            // 在这里把你的广告设回 nil
)
```

* **设置广告即展示。** 宿主在屏幕上且有尺寸后，已加载的广告就会展示。设为 `nil` 或另一个广告，当前展示的广告就会关闭；宿主离开视图层级时也会关闭。
* **所有格式。** 叠加广告或暂停广告展示在宿主所在的位置。线性广告从最顶层的视图控制器全屏呈现；宿主从不关闭它：它自行结束或由观众结束，`onEnd` 仍会送达。
* **宿主是广告的 delegate。** 通过宿主的闭包接收广告事件，而不是 `ad.delegate`。
* **`onShowFailed`** 收到 `show` 会抛出的原因：`anotherAdShowing`、`contentPaused`、`containerTooSmall` 等。
* **广告以外的点击** 会传给你的播放器，因此你自己的手势照常工作。

## 把广告放在模型中

SwiftUI 会重建视图结构体。把 `VideoAds` 放在你的 `@StateObject` 模型中，而不是视图中：释放 `VideoAds` 会结束它的广告。在观众真正离开剧集时（你的返回按钮、下一集）调用 `ads.destroy()`，而不是在 `onDisappear` 中：线性广告覆盖你的视图时，SwiftUI 也会调用 `onDisappear`。

## 在信息流中

为每一页提供自己的模型和宿主，只在当前页设置广告。被滑走的页面上的广告会在大约一秒内结束（`.interrupted`），为下一页的广告腾出屏幕。见[信息流中的广告](https://docs.kontext.so/zh/video/sdk/swift/guides/feeds.md)。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.