tencent cloud

实时音视频

动态与公告
产品动态
产品近期公告
关于 TRTC Live 正式上线的公告
关于TRTC Conference 正式版上线的公告
Conference 商业化版本即将推出
关于多人音视频 Conference 开启内测公告
关于音视频通话 Call 正式版上线的公告
关于腾讯云音视频终端 SDK 播放升级及新增授权校验的公告
关于 TRTC 应用订阅套餐服务上线的相关说明
产品简介
产品概述
基本概念
产品功能
产品优势
应用场景
性能数据
购买指南
计费概述
免费时长说明
月订阅
现收现付
TRTC 逾期与暂停政策
常见问题解答
退款说明
新手指引
Demo 体验
视频通话 SDK
组件介绍
开通服务
跑通 Demo
快速接入
离线唤醒
会话聊天
云端录制
AI 降噪
界面定制
Chat 集成通话能力
更多特性
无 UI 集成
服务端 API
客户端 API
解决方案
错误码表
发布日志
常见问题
视频会议 SDK
组件介绍(TUIRoomKit)
开通服务(TUIRoomKit)
跑通 Demo(TUIRoomKit)
快速接入(TUIRoomKit)
屏幕共享(TUIRoomKit)
预定会议(TUIRoomKit)
会中呼叫(TUIRoomKit)
界面定制(TUIRoomKit)
虚拟背景(TUIRoomKit)
会议控制(TUIRoomKit)
云端录制(TUIRoomKit)
AI 降噪(TUIRoomKit)
会中聊天(TUIRoomKit)
机器人推流(TUIRoomKit)
更多特性(TUIRoomKit)
客户端 API(TUIRoomKit)
服务端 API(TUIRoomKit)
常见问题(TUIRoomKit)
错误码 (TUIRoomKit)
SDK更新日志(TUIRoomKit)
直播与语聊 SDK
Live 视频直播计费说明
组件介绍
开通服务(TUILiveKit)
跑通 Demo
无 UI 集成
UI 自定义
直播监播
视频直播
语聊房
高级功能
客户端 API
服务端 API
错误码
发布日志
常见问题
RTC Engine
开通服务
SDK 下载
API-Example
接入指引
API-参考手册
高级功能
AI 集成
概述
MCP 配置
Skills 配置
集成指南
常见问题
RTC RESTFUL API
History
Introduction
API Category
Room Management APIs
Stream mixing and relay APIs
On-cloud recording APIs
Data Monitoring APIs
Pull stream Relay Related interface
Web Record APIs
AI Service APIs
Cloud Slicing APIs
Cloud Moderation APIs
Making API Requests
Call Quality Monitoring APIs
Usage Statistics APIs
Data Types
Appendix
Error Codes
控制台指南
应用管理
套餐包管理
用量统计
监控仪表盘
开发辅助
解决方案
实时合唱
常见问题
迁移指南
计费相关
功能相关
UserSig 相关
应对防火墙限制相关
缩减安装包体积相关
Andriod 与 iOS 相关
Web 端相关
Flutter 相关
Electron 相关
TRTCCalling Web 相关
音视频质量相关
其他问题
旧版文档
RTC RoomEngine SDK(旧)
集成 TUIRoom (Web)
集成 TUIRoom (Android)
集成 TUIRoom (iOS)
集成 TUIRoom (Flutter)
集成 TUIRoom (Electron)
TUIRoom API 查询
实现云端录制与回放(旧)
监控仪表盘计费(旧)
协议与策略
安全合规认证
安全白皮书
信息安全说明
服务等级协议
苹果隐私策略:PrivacyInfo.xcprivacy
TRTC 政策
隐私协议
数据处理和安全协议
词汇表

iOS

PDF
聚焦模式
字号
最后更新时间: 2025-06-23 14:24:11
在 iOS 平台下支持两种不同的屏幕分享方案:
应用内分享
即只能分享当前 App 的画面,该特性需要 iOS 13 及以上版本的操作系统才能支持。由于无法分享当前 App 之外的屏幕内容,因此适用于对隐私保护要求高的场景。
跨应用分享
基于苹果的 Replaykit 方案,能够分享整个系统的屏幕内容,但需要当前 App 额外提供一个 Extension 扩展组件,因此对接步骤也相对应用内分享要多一点。

支持的平台

iOS
Android
macOS
Windows
Electron
Chrome 浏览器

应用内分享

