搭建视频直播
核心功能
LiveCoreView 是一个专为直播场景设计的轻量级
UIView 组件,是您构建直播场景的核心,它封装了所有复杂的底层直播技术(例如推拉流、连麦、音视频渲染)。您可以将 LiveCoreView 作为直播画面的“画布”,专注于上层 UI 与交互的开发。通过下方的视图层级示意图,您可以直观了解 LiveCoreView 在直播界面中的位置和作用:

核心概念
核心概念 | 核心职责 | 关键 API / 属性 |
LiveCoreView | 负责底层音视频流的推流、拉流与渲染,并提供代理接口用于挂载上层自定义 UI(如用户信息、PK 进度条)。 | viewType: .pushView (主播推流) .playView (观众拉流)。setLiveID():绑定当前视图要渲染的直播间 ID。videoViewDelegate:视频画面上的 UI 插槽代理。 |
LiveListStore | 管理直播间的全生命周期(创建、进入、离开),并负责状态同步与被动事件(如直播结束、被踢出)的监听。 | createLive():主播发起直播。endLive(): 主播结束直播。joinLive():观众进入直播间。leaveLive():观众退出直播。 |
LiveInfo | 用于在开播前定义房间的各项参数,如房间号、麦位布局模式、最大连麦人数等。 | • liveID:房间唯一标识符。• seatLayoutTemplateID:布局模板 ID(如 600 为动态宫格)。 |
准备工作
步骤1:开通服务
步骤2:在当前项目中导入 AtomicXCore
1. 安装组件:请在您的 Podfile 文件中添加
pod 'AtomicXCore' 依赖,然后执行pod install。target 'xxxx' dopod 'AtomicXCore'end
2. 配置工程权限: 请在应用的
Info.plist 文件中添加相机和麦克风的使用权限说明。<key>NSCameraUsageDescription</key><string>TUILiveKit需要访问你的相机权限,开启后录制的视频才会有画面</string><key>NSMicrophoneUsageDescription</key><string>TUILiveKit需要访问您的麦克风权限,开启后录制的视频才会有声音</string>

步骤3:实现登录逻辑
在您的项目中调用
LoginStore.shared.login 完成登录,这是使用 AtomicXCore 所有功能的关键前提。重要:
推荐在您 App 自身的用户账户登录成功后,再调用 LoginStore.shared.login,以确保登录业务逻辑的清晰和一致。
import AtomicXCore// AppDelegate.swiftfunc application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {LoginStore.shared.login(sdkAppID: 1400000001, // 替换为您的 SDKAppIDuserID: "test_001", // 替换为您的 UserIDuserSig: "xxxxxxxxxxx") { result in // 替换为您的 UserSigswitch result {case .success(let info):debugPrint("login success")case .failure(let error):debugPrint("login failed code:\(error.code), message:\(error.message)")}}return true}
登录接口参数说明:
参数 | 类型 | 说明 |
SDKAppID | Int | |
UserID | String | 当前用户的唯一 ID,仅包含英文字母、数字、连字符和下划线。 |
userSig | String | 用于腾讯云鉴权的票据。请注意: 开发环境:您可以采用本地 GenerateTestUserSig.genTestSig 函数生成 UserSig 或者通过 UserSig 辅助工具 生成临时的 UserSig。生产环境:为了防止密钥泄露,请务必采用服务端生成 UserSig 的方式。详细信息请参见 服务端生成 UserSig。 |
搭建基础直播间
步骤1:实现主播视频开播
主播开播流程如下,您只需执行以下几步操作,即可快速搭建主播视频直播。

