> ## 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.

# AVPlayer

> 把 AVPlayer 交给 SDK：ads.track(player)。

SDK 会跟随你的内容播放器：观众在剧集中的位置，以及内容是否在播放。叠加广告只在内容播放时展示，观众暂停时结束；暂停广告在内容再次播放时结束。`AVPlayer` 不需要适配器：`track(_:)` 直接接受它。

## 跟随播放器

```swift theme={null}
player.replaceCurrentItem(with: AVPlayerItem(url: episode.url))
ads.track(player)          // 这一集进入播放器之后
player.play()
```

* **任何 `AVPlayer`**，包括 `AVQueuePlayer`，无论在哪里渲染：`AVPlayerLayer`、`AVPlayerViewController`、SwiftUI 的 `VideoPlayer`。
* **弱持有：** SDK 绝不会让你的播放器保持存活。它在 `destroy()` 或下一次 `track(_:)` 时放开。
* **在剧集开始播放时调用**，而不是在创建 `VideoAds` 时：在那之前播放器的时间属于上一集。在那之前 SDK 发送 0，这对预取来说是正确的。

## 多集共用一个播放器

大多数应用复用一个播放器并替换它的播放项。每一集的播放项进入播放器后，用该集的 `VideoAds` 跟随它：

```swift theme={null}
func open(_ episode: Episode) {
    ads?.destroy()                                     // 如果片尾广告在屏幕上，在它的 didEnd 之后
    ads = VideoAds(content: episode.content)
    player.replaceCurrentItem(with: AVPlayerItem(url: episode.url))
    ads?.track(player)
}
```

如果在播放项更换之前跟随，新剧集的叠加广告和暂停广告会在 `show` 时抛出 `invalidated(.contentChanged)`：SDK 把上一个播放项当成了这一集的。新播放项就位后再次跟随即可正常展示。

## SDK 读取什么

| SDK 需要 | 从 `AVPlayer` 读取 |
| - | - |
| 内容的位置 | `currentTime()` |
| 是否在播放 | `rate` 不为 0，且播放项尚未播放到结尾。被观众或你的应用暂停不算播放；缓冲时 rate 保持不变，因此算作播放。 |
| 速度 | `rate`，它也用来区分快速播放和拖动进度 |
| 拖动进度 | 当前播放项的时间跳变 |
| 另一集 | 另一个 `currentItem`，或播放项播放到结尾（无论 `actionAtItemEnd` 如何设置） |

SDK 会观察播放器，因此无论暂停来自哪里，观众一暂停叠加广告就会结束：你的控件、锁屏、控制中心、耳机、画中画。

## 在后台

应用进入后台时，iOS 会暂停 `AVPlayer`。屏幕上的叠加广告会冻结而不是结束：如果应用回到前台后一秒内内容再次播放，它会继续，否则以 `.interrupted` 结束。

## 循环播放的剧集

`AVPlayerLooper` 播放的是播放项的副本，因此每一次循环都是另一个播放项：在一次循环中请求的叠加广告或暂停广告，在下一次循环中会被拒绝（`invalidated(.contentChanged)`）。像往常一样在 `didEnd` 中请求下一个广告，它就属于正在播放的那次循环。


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