应用内分享的方案非常简单,只需要调用 RoomEngine 提供的接口 startScreenCapture 并传入参数appgroup 即可。
同时您可以调用updateVideoQualityEx修改编码参数,我们推荐的用于 iOS 屏幕分享的编码参数是:
参数项
参数名称
常规推荐值
文字教学场景
分辨率
videoResolution
1280 × 720
1920 × 1080
帧率
fps
10 FPS
8 FPS
最高码率
bitrate
1600 kbps
2000 kbps
由于屏幕分享的内容一般不会剧烈变动,所以设置较高的 FPS 并不经济,推荐10 FPS即可。
如果您需要更高的画质,请调高FPS。
如果您要分享的屏幕内容包含大量文字,可以适当提高分辨率和码率设置。
最高码率(videoBitrate)是指画面在剧烈变化时的最高输出码率,如果屏幕内容变化较少,实际编码码率会比较低。
示例:
import RTCRoomEngine

let roomEngine = TUIRoomEngine.sharedInstance()

roomEngine.startScreenCapture(appGroup: "")

let params = TUIRoomVideoEncoderParams()
params.fps = 10 //替换为您真实需要的值
params.resolutionMode = .portrait //竖屏分辨率
params.bitrate = .1600 //此处换为您真实需要的值
params.videoResolution = .quality720P //此处换位您需要的值

roomEngine.updateVideoQualityEx(streamType: .screenStream, params: params)

跨应用分享

iOS 系统上的跨应用屏幕分享,需要增加 Broadcast Upload Extension 录屏进程以配合主 App 进程进行推流。Extension 录屏进程由系统在需要录屏的时候创建,并负责接收系统采集到屏幕图像。因此需要:
1. 创建 App Group,并在 XCode 中进行配置(可选)。这一步的目的是让 Extension 录屏进程可以同主 App 进程进行跨进程通信。
2. 在您的工程中,新建一个 Broadcast Upload Extension 的 Target,并在其中集成 SDK 压缩包中专门为扩展模块定制的 TXLiteAVSDK_ReplayKitExt.framework
3. 对接主 App 端的接收逻辑,让主 App 等待来自 Broadcast Upload Extension 的录屏数据。
注意:
如果跳过第1步,也就是不配置 App Group(接口传 nil),屏幕分享依然可以运行,但稳定性要打折扣,故虽然步骤较多,但请尽量配置正确的 App Group 以保障屏幕分享功能的稳定性。

步骤1:创建 App Group

使用您的账号登录 Apple 开发者官方网站 ,进行以下操作,注意完成后需要重新下载对应的 Provisioning Profile
1. 单击 Certificates, IDs & Profiles
2. 在右侧的界面中单击加号。
3. 选择 App Groups,单击 Continue
4. 在弹出的表单中填写 Description 和 Identifier,其中 Identifier 需要传入接口中的对应的 AppGroup 参数。完成后单击 Continue



5. 回到 Identifier 页面,左上边的菜单中选择 App IDs,然后单击您的 App ID(主 App 与 Extension 的 AppID 需要进行同样的配置)。
6. 选中 App Groups 并单击 Edit
7. 在弹出的表单中选择您之前创建的 App Group,单击 Continue 返回编辑页,单击 Save 保存。



8. 重新下载 Provisioning Profile 并配置到 XCode 中。

步骤2:创建 Broadcast Upload Extension

1. 在 Xcode 菜单依次单击 FileNewTarget...,选择 Broadcast Upload Extension
2. 在弹出的对话框中填写相关信息,不用勾选 Include UI Extension,单击 Finish 完成创建。
3. 将下载到的 SDK 压缩包中的 TXLiteAVSDK_ReplayKitExt.framework 拖动到工程中,勾选刚创建的 Target。
4. 选中新增加的 Target,依次单击 + Capability,双击 App Groups,如下图:

AddCapability


操作完成后,会在文件列表中生成一个名为 Target名.entitlements 的文件,如下图所示,选中该文件并单击 + 号填写上述步骤中的 App Group 即可。

AddGroup


5. 选中主 App 的 Target ,并按照上述步骤对主 App 的 Target 做同样的处理。
6. 在新创建的 Target 中,Xcode 会自动创建一个名为 "SampleHandler.h" 的文件,用如下代码进行替换。需将代码中的 APPGROUP 改为上文中的创建的 App Group Identifier
import ReplayKit
import TXLiteAVSDK_ReplayKitExt

let APPGROUP = ""

class SampleHandler: RPBroadcastSampleHandler, TXReplayKitExtDelegate {

let recordScreenKey = Notification.Name.init("TRTCRecordScreenKey")

override func broadcastStarted(withSetupInfo setupInfo: [String : NSObject]?) {
if let setupInfo = setupInfo {
}
TXReplayKitExt.sharedInstance().setup(withAppGroup: APPGROUP, delegate: self)
}
override func broadcastPaused() {
// 可以添加暂停时的资源释放或状态保存逻辑
}

override func broadcastResumed() {
// 可以添加恢复时的资源重新初始化逻辑
}

override func broadcastFinished(){
// User has requested to finish the broadcast.
TXReplayKitExt.sharedInstance().broadcastFinished()
}

func broadcastFinished(_ broadcast: TXReplayKitExt, reason: TXReplayKitExtReason) {
var tip = ""
switch reason {
case TXReplayKitExtReason.requestedByMain:
tip = "屏幕共享已结束"
break
case TXReplayKitExtReason.disconnected:
tip = "应用断开"
break
case TXReplayKitExtReason.versionMismatch:
tip = "集成错误(SDK 版本号不相符合)"
break
default:
break
}

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

override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
switch sampleBufferType {
case RPSampleBufferType.video:
TXReplayKitExt
.sharedInstance()
.send(sampleBuffer, with: .video)
break
case RPSampleBufferType.audioApp:
// 可以在此处处理应用音频
break
case RPSampleBufferType.audioMic:
// 可以在此处处理麦克风音频
break
@unknown default:
let error = "未知的采样缓冲区类型: \\(sampleBufferType)"
finishBroadcastWithError(NSError(domain: error, code: -1, userInfo: nil))
}
}
}

步骤3:对接主 App 端的接收逻辑

按照如下步骤,对接主 App 端的接收逻辑。也就是在用户触发屏幕分享之前,要让主 App 处于“等待”状态,以便随时接收来自 Broadcast Upload Extension 进程的录屏数据。
1. 调用 startScreenCapture 方法,并传入 步骤1 中设置的 AppGroup,让 SDK 进入“等待”状态。
2. 等待用户触发屏幕分享。如果不实现 步骤4 中的“触发按钮”,屏幕分享就需要用户在 iOS 系统的控制中心,通过长按录屏按钮来触发,这一操作步骤如下图所示:
3. 通过调用 stopScreenCapture 接口可以随时中止屏幕分享。
示例:
import RTCRoomEngine

TUIRoomEngine.sharedInstance().startScreenCapture(appGroup: "")
TUIRoomEngine.sharedInstance().stopScreenCapture()

步骤4:增加屏幕分享的触发按钮(可选)

截止到 步骤3 ,我们的屏幕分享还必须要用户从控制中心中长按录屏按钮来手动启动。您可通过下述方法实现类似腾讯会议的单击按钮即可触发的效果:
1. TRTCBroadcastExtensionLauncher 文件实现了唤起屏幕分享,将其加入到您的工程中。
2. 在您的界面上放置一个按钮,并在按钮的响应函数中调用 TRTCBroadcastExtensionLauncher 中的 launch 函数,就可以唤起屏幕分享功能了。
示例:
@objc private func buttonTapped() {
TRTCBroadcastExtensionLauncher.sharedInstance.launch()
}
import UIKit
import TXLiteAVSDK_ReplayKitExt

class TRTCBroadcastExtensionLauncher: NSObject {

var systemBroacastExtensionPicker = RPSystemBroadcastPickerView()
var prevLaunchEventTime : CFTimeInterval = 0

static let sharedInstance = TRTCBroadcastExtensionLauncher()

override init() {
super.init()
let picker = RPSystemBroadcastPickerView(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
picker.showsMicrophoneButton = false
picker.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin]
systemBroacastExtensionPicker = picker

if let pluginPath = Bundle.main.builtInPlugInsPath,
let contents = try? FileManager.default.contentsOfDirectory(atPath: pluginPath) {

for content in contents where content.hasSuffix(".appex") {
guard let bundle = Bundle(path: URL(fileURLWithPath: pluginPath).appendingPathComponent(content).path),
let identifier : String = (bundle.infoDictionary?["NSExtension"] as? [String:Any])? ["NSExtensionPointIdentifier"] as? String
else {
continue
}
if identifier == "com.apple.broadcast-services-upload" {
picker.preferredExtension = bundle.bundleIdentifier
break
}
}
}
}

static func launch() {
TRTCBroadcastExtensionLauncher.sharedInstance.launch()
}

func launch() {
// The pop-up on iOS 12 is slow and will crash if you click quickly.
let now = CFAbsoluteTimeGetCurrent()
if now - prevLaunchEventTime < 1.0 {
return
}
prevLaunchEventTime = now

for view in systemBroacastExtensionPicker.subviews {
if let button = view as? UIButton {
button.sendActions(for: .allTouchEvents)
break
}
}
}
}