提示:
1. 初始化主播推流的视图
在您的主播视图控制器中,创建一个
LiveCoreView 实例,并将 viewType 指定为 .pushView(推流视图)。import AtomicXCore// YourAnchorViewController 代表您的主播开播视图控制器class YourAnchorViewController: UIViewController {private let liveId: String// 1. 将 LiveCoreView 作为您视图控制器的一个属性private let coreView = LiveCoreView(viewType:.pushView, frame: UIScreen.main.bounds)// 2. 新增便利构造函数完成实例初始化// - liveId: 您需要开播的直播房间 idpublic init(liveId: String) {self.liveId = liveIdsuper.init(nibName: nil, bundle: nil)self.coreView.setLiveID(liveId)}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}public override func viewDidLoad() {super.viewDidLoad()// 3. 将主播推流页面加载到您的视图上view.addSubview(coreView)}}
2. 打开摄像头和麦克风
通过调用 DeviceStore 的
openLocalCamera、openLocalMicrophone 接口打开摄像头和麦克风,您无需做额外操作,LiveCoreView 会自动预览当前摄像头的视频流,示例代码如下:import AtomicXCore// YourAnchorViewController 代表您的主播开播视图控制器class YourAnchorViewController: UIViewController {// ... 其他代码 ...public override func viewDidLoad() {super.viewDidLoad()// 打开设备openDevices()}private func openDevices() {// 1. 打开前置摄像头DeviceStore.shared.openLocalCamera(isFront: true, completion: nil)// 2. 打开麦克风DeviceStore.shared.openLocalMicrophone(completion: nil)}}
3. 开始直播
通过调用 LiveListStore 的
createLive 接口开始视频直播,完整示例代码如下:import AtomicXCore// YourAnchorViewController 代表您的主播开播视图控制器class YourAnchorViewController: UIViewController {// ... 其他代码 ...// 调用开播接口开始直播private func startLive() {var liveInfo = LiveInfo()// 1. 设置直播的房间 idliveInfo.liveID = self.liveId// 2. 设置直播的房间名称liveInfo.liveName = "test 直播"// 3. 配置布局模板,默认:600 动态宫格布局liveInfo.seatLayoutTemplateID = 600// 4. 配置主播始终在麦位上liveInfo.keepOwnerOnSeat = true// 5. 调用 LiveListStore.shared.createLive 开始直播LiveListStore.shared.createLive(liveInfo) { [weak self] result inguard let self = self else { return }switch result {case .success(let info):debugPrint("startLive success")case .failure(let error):debugPrint("startLive error:\(error.message)")}}}}
LiveInfo参数说明:参数名 | 类型 | 属性 | 描述 |
liveID | String | 必填 | 直播间的唯一标识符。 |
liveName | String | 选填 | 直播间的标题。 |
notice | String | 选填 | 直播间的公告信息。 |
isMessageDisable | Bool | 选填 | 是否禁言( true:是,false:否)。 |
isPublicVisible | Bool | 选填 | 是否公开可见( true:是,false:否)。 |
isSeatEnabled | Bool | 选填 | 是否启用麦位功能( true:是,false:否)。 |
keepOwnerOnSeat | Bool | 选填 | 是否保持房主在麦位上。 |
maxSeatCount | Int | 必填 | 最大麦位数量。 |
seatMode | TakeSeatMode | 选填 | 上麦模式( .free:自由上麦,.apply:申请上麦)。 |
seatLayoutTemplateID | UInt | 必填 | 麦位布局模板 ID。 |
coverURL | String | 选填 | 直播间的封面图片地址。 |
backgroundURL | String | 选填 | 直播间的背景图片地址。 |
categoryList | [NSNumber] | 选填 | 直播间的分类标签列表。 |
activityStatus | Int | 选填 | 直播活动状态。 |
isGiftEnabled | Bool | 选填 | 是否启用礼物功能( true:是,false:否)。 |
4. 结束直播
直播结束后,主播可以调用 LiveListStore 的
endLive 接口结束直播。SDK 会处理停止推流和销毁房间的逻辑。import AtomicXCore// YourAnchorViewController 代表您的主播开播视图控制器class YourAnchorViewController: UIViewController {// ... 其他代码 ...// 结束直播private func stopLive() {LiveListStore.shared.endLive { [weak self] result inguard let self = self else { return }switch result {case .success(let data):debugPrint("endLive success")case .failure(let error):debugPrint("endLive error: \(error.message)")}}}}
步骤2:实现观众进房观看
观众观看流程如下,通过简单几步操作,即可实现观众观看直播。

提示:
1. 实现观众拉流页面
在您的观众视图控制器中,创建
LiveCoreView 实例,并将 viewType 指定为 .playView(拉流视图)。import AtomicXCore// YourAudienceViewController 代表您的观众观看视图控制器class YourAudienceViewController: UIViewController {// 1. 初始化观众拉流页面private let coreView = LiveCoreView(viewType:.playView, frame: UIScreen.main.bounds)private let liveId: Stringpublic init(liveId: String) {self.liveId = liveIdsuper.init(nibName: nil, bundle: nil)// 2. 绑定直播 idself.coreView.setLiveID(liveId)}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}public override func viewDidLoad() {super.viewDidLoad()// 3. 将主播推流页面加载到您的视图上view.addSubview(coreView)}}
2. 进入直播间观看
通过调用 LiveListStore 的
joinLive 接口加入直播,您无需做额外操作,LiveCoreView 会自动播放当前房间的视频流,完整示例代码如下:import AtomicXCore// YourAudienceViewController 代表您的观众观看视图控制器class YourAudienceViewController: UIViewController {// ... 其他代码 ...public override func viewDidLoad() {super.viewDidLoad()// 3. 将主播推流页面加载到您的视图上view.addSubview(coreView)// 4. 进入直播间joinLive()}private func joinLive() {// 调用 LiveListStore.shared.joinLive 进入直播间// - liveId: 与主播开播同样的 liveIdLiveListStore.shared.joinLive(liveID: liveId) { [weak self] result inguard let self = self else { return }switch result {case .success(let info):debugPrint("joinLive success")case .failure(let error):debugPrint("joinLive error \(error.message)")// 进房失败,也需要退出页面// self.dismiss(animated: true)}}}}
3. 退出直播
观众退出直播间时,需要调用 LiveListStore 的
leaveLive 接口退出直播。SDK 会自动停止拉流并退出房间。import AtomicXCore// YourAudienceViewController 代表您的观众观看视图控制器class YourAudienceViewController: UIViewController {// ... 其他代码 ...// 退出直播private func leaveLive() {LiveListStore.shared.leaveLive { [weak self] result inguard let self = self else { return }switch result {case .success:debugPrint("leaveLive success")case .failure(let error):debugPrint("leaveLive error \(error.message)")}}}}
步骤3:监听直播事件
在观众加入直播间后,您还需要处理一些房间内的“被动”事件。例如,主播主动结束了直播,或者观众因为违规等原因被踢出房间。如果不监听这些事件,观众端 UI 可能会停留在黑屏页面,影响用户体验。
您可以通过订阅
LiveListStore 提供的 liveListEventPublisher 来实现事件监听。import AtomicXCoreimport Combine // 1. 导入 Combine 框架// YourAudienceViewController 代表您的观众观看视图控制器class YourAudienceViewController: UIViewController {// ... 其他代码 (coreView, liveId, init, deinit, joinLive, leaveLive等) ...// 2. 定义 cancellableSet 来管理订阅生命周期private var cancellableSet: Set<AnyCancellable> = []public override func viewDidLoad() {super.viewDidLoad()view.addSubview(coreView)// 3. 监听直播事件setupLiveEventListener()// 4. 进入直播间joinLive()}// 5. 新增一个方法来设置事件监听private func setupLiveEventListener() {LiveListStore.shared.liveListEventPublisher.receive(on: RunLoop.main) // 确保在主线程处理 UI 更新.sink { [weak self] event inguard let self = self else { return }switch event {case .onLiveEnded(let liveID, let reason, let message):// 监听到直播结束debugPrint("Live ended. liveID: \(liveID), reason: \(reason.rawValue), message: \(message)")// 在此处处理退出直播间的逻辑,例如关闭当前页面// self.dismiss(animated: true)case .onKickedOutOfLive(let liveID, let reason, let message):// 监听到被踢出直播debugPrint("Kicked out of live. liveID: \(liveID), reason: \(reason.rawValue), message: \(message)")// 在此处处理退出直播间的逻辑// self.dismiss(animated: true)}}.store(in: &cancellableSet) // 管理订阅}// ... joinLive() 和 leaveLive() 方法 ...}
运行效果
| 动态宫格布局 | 浮动小窗布局 | 固定宫格布局 | 固定小窗布局 |
模板 ID | 600 | 601 | 800 | 801 |
描述 | 默认布局,可根据连麦人数动态调整宫格大小。 | 连麦嘉宾以浮动小窗形式显示。 | 连麦人数固定,每个嘉宾占据一个固定宫格。 | 连麦人数固定,嘉宾以固定小窗形式显示。 |
运行效果 | ![]() | ![]() | ![]() | ![]() |
功能进阶
实现房间内的自定义状态同步
在直播中,主播可能需要向所有观众同步一些自定义信息,例如“当前房间话题”、“背景音乐信息”等。
LiveListStore 的 MetaData 功能可以实现这一点。实现方式:
1. 主播端将自定义信息(建议使用 JSON 格式)通过
updateLiveMetaData 接口设置到一个或多个 key 中。AtomicXCore 会将这个变更实时同步给所有观众。2. 观众端只需订阅
LiveListState.currentLive,监听 metaData 的变化,一旦发现关心的 key 更新,就解析其 value 并刷新业务状态。示例代码:
import AtomicXCoreimport Combine// 1. 定义一个背景音乐模型 (可选,建议使用 Codable)struct MusicModel: Codable {let musicId: Stringlet musicName: String}// 2. 主播端:在您的主播业务逻辑中,添加推送背景音乐的方法func updateBackgroundMusic(music: MusicModel) {guard let jsonData = try? JSONEncoder().encode(music),let jsonString = String(data: jsonData, encoding: .utf8) else { return }// 将要更新的元数据let metaData = ["music_info": jsonString]// 使用全局单例的 liveListStore 来更新 metaDataLiveListStore.shared.updateLiveMetaData(metaData) { result inif case .success = result {print("背景音乐 \(music.musicName) 推送成功")} else if case .failure(let error) = result {print("背景音乐推送失败: \(error.message)")}}}// 3. 观众端:在您的观众业务逻辑中,订阅并响应private func subscribeToDataUpdates() {LiveListStore.shared.state// 监听当前房间的 metaData.subscribe(StatePublisherSelector(keyPath: \LiveListState.currentLive)).map { $0.metaData["music_info"]}.removeDuplicates().receive(on: DispatchQueue.main).sink { jsonString inguard let jsonString = jsonString,let data = jsonString.data(using: .utf8),let music = try? JSONDecoder().decode(MusicModel.self, from: data) else {return}// 刷新业务状态,播放新的音乐// ... (例如: playMusic(music))}.store(in: &cancellables)}
丰富直播场景
当您完成了基础的直播功能后,您可以参考以下功能指南来为直播添加丰富的互动玩法。
直播功能 | 功能介绍 | 功能 Stores | 实现指南 |
实现观众音视频连线 | 观众申请上麦,与主播进行实时视频互动。 | ||
实现主播跨房连线 PK | 两个不同房间的主播进行连线,实现互动或 PK。 | ||
添加弹幕聊天功能 | 观众可以在直播间发送和接收实时文字消息。 | ||
构建礼物赠送系统 | 观众可以向主播赠送虚拟礼物,增加互动和趣味性。 |
API 文档
Store/Component | 功能描述 | API 文档 |
LiveCoreView | 直播视频流展示与交互的核心视图组件:负责视频流渲染和视图挂件处理,支持主播直播、观众连麦、主播连线等场景。 | |
LiveListStore | 直播间全生命周期管理:创建 / 加入 / 离开 / 销毁房间,查询房间列表,修改直播信息(名称、公告等),监听直播状态(如被踢出、结束)。 | |
DeviceStore | 音视频设备控制:麦克风(开关 / 音量)、摄像头(开关 / 切换 / 画质)、屏幕共享,设备状态实时监听。 | |
CoGuestStore | 观众连麦管理:连麦申请 / 邀请 / 同意 / 拒绝,连麦成员权限控制(麦克风 / 摄像头),状态同步。 | |
CoHostStore | 主播跨房连线:支持多布局模板(动态网格等),发起 / 接受 / 拒绝连线,连麦主播互动管理。 | |
BattleStore | 主播 PK 对战:发起 PK(配置时长 / 对手),管理 PK 状态(开始 / 结束),同步分数,监听对战结果。 | |
GiftStore | 礼物互动:获取礼物列表,发送 / 接收礼物,监听礼物事件(含发送者、礼物详情)。 | |
BarrageStore | 弹幕功能:发送文本 / 自定义弹幕,维护弹幕列表,实时监听弹幕状态。 | |
LikeStore | 点赞互动:发送点赞,监听点赞事件,同步总点赞数。 | |
LiveAudienceStore | 观众管理:获取实时观众列表(ID / 名称 / 头像),统计观众数量,监听观众进出事件。 | |
AudioEffectStore | 音频特效:变声(童声 / 男声)、混响(KTV 等)、耳返调节,实时切换特效。 | |
BaseBeautyStore | 基础美颜:调节磨皮 / 美白 / 红润(0-9级),重置美颜状态,同步效果参数。 |
常见问题
主播调用 createLive 或 观众调用 joinLive 后为什么画面是黑的,没有视频画面?
检查 setLiveID:请确保在调用开播或观看接口前,已经为 LiveCoreView 实例设置了正确的 liveID。
检查设备权限:请确保 App 已获得摄像头和麦克风的系统使用权限。
检查主播端:主播端是否正常调用
DeviceStore.shared.openLocalCamera(isFront: true) 打开了摄像头。检查网络:请检查设备网络连接是否正常。
主播端打开摄像头后,开播后可以看到本地视频预览画面,开播前视频预览是黑屏?
检查主播端:请检查主播推流视图
LiveCoreView 的 viewType是否配置为.pushView。检查观众端:请检查观众拉流视图
LiveCoreView 的 viewType是否配置为 .playView。使用 updateLiveMetaData 时有哪些需要注意的限制和规则?
为了保证系统的稳定和高效,
metaData 的使用遵循以下规则:权限: 只有房主和管理员可以调用
updateLiveMetaData。普通观众没有权限。数量与大小限制:
单个房间最多支持 10 个 key。
每个 key 的长度不超过 50 字节,每个 value 的长度不超过 2KB。
单个房间所有 value 的总大小不超过 16KB。
冲突解决:
metaData 的更新机制是"后来者覆盖"。如果多个管理员在短时间内修改同一个 key,最后一次的修改会生效。建议在业务设计上避免多人同时修改同一个关键信息。rsync 因权限不足导致依赖三方库资源拷贝失败
例如在使用 Xcode 集成 SnapKit 框架进行开发时,可能会遇到如下编译报错:
rsync(xxxx):1:1: SnapKit.framework/SnapKit_Privacy.bundle/: mkpathat: Operation not permitted
问题原因
Xcode 的用户脚本沙盒机制限制了构建过程中
rsync 脚本对 SnapKit.framework 资源文件的写入权限,导致框架内的 SnapKit_Privacy.bundle 无法正常拷贝。解决步骤
1. 关闭用户脚本沙盒打开 Xcode 项目,进入项目的 Build Settings,搜索
User Script Sandboxing(或标识 ENABLE_USER_SCRIPT_SANDBOXING),将其值从 YES 修改为 NO。2. 清理并重新构建项目执行 Product → Clean Build Folder 清理项目缓存,然后重新编译运行即可。



