快速实现
AUIKaraoke 是一个基于 AUIKit 搭建的、针对 K 歌场景的开源 UI 组件,提供 K 歌房间相关功能。asceneskit 是 K 歌房的容器组件,你可以通过 asceneskit 自定义 K 歌房间的用户界面逻辑、实现房间管理等。
本文介绍如何通过 AUIKaraoke 快速搭建一个含 UI 界面的在线 K 歌房。
示例项目
声网在 GitHub 上提供一个开源的示例项目 供你参考。
准备开发环境
本节介绍集成 AUIKaraoke 的前提条件和项目相关配置。
前提条件
-
CocoaPods 1.12.1 及以上
-
Xcode 14.0 及以上
-
iOS 设备,版本 13.0 及以上
信息声网推荐使用真机运行项目。部分模拟机可能存在功能缺失或者性能问题。
-
有效的苹果开发者账号
-
你的声网项目的 App ID、证书,以及环信项目的 APPKEY、Client ID 以及 Client Secret,如何获取请参考开通服务
创建并配置项目
按照下列步骤来创建并配置你的项目。
-
创建一个新的项目,Application 选择 App,Interface 选择 Storyboard,Language 选择 Swift。
如果你没有添加过开发团队信息,会看到 Add account… 按钮。点击该按钮并按照屏幕提示登录 Apple ID,点击 Next,完成后即可选择你的 Apple 账户作为开发团队。
-
为你的项目设置自动签名。
-
设置部署你的 App 的目标设备。
-
添加项目的设备权限。在项目导航栏中
info
下,配置麦克风权限,如下图所示:
添加依赖库
-
下载声网提供的 AUIKaraoke 源码。运行以下命令克隆项目到本地:
Shellgit clone git@github.com:AgoraIO-Community/AUIKaraoke.git
-
将 AUIKaraoke 源码目录下
iOS/AScenesKit
文件夹复制到你的项目路径下,例如放在和AUIKitDemo.xcodeproj
同级的目录下。 -
将 AUIKaraoke 源码目录下
iOS/Example/AUIKaraoke/KaraokeUIKit.swift
类复制到你的项目路径下。- 选中项目下
AUIKitDemo
文件夹,右键选择 Add Files to "AUIKitDemo"。
- 选中项目下

- 指定
KaraokeUIKit.swift
文件,勾选 Destination: Copy items if neeed,点击右下角Add
。