注意:
苹果在 iOS 12.0 中增加了 RPSystemBroadcastPickerView 可以从应用中弹出启动器供用户确认启动屏幕分享,到目前为止, RPSystemBroadcastPickerView 尚不支持自定义界面,也没有官方的唤起方法。
TRTCBroadcastExtensionLauncher 的原理就是遍历 RPSystemBroadcastPickerView 的子 View 寻找 UIButton 并触发了其点击事件。
但该方案不被苹果官方推荐,并可能在新一轮的系统更新中失效,因此 步骤4 只是一个可选方案,您需要自行承担风险来选用此方案。

步骤5:混流模式下屏幕共享

当您完成了上述逻辑之后,您需要调用 setLiveStreamLayoutInfo API 修改画面布局。
import RTCRoomEngine

let roomEngine = TUIRoomEngine.sharedInstance()
let layoutManager = roomEngine.getExtension(extensionType: .liveLayoutManager) as? TUILiveLayoutManager
roomEngine.startScreenCapture(appGroup: "")//替换为真实的appGroup

layoutManager.setLiveStreamLayoutInfo(
roomID: roomInfo.roomId,
layoutInfo: "" //详见下文
onSuccess: {
//修改成功
},
onError: {code ,message in
}
)
//layoutInfo格式需求:
{
"RoomId": "live_adams", //替换为您的RoomID
//当layouttype是1000时候,修改VideoEncode时候需要同步修改LayoutInfo,九宫格模式下会默认自动根据分辨率修改更新layoutInfo
"VideoEncode": {
"Width": 1080,
"Height": 1920,
},
"LayoutMode": 1000, // 0~9 内置布局模板, 1000自定义布局, 只有1000时候才能修改LayoutInfo,0为九宫格
"LayoutInfo":{
"LayoutList": [
{
"LocationX": 0, // 具体数值
"LocationY": 0, // 具体数值
"ImageWidth": 1080, // 具体数值
"ImageHeight": 960, // 具体数值
"ZOrder": 0, // 层级
"StreamType": 0, // 0为摄像头, 1为屏幕共享
"Member_Account": "admin001", //替换为您的userId
"BackgroundImageUrl": "ImageUrl",
"RoomId":"live_adams", //替换为您的RoomId
"BackgroundColor":"0x1F212C"
},
{
"LocationX": 0, // 具体数值
"LocationY": 960, // 具体数值
"ImageWidth": 1080, // 具体数值
"ImageHeight": 960, // 具体数值
"ZOrder": 0, // 层级
"StreamType": 0, // 0为摄像头, 1为屏幕共享
"Member_Account": "admin001", //替换为您的UserId
"BackgroundImageUrl": "ImageUrl",
"RoomId":"live_adams", //替换为您的RoomId
"BackgroundColor":"0x1F212C"
}
],
"MaxUserLayout": {
"LocationX": 0, // 具体数值
"LocationY": 0, // 具体数值
"ImageWidth": 1080, // 具体数值
"ImageHeight": 1920, // 具体数值
"ZOrder": 0, //层级
"StreamType": 0, // 0为摄像头, 1为屏幕共享
"Member_Account": "admin001", //替换为您的userId
"BackgroundImageUrl": "ImageUrl",
"RoomId":"live_adams", //替换为您的roomId
"BackgroundColor":"0x1F212C"
}
}

步骤6:混流模式下停止分享

当您想要停止屏幕共享并且将画面布局修改回来时,您需要调用 stopScreenCapture 接口关闭并且调用 setLiveStreamLayoutInfo 接口恢复画面布局。
import RTCRoomEngine

let roomEngine = TUIRoomEngine.sharedInstance()
let layoutManager = roomEngine.getExtension(extensionType: .liveLayoutManager) as? TUILiveLayoutManager
roomEngine.stopScreenCapture()

layoutManager.setLiveStreamLayoutInfo(
roomID: roomInfo.roomId,
layoutInfo: "",//详见下文
onSuccess: {},
onError: { code ,message in
}
)
//当您想要恢复默认的宫格布局时,您需要传入的layoutInfo参数如下:
{
"RoomId": "live_12121", //替换为真实房间号
"VideoEncode": {
"Width": 1080,
"Height": 1920
},
"LayoutMode": 0
}

观看屏幕分享

当有用户播放屏幕共享时您可以通过监听 TUIRoomObserver 中的 onUserVideoStateChanged 来感知到屏幕共享流。
示例:
import RTCRoomEngine

extension ScreenSharedController: TUIRoomObserver { //替换为您具体的业务类,此处仅为举例
func onUserVideoStateChanged(userId: String, streamType: TUIVideoStreamType, hasVideo: Bool, reason: TUIChangeReason) {
}
}


帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