# 屏幕共享 (/zh-CN/realtime-media/rtc/build/video/screen-share/ios)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

在互动直播或视频通话中，主播或视频通话用户可以通过声网 SDK 中的屏幕共享特性，将自己的屏幕内容以视频的方式分享给其他用户或观众观看。

屏幕共享可以应用在以下场景中：

| 场景     | 描述                                                         |
| :------- | :----------------------------------------------------------- |
| 在线教育 | 老师将自己的屏幕、教学课件、绘图软件或编程软件共享给学生，用于课堂示范 |
| 游戏直播 | 主播共享自己的游戏画面给观众                                 |
| 互动直播 | 主播共享自己的屏幕和观众互动                                 |
| 视频会议 | 会议成员共享屏幕观看 PPT 或者文档                            |
| 远程控制 | 被控端向主控端展示自己的桌面                                 |

## 技术原理 [#技术原理-1]

由于 Apple 不支持在 App 主进程采集屏幕，因此你需要为屏幕共享流单独创建一个 Extension，并在 Extension 中使用 iOS 原生的 ReplayKit 框架实现录制屏幕，然后将屏幕共享流发送给主进程、实现屏幕共享。

<DocsImage alt="屏幕共享原理" src="https://web-cdn.agora.io/docs-portal/img/rtc/screensharing-ios-tech.png" displayWidth="50%" />

根据实际业务场景的不同，你可以选择以下任一方式调用 API 实现屏幕共享：

- 在加入频道前调用 `startScreenCapture`，然后调用 `joinChannelByToken` [2/4] 加入频道并设置 `publishScreenCaptureVideo` 为 `true`，即可开始屏幕共享。
- 在加入频道后调用 `startScreenCapture`，然后调用 `updateChannelWithMediaOptions` 更新频道媒体选项并设置 `publishScreenCaptureVideo` 为 `true`，即可开始屏幕共享。

## 注意事项 [#注意事项-1]

- 在开启屏幕共享后，声网以屏幕共享视频流的分辨率作为计费标准。默认分辨率为 1280 × 720，你也可以根据你的业务需求进行调整。详见[如何确定屏幕共享视频流的分辨率？](/zh-CN/realtime-media/rtc/reference/billing-faq#screencapture)
- 受系统限制，屏幕共享只支持 iOS 12.0 及以上版本。
- 该功能对设备性能要求较高，声网推荐你使用 iPhone X 及以上设备。
- 用户在 iOS 设备上开启屏幕共享后，因系统限制，音频路由会自动切换为听筒。
    - 如果当前使用通话音量，则你可以手动切换音频路由，例如，你可以根据实际需求将音频路由切换成扬声器。
    - 如果当前使用媒体音量，由于系统限制，你在这种场景下无法手动切换音频路由。如果你不了解使用的是通话还是媒体音量，请参考[如何区分媒体音量和通话音量](/zh-CN/reference/faq/integration/system_volume)。

## 前提条件 [#前提条件-1]

在实现屏幕共享前，请确保已在你的项目中实现基本的实时音视频功能。详见[实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)。

## 项目设置 [#项目设置]
按照以下步骤修改你的项目文件。

1. 前往你的项目文件夹，用 Xcode 打开 `.xcodeproj` 文件。
1. 点击 **File > New > Target...**, 在弹出的窗口中选择 **Broadcast Upload Extension**, 点击 **Next**。

    ![在 Xcode 中创建 Broadcast Upload Extension](https://web-cdn.agora.io/docs-files/1606368184836)

2. 在弹出的窗口中填写 **Product Name** 等信息，取消勾选 **Include UI Extension**，点击 **Finish**。Xcode 会自动创建该 Extension 的文件夹，其中包含 `SampleHandler.swift` 文件。
3. 在 **Target** 下选中刚创建的 Extension，点击 **General**，在 **Deployment Info** 下将 iOS 的版本设置为 12.0 或之后。

<DocsImage alt="设置 Extension 的 Deployment Info" src="https://web-cdn.agora.io/docs-files/1670580188367" displayWidth="35%" />

4. 修改项目设置以实现屏幕共享的代码逻辑，根据实际业务需求选择以下三种方式其中之一即可：

   - 如果你只需使用声网提供的 `AgoraReplayKitExtension.xcframework` 动态库中的功能，则：选中 **Target** 为刚刚创建的 Extension，在 **Info** 中将 **NSExtension > NSExtensionPrincipalClass** 所对应的 **Value** 从 **SampleHandler** 改为 **AgoraReplayKitHandler**。

      ![将 NSExtensionPrincipalClass 设置为 AgoraReplayKitHandler](https://web-cdn.agora.io/docs-files/1648112619203)

   - 如果你需要另外实现一些业务逻辑，可以继承 `AgoraReplayKitHandler` 类。参考如下代码修改 `SampleHandler.swift` 文件：

        ```swift
        import ReplayKit
        import AgoraReplayKitExtension

        class SampleHandler: AgoraReplayKitHandler {
            override func broadcastStarted(withSetupInfo setupInfo: [String : NSObject]?) {
                // 用户请求开始广播
                super.broadcastStarted(withSetupInfo: setupInfo)
            }
        }
        ```

   - 如果你希望使用 iOS 原生的 `SampleHandler`、不继承 `AgoraReplayKitHandler` 类，参考如下代码修改 `SampleHandler.swift` 文件：

        ```swift
        import ReplayKit
        import AgoraReplayKitExtension

        class SampleHandler: RPBroadcastSampleHandler, AgoraReplayKitExtDelegate {
            override func broadcastStarted(withSetupInfo setupInfo: [String : NSObject]?) {
                // 用户请求开始广播
                AgoraReplayKitExt.shareInstance().start(self)
            }
            override func broadcastPaused() {
                // 用户请求暂停广播，屏幕共享暂停
                AgoraReplayKitExt.shareInstance().pause()
            }

            override func broadcastResumed() {
                // 用户请求恢复广播，屏幕共享恢复
                AgoraReplayKitExt.shareInstance().resume()
            }

            override func broadcastFinished() {
                // 用户请求停止广播
                AgoraReplayKitExt.shareInstance().stop()
            }

            override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
                AgoraReplayKitExt.shareInstance().push(sampleBuffer, with: sampleBufferType)
            }

            func broadcastFinished(_ broadcast: AgoraReplayKitExt, reason: AgoraReplayKitExtReason) {
                var tip = ""
                switch reason {
                case AgoraReplayKitExtReasonInitiativeStop:
                    tip = "AgoraReplayKitExtReasonInitiativeStop"

                case AgoraReplayKitExtReasonConnectFail:
                    tip = "AgoraReplayKitExReasonConnectFail"

                case AgoraReplayKitExtReasonDisconnect:
                    tip = "AgoraReplayKitExReasonDisconnect"

                default: break
                }

                let error = NSError(domain: NSCocoaErrorDomain,
                                    code: 0,
                                    userInfo: [NSLocalizedFailureReasonErrorKey: tip])
                self .finishBroadcastWithError(error as Error)
                }
            }

        ```

## 自动集成动态库 [#自动集成动态库]

通过 CocoaPods 集成 SDK 时，你需要在 `Podfile` 文件中添加如下内容，指定集成屏幕共享动态库 `AgoraReplayKitExtension.xcframework`，示例代码如下：

```ruby
platform :ios, '9.0'
target 'Your App' do
    # 只集成基础库和屏幕共享动态库
    # 请使用具体的 SDK 版本号替换下面代码中的 x.y.z，可通过发版说明获取最新版本号
    pod 'AgoraRtcEngine_iOS', 'x.y.z', :subspecs => ['RtcBasic', 'ReplayKit']
end
```

:::info[信息]
屏幕共享动态库封装了如下功能：

- 使用 Apple ReplayKit 进行屏幕录制。
- 使用 SDK 采集功能获取系统录屏数据，并发送给频道中其他用户。
:::

## 实现屏幕共享 [#实现屏幕共享-1]

本节介绍如何在你的项目中实现屏幕共享，API 调用时序如下图所示。

<DocsImage alt="流程图" src="https://web-cdn.agora.io/docs-portal/img/rtc/screen-share/screen-share-process-mobile.svg" displayWidth="70%" />

### 设置音频场景 [#设置音频场景]

调用 `setAudioScenario` 方法，并设置音频场景为  `AgoraAudioScenarioGameStreaming`（高音质场景），以提高屏幕共享时采集系统音频的成功率。

### 开启屏幕采集 [#开启屏幕采集-1]

1. 调用 `startScreenCapture` 开启屏幕采集，并根据你的应用场景进行参数设置：
   - `captureVideo`：是否在屏幕共享时采集系统视频。
   - `captureAudio`：是否在屏幕共享时采集系统音频。
   - `captureSignalVolume`：采集的系统音量。
   - `dimensions`：视频编码的分辨率。
   - `frameRate`：视频编码帧率 (fps)。
   - `bitrate`：视频编码码率 (Kbps)。
   - `contentHint`：屏幕共享视频的内容类型。

    ```swift
    // 设置屏幕采集的参数
    private lazy var screenParams: AgoraScreenCaptureParameters2 = {
        let params = AgoraScreenCaptureParameters2()
        params.captureVideo = true
        params.captureAudio = true
        let audioParams = AgoraScreenAudioParameters()
        // 设置采集的系统音量
        audioParams.captureSignalVolume = 50
        params.audioParams = audioParams
        let videoParams = AgoraScreenVideoParameters()
        // 设置共享屏幕的分辨率
        videoParams.dimensions = screenShareVideoDimension()
        // 设置视频编码帧率
        videoParams.frameRate = .fps15
        // 设置视频编码码率
        videoParams.bitrate = AgoraVideoBitrateStandard
        params.videoParams = videoParams
        return params
    }()

    // 开启屏幕采集
    agoraKit.startScreenCapture(screenParams)
    ```

1. 结合用户的手动操作，使 App 开启屏幕共享。有两种方式供你参考：
   - 方式一：提示用户在 iOS 系统的控制中心长按**屏幕录制**按钮，并选择用你创建的 Extension 开启录制。
   - 方式二：使用 Apple 在 iOS 12.0 中新增的 [RPSystemBroadcastPickerView](https://developer.apple.com/documentation/replaykit/rpsystembroadcastpickerview)，使 App 界面弹出 “开启屏幕共享” 的按钮，提示用户通过点击该按钮开启录制，示例代码如下：

   :::info[信息]
   `RPSystemBroadcastPickerView` 存在一些使用限制并可能在后续版本的 iOS 系统中失效。因此，请酌情使用方式二。
   :::

    ```swift
    let frame = CGRect(x: 0, y:0, width: 60, height: 60)
    // 创建 RPSystemBroadcastPickerView 对象
    systemBroadcastPicker = RPSystemBroadcastPickerView(frame: frame)
    systemBroadcastPicker?.showsMicrophoneButton = false
    systemBroadcastPicker?.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin]
    // 获取主应用程序的 Bundle Identifier
    let bundleId = Bundle.main.bundleIdentifier ?? ""
    // 设置 Extension 名称
    systemBroadcastPicker?.preferredExtension = "\(bundleId).Agora-ScreenShare-Extension"
    ```

### 在频道中发布屏幕共享视频流 [#在频道中发布屏幕共享视频流]

加入频道后，调用 `updateChannelWithMediaOptions`，发布采集的屏幕共享视频流。示例代码如下：

```swift
// 在进行屏幕视频采集（state 为 capturing，souceType 为 screen）时，定义 rtcEngine 的行为
func rtcEngine(_ engine: AgoraRtcEngineKit, localVideoStateChangedOf state: AgoraVideoLocalState, error: AgoraLocalVideoStreamError, sourceType: AgoraVideoSourceType) {
    switch (state, sourceType) {
    case (.capturing, .screen):
        // 在频道中发布屏幕采集的视频
        option.publishScreenCaptureVideo = true
        // 在频道中发布屏幕采集的音频
        option.publishScreenCaptureAudio = true
        // 不发布摄像头采集的视频
        option.publishCameraTrack = false
        // 使用以上 option 中的设置更新频道设置
        agoraKit.updateChannel(with: option)

    default: break
    }
}
```

### （可选）设置屏幕共享场景 [#可选设置屏幕共享场景-1]

调用 `setScreenCaptureScenario` 方法设置屏幕共享场景，按照实际使用场景，将 `scenarioType` 设置为以下任意一种：

- `AgoraScreenScenarioDocument`(1)：文档场景
- `AgoraScreenScenarioGaming`(2)：游戏场景
- `AgoraScreenScenarioVideo`(3)：视频场景
- `AgoraScreenScenarioRDC`(4)：远程控制场景

示例代码如下：

```swift
agoraKit.setScreenCaptureScenario(.video)
```

### （可选）更新屏幕共享 [#可选更新屏幕共享-1]
如果你要更新屏幕共享的参数，调用 `updateScreenCapture`，修改屏幕共享的参数。例如：视频编码分辨率、帧率、码率。

```swift
// 设置新的屏幕采集参数
private lazy var screenParams: AgoraScreenCaptureParameters2 = {
    let params = AgoraScreenCaptureParameters2()
    params.captureVideo = true
    params.captureAudio = true
    let audioParams = AgoraScreenAudioParameters()
    // 设置采集的系统音量
    audioParams.captureSignalVolume = 70 // 更新音量
    params.audioParams = audioParams
    let videoParams = AgoraScreenVideoParameters()
    // 更新共享屏幕的分辨率
    videoParams.dimensions = CGSizeMake(960, 540) // 更新为 960 x 540
    // 更新视频编码帧率
    videoParams.frameRate = .fps30 // 更新为 30 fps
    // 更新视频编码码率
    videoParams.bitrate = 1500 // 更新为 1500 Kbps
    params.videoParams = videoParams
    return params
}()

// 更新屏幕共享参数
agoraKit.updateScreenCapture(screenParams)
```

### 停止屏幕共享 [#停止屏幕共享-1]
调用 `stopScreenCapture`，在频道内停止屏幕共享。示例代码如下：

```swift
// 停止屏幕共享
agoraKit.stopScreenCapture()
// 停止在频道中发布屏幕采集的视频
option.publishScreenCaptureVideo = false
// 停止在频道中发布屏幕采集的音频
option.publishScreenCaptureAudio = false
// 在频道中发布摄像头采集的视频
option.publishCameraTrack = true
agoraKit.updateChannel(with: option)
```

## 参考信息 [#参考信息-1]

### 功能介绍 [#功能介绍-1]

声网 SDK 的屏幕共享特性可提供以下功能，适用于各种场景下的屏幕共享。

![](https://web-cdn.agora.io/docs-files/1680251438368)

:::info[信息]
屏幕共享功能在各平台的适用情况如下：

- 桌面端（Windows 和 macOS）：支持上述所有屏幕共享功能。
- 移动端（Android 和 iOS）：仅支持共享整个屏幕。
:::

#### 共享整个屏幕 [#共享整个屏幕-1]

将你的整个屏幕进行共享，包括屏幕中的所有信息，该功能支持同时采集两块屏幕的信息并共享。

#### 共享 App 窗口 [#共享-app-窗口-1]

如果你不希望将整个屏幕内容分享给其他用户，可以只共享一个 App 窗口中的画面。

#### 共享指定区域 [#共享指定区域-1]

如果你只希望共享屏幕或 App 窗口中的一部分，可以在开启屏幕共享时设置一个共享区域，只有该区域内的画面会被分享。

#### 高级功能 [#高级功能-1]

除上述功能外，你还可以在开启屏幕共享时通过调整参数，实现以下高级共享功能：

- 屏蔽指定 App 窗口：在共享屏幕时，如果你不希望暴露某个 App 窗口，可以选择将该 App 窗口屏蔽，则该窗口将不会出现在共享的屏幕中。
- 描边：如果你需要勾勒出正在共享的范围，可以对指定的 App 窗口或屏幕进行描边，并自定义描边的宽度、颜色和透明度。
- 前置指定 App 窗口：如果你同时共享了多个 App 窗口，可能会出现窗口之间互相遮挡的情况，你可以指定一个 App 窗口并将其前置，即可避免它被其他窗口遮挡。
- 设置共享场景：SDK 会根据你设置的场景自动调节 QOE (Quality of Experience) 策略。
  - 在共享文档、幻灯片、表格，或者远程控制时，你可以将共享场景设置为文档场景或远程控制场景，SDK 会优先保障画质，并降低接收端看共享视频的延时。
  - 在共享游戏或电影、视频直播时，你可以将共享场景设置为游戏场景或视频场景，SDK 会优先保障流畅性。

### 优势介绍 [#优势介绍-1]

声网提供的屏幕共享特性具备以下优势：

**超高清画质体验**

支持分辨率为 4K、帧率为 60 fps 的超高清视频。

**多 App 支持**

适配 WPS Office、Microsoft PowerPoint、Visual Studio Code、Adobe Photoshop、Windows Media Player 和 Scratch 等多款主流 App，方便用户在屏幕共享时直接共享指定 App，提升功能易用性。

**多设备支持**

支持多设备同时共享，兼容 Windows 8 系统、无独立显卡的设备、双显卡设备、外接屏幕设备等，满足各种场景下的设备使用需求。

**多平台适配**

支持 iOS、Android、macOS、Windows、Web、Unity、Flutter、React Native、Unreal Engine 等平台。

**高安全保障**

支持仅共享 App 和屏幕中的部分区域内容，并支持屏蔽指定 App 窗口，有效保障用户信息安全。

### 示例项目 [#示例项目-1]

声网提供了开源的示例项目供你参考，你可以前往下载或查看其中的源代码。

<Cards>
  <Card title="Agora-ScreenShare-Extension-OC" href="https://gitee.com/agoraio-community/API-Examples/tree/main/iOS/APIExample-OC/Agora-ScreenShare-Extension-OC" />
  <Card title={<RepositoryCardTitle provider="gitee">ScreenShare</RepositoryCardTitle>} href="https://gitee.com/agoraio-community/API-Examples/tree/main/iOS/APIExample-OC/APIExample-OC/Examples/Advanced/ScreenShare" />

  <Card title="Agora-ScreenShare-Extension" href="https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/Agora-ScreenShare-Extension" />
  <Card title={<RepositoryCardTitle provider="github">ScreenShare</RepositoryCardTitle>} href="https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/ScreenShare" />
</Cards>

### API 参考 [#api-参考-1]

- [`startScreenCapture`](/zh-CN/api-reference/rtc/ios/video/screencapture#api_irtcengine_startscreencapture)
- [`updateScreenCapture`](/zh-CN/api-reference/rtc/ios/video/screencapture#api_irtcengine_updatescreencapture)
- [`stopScreenCapture`](/zh-CN/api-reference/rtc/ios/video/screencapture#api_irtcengine_stopscreencapture)




