-
在
AUIKitDemo.xcodeproj
同级目录下创建一个 Podfile 文件,并添加如下内容:Rubysource 'https://github.com/CocoaPods/Specs.git'
platform :ios, '13.0'
target 'AUIKitDemo' do
use_frameworks!
pod 'AScenesKit', :path => './AScenesKit'
pod 'AgoraRtcEngine_Special_iOS', '4.1.1.29'
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
end
end
end -
在 Podfile 文件目录下打开终端,执行下列命令来把 AScenesKit 的相关依赖集成进 App 中:
Rubypod update --verbose
成功后,该目录下会新生成一个
AUIKitDemo.xcworkspace
文件。如果你在执行上述命令时因网络问题而失败,可尝试更换镜像源,详见常见问题。 -
打开
AUIKitDemo.xcworkspace
文件,点击 Start the active scheme 来编译项目。如果你使用的 Xcode 15,在编译时可能遇到报错,可参考常见问题解决报错。
创建在线 K 歌房
本节介绍如何以房主身份快速搭建一个在线 K 歌房来体验 K 歌场景。
1. 初始化 AUIKaraoke
-
添加依赖。
在
AppDelegate.swift
文件中添加下列代码来添加依赖:Swiftimport AUIKitCore
import AScenesKit -
初始化 KaraokeUIKit。
创建
AUiCommonConfig
对象,调用setup
初始化来 KaraokeUIKit。在AppDelegate.swift
文件中添加下列代码:Swiftfunc application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 随机设置用户 uid
let uid = Int(arc4random_uniform(99999999))
let commonConfig = AUICommonConfig()
// 你的声网 AppID
commonConfig.appId = KeyCenter.AppId
// 你的声网 App 证书
commonConfig.appCert = KeyCenter.AppCertificate
// 你的 IM AppKey
commonConfig.imAppKey = KeyCenter.IMAppKey
// 你的 IM Client ID
commonConfig.imClientId = KeyCenter.IMClientId
// 你的 IM Client Secret
commonConfig.imClientSecret = KeyCenter.IMClientSecret
// 你的业务服务器域名
commonConfig.host = KeyCenter.HostUrl
let ownerInfo = AUIUserThumbnailInfo()
// 用户 ID
ownerInfo.userId = "\(uid)"
// 用户名
ownerInfo.userName = "user_\(uid)"
// 用户头像
ownerInfo.userAvatar = "https://accktvpic.oss-cn-beijing.aliyuncs.com/pic/sample_avatar/sample_avatar_1.png"
commonConfig.owner = ownerInfo
KaraokeUIKit.shared.setup(commonConfig: commonConfig,
// apiConfig 包含 KtvApi、RtcEngine、RtmClient 对象。如果你的项目中还未使用这几个对象,请传入 nil, AUIKaraoke 内部会自行创建
apiConfig: nil)
return true
}
2. 创建并进入房间
-
在
ViewController.swift
文件中添加下列依赖:Swiftimport AUIKitCore
import AScenesKit -
添加创建房间按钮。
在
ViewController.swift
文件中,将viewDidLoad
替换为下列代码:Swiftoverride func viewDidLoad() {
super.viewDidLoad()
//作为房主创建房间的按钮
let createButton = UIButton(frame: CGRect(x: 10, y: 100, width: 100, height: 60))
createButton.setTitle("创建房间", for: .normal)
createButton.setTitleColor(.red, for: .normal)
createButton.addTarget(self, action: #selector(onCreateAction), for: .touchUpInside)
view.addSubview(createButton)
} -
在
ViewController
文件中声明一个在线 K 歌房间容器的属性。Swiftclass ViewController: UIViewController {
var karaokeView: AUIKaraokeRoomView?
....
} -
生成启动房间所需的 RTC Token 和 RTM Token。在
ViewController.swift
文件中,将下列代码添加至viewDidLoad
之后:Swift// 生成并配置房间的 Token
private func generateToken(channelName: String,
roomConfig: AUIRoomConfig,
completion: @escaping ((Error?) -> Void)) {
// 获取当前用户的 ID
let uid = KaraokeUIKit.shared.commonConfig?.owner?.userId ?? ""
// 定义 RTC 合唱频道的名称
let rtcChorusChannelName = "\(channelName)_rtc_ex"
// 主频道的频道名
roomConfig.channelName = channelName
// 和合唱频道的频道名
roomConfig.rtcChorusChannelName = rtcChorusChannelName
print("generateTokens: \(uid)")
let group = DispatchGroup()
var err: Error?
group.enter()
let tokenModel1 = AUITokenGenerateNetworkModel()
tokenModel1.channelName = channelName
tokenModel1.userId = uid
// 发起网络请求来生成 Token
tokenModel1.request { error, result in
defer {
if err == nil {
err = error
}
group.leave()
}
guard let tokenMap = result as? [String: String], tokenMap.count >= 2 else {return}
roomConfig.rtcToken = tokenMap["rtcToken"] ?? ""
roomConfig.rtmToken = tokenMap["rtmToken"] ?? ""
}
group.enter()
let tokenModel2 = AUITokenGenerateNetworkModel()
tokenModel2.channelName = rtcChorusChannelName
tokenModel2.userId = uid
// 发起网络请求来生成 Token
tokenModel2.request { error, result in
defer {
if err == nil {
err = error
}
group.leave()
}
guard let tokenMap = result as? [String: String], tokenMap.count >= 2 else {return}
roomConfig.rtcChorusRtcToken = tokenMap["rtcToken"] ?? ""
}
group.notify(queue: DispatchQueue.main) {
completion(err)
}
} -
创建房间详情页再调用
createRoom
创建并进入房间。在ViewController.swift
文件中,将下列代码添加至viewDidLoad
之后:Swift@objc func onCreateAction(_ button: UIButton) {
button.isEnabled = false
// 生成一个随机的房间 ID
let roomId = Int(arc4random_uniform(99999999))
let roomInfo = AUIRoomInfo()
roomInfo.roomId = "\(roomId)"
roomInfo.roomName = "\(roomId)"
roomInfo.owner = AUIRoomContext.shared.currentUserInfo
let roomConfig = AUIRoomConfig()
// 创建房间容器
let karaokeView = AUIKaraokeRoomView(frame: self.view.bounds)
// 生成进入房间所需的 Token
generateToken(channelName: "\(roomId)",
roomConfig: roomConfig,
completion: {[weak self] error in
guard let self = self else {return}
if let error = error {
button.isEnabled = true
self.navigationController?.popViewController(animated: true)
AUIToast.show(text: error.localizedDescription)
return
}
// 创建房间
KaraokeUIKit.shared.createRoom(roomInfo: roomInfo,
roomConfig: roomConfig,
karaokeView: karaokeView) {[weak self] error in
guard let self = self else {return}
button.isEnabled = true
if let error = error {
AUIToast.show(text: error.localizedDescription)
return
}
}
})
// 将房间视图添加到当前视图
self.view.addSubview(karaokeView)
self.karaokeView = karaokeView
}
至此,你已经成功创建一个在线 K 歌房。
测试 App
参考以下步骤来测试你的 App:
-
将 iOS 设备连接至计算机。
-
点击 start the active scheme 来运行你的项目,需等待几秒至 App 安装完成。
-
(可选)如果设备上弹出不受信任的开发者提示,则首先点击取消关闭该提示,然后在 iOS 设备上打开设置 > 通用 > VPN 与设备管理,在开发者 APP 中选择信任该开发者。
-
安装成功后,你的 iOS 设备上会出现 AUIKaraoke App。打开 App,点击创建房间创建一个新的房间来体验在线 K 歌。
后续步骤
成功搭建一个在线 K 歌房间后,你还可以参考本节来进一步了解启动 K 歌房间后的后续步骤。
听众进入房间
-
添加加入房间按钮。 在
ViewController
文件中添加下列代码:Swiftoverride func viewDidLoad() {
super.viewDidLoad()
...
// 观众加入房间的按钮
let joinButton = UIButton(frame: CGRect(x: 10, y: 160, width: 100, height: 60))
joinButton.setTitle("加入房间", for: .normal)
joinButton.setTitleColor(.red, for: .normal)
joinButton.addTarget(self, action: #selector(onJoinAction), for: .touchUpInside)
view.addSubview(joinButton)
} -
获取房间信息并调用
enterRoom
加入房间。在ViewController
文件中,将下列代码添加至func onCreateAction
之后:Swift@objc func onJoinAction() {
let alertController = UIAlertController(title: "房间名", message: "", preferredStyle: .alert)
alertController.addTextField { (textField) in
textField.placeholder = "请输入"
}
let cancelAction = UIAlertAction(title: "取消", style: .cancel) { (_) in
}
let saveAction = UIAlertAction(title: "确认", style: .default) { (_) in
if let inputText = alertController.textFields?.first?.text {
// 处理用户输入的内容,获取房间信息列表
KaraokeUIKit.shared.getRoomInfoList(lastCreateTime: 0, pageSize: 50) { error, roomList in
guard let roomList = roomList else {return}
for room in roomList {
if room.roomName == inputText {
self.enterRoom(roomInfo: room)
break
}
}
}
}
}
alertController.addAction(cancelAction)
alertController.addAction(saveAction)
present(alertController, animated: true, completion: nil)
}
// 进入房间
func enterRoom(roomInfo: AUIRoomInfo) {
let karaokeView = AUIKaraokeRoomView(frame: self.view.bounds)
let roomId = roomInfo.roomId
let roomConfig = AUIRoomConfig()
generateToken(channelName: roomId,
roomConfig: roomConfig) {[weak self] err in
guard let self = self else {return}
KaraokeUIKit.shared.enterRoom(roomId: roomId,
roomConfig: roomConfig,
karaokeView: karaokeView) {[weak self] roomInfo, error in
guard let self = self else {return}
if let error = error {
self.navigationController?.popViewController(animated: true)
AUIToast.show(text: error.localizedDescription)
return
}
}
}
self.view.addSubview(karaokeView)
self.karaokeView = karaokeView
}
退出及销毁房间
当你不再需要进行 K 歌时,调用 leaveRoom
销毁房间。调用 unbindRespDelegate
取消绑定对应房间的响应。取消后,将不再通知 AUIRoomManagerRespDelegate
对象与房间管理操作相关的结果或响应。 在 ViewController
文件中添加下列代码:
func destroyRoom(roomId: String) {
//点击退出
self.karaokeView?.onBackAction()
self.karaokeView?.removeFromSuperview()
KaraokeUIKit.shared.leaveRoom(roomId: roomId)
//在退出房间时取消订阅
KaraokeUIKit.shared.unbindRespDelegate(delegate: self)
}
-
当房间被销毁时,退出该房间。
调用
bindRespDelegate
来订阅房间相关事件。在销毁房间时,调用unbindRespDelegate
取消订阅房间相关事件,然后通过onRoomDestroy
来处理房间销毁。在ViewController
文件将下列代码添加至destroyRoom
之后:Swiftclass ViewController: UIViewController {
@objc func onCreateAction(_ button: UIButton) {
...
// 房主订阅房间被销毁回调
KaraokeUIKit.shared.bindRespDelegate(delegate: self)
}
func enterRoom(roomInfo: AUIRoomInfo) {
...
// 听众订阅房间被销毁回调
KaraokeUIKit.shared.bindRespDelegate(delegate: self)
}
}
extension ViewController: AUIKaraokeRoomServiceRespDelegate {
//房间销毁
func onRoomDestroy(roomId: String) {
self.destroyRoom(roomId: roomId)
}
} -
主动退出房间。当你结束 K 歌并需要释放 K 歌房使用的所有资源时,退出并销毁当前房间。示例代码如下:
Swift@objc func onCreateAction(_ button: UIButton) {
...
let karaokeView = AUIKaraokeRoomView(frame: self.view.bounds)
karaokeView.onClickOffButton = { [weak self] in
// 房主退出并销毁房间
self?.destroyRoom(roomId: roomInfo.roomId)
}
}
func enterRoom(roomInfo: AUIRoomInfo) {
...
let karaokeView = AUIKaraokeRoomView(frame: self.view.bounds)
karaokeView.onClickOffButton = { [weak self] in
// 听众退出房间
self?.destroyRoom(roomId: roomInfo.roomId)
}
}
常见问题
pod update 失败
如果你在执行 pod update
命令时,因网络问题而失败,可尝试使用国内镜像源。
-
打开
Podfile
文件,将source
替换为国内镜像源:Rubysource 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git'
-
保存文件,重新执行
pod update
命令。
使用 Xcode 15 编译报错
如果你使用 Xcode 15,在编译时可能遇到下列报错:
Sandbox: rsync.samba(47334) deny(1) file-write-create...
你可以在导航栏的 Build Settings 中将 User Script Sandboxing 设为 NO
,如下图所示: