TUIRoomKit 是腾讯云提供的一站式多人音视频房间解决方案，集成了完整的 UI 组件和核心功能。通过本文档，开发者可以快速了解如何将 TUIRoomKit 集成到项目中，实现多人音视频房间功能。本文还将详细介绍如何快速替换图片资源、本地化文案等个性化配置，帮助开发者打造符合品牌特色的音视频应用。
| 房间准备页 | 标准房间主页 | 大型研讨会房间主页 | 成员管理 |
| --- | --- | --- | --- |
|  |  |  |  |

## 前提条件

### 开通服务

请参考 开通服务 领取 `TUIRoomKit` 体验版，并在 [应用管理](https://console.cloud.tencent.com/trtc) 页面获取以下信息：
- **SDKAppID**：应用标识（必填），腾讯云基于 SDKAppID 完成计费统计。

- **SDKSecretKey**：应用密钥，用于初始化配置文件的密钥信息。

### 环境准备

在开始运行 Demo 之前，请确保您的开发环境满足以下要求：
- **Xcode**：需使用 **Xcode 15 **或更高版本。

- **iOS 系统**：支持 **iOS 13.0 **或更高版本的设备。

- **CocoaPods 环境**：已安装 CocoaPods 环境。如果您尚未安装，请参见 [CocoaPods官网安装](https://guides.cocoapods.org/using/getting-started.html)，或按以下步骤操作：

  - **使用 gem 安装 CocoaPods**：在终端中执行 `sudo gem install cocoapods` 命令进行安装。

      > **提示：**
      >

      > `sudo gem install cocoapods` 安装过程中可能需要输入电脑密码，按提示输入管理员密码即可。
      >

## 快速接入

### 步骤1：集成 TUIRoomKit 组件
1. **添加 Pod 依赖：**

  - **若项目已有 Podfile 文件。**

      在您项目的 `Podfile` 文件中添加 `pod 'TUIRoomKit'` 依赖。例如：

      ``` ruby
        target 'YourProjectTarget' do
          # 其他已有的 Pod 依赖...
          # 添加 pod 'TUIRoomKit' 依赖
          pod 'TUIRoomKit'

        end
      ```
  - **若项目没有 Podfile 文件。**

      在终端中通过 `cd` 命令切换到您的 `.xcodeproj` 目录下，然后执行 `pod init` 命令创建 `Podfile` 文件，创建完成后，在您的 `Podfile` 文件中添加 `pod 'TUIRoomKit'` 依赖。例如：

      ``` bash
      // 如果您的项目目录是 /Users/yourusername/Projects/YourProject

      // 1. cd 到您的.xcodeproj 工程目录下
      cd /Users/yourusername/Projects/YourProject

      // 2. 执行 pod init，此命令运行完后，会在您的工程目录下生成一个 Podfile 文件。
      pod init

      // 3. 在生成的 Podfile 文件中添加 pod 'TUIRoomKit' 依赖
        target 'YourProjectTarget' do
          # 添加 pod 'TUIRoomKit' 依赖
          pod 'TUIRoomKit'

        end
      ```
2. **安装组件**：

   在终端中 `cd` 到 `Podfile` 文件所在的目录，然后执行以下命令安装组件。

   ``` bash
   pod install
   ```

### 步骤2：工程配置

为了使用音视频功能，您的应用需要获取麦克风和摄像头的权限。请在应用的 `Info.plist` 文件中添加以下两项，并填写对应的使用说明，这些说明将在系统请求权限时向用户显示：
``` ruby
<key>NSCameraUsageDescription</key>
<string>TUIRoomKit需要访问您的相机权限</string>
<key>NSMicrophoneUsageDescription</key>
<string>TUIRoomKit需要访问您的麦克风权限</string>
```

### 步骤3：登录

代码集成完成后，需要完成登录操作，这是**使用 **`TUIRoomKit`** 的关键步骤**。只有在登录成功后，才能正常使用 `TUIRoomKit` 的各项功能，因此请仔细检查相关参数配置是否正确：

> **说明：**
>

> 在示例代码中，登录操作是在 `didFinishLaunchingWithOptions` 方法内完成的。但在实际项目场景下，强烈推荐**在完成自己的用户身份验证等相关登录操作后，再调用 AtomicXCore 的登录服务**。这样可以避免因过早调用登录服务，导致业务逻辑混乱或数据不一致的问题，同时也能更好地适配您项目中现有的用户管理和权限控制体系。
>

【Swift】
``` swift
import AtomicXCore

//  AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    LoginStore.shared.login(sdkAppID: 1400000001,                  // 替换为项目的 sdkAppID
                            userID: "test_001",                    // 替换为项目的 userID
                            userSig: "xxxxxxxxxxx") { result in    // 替换为项目的 userSig
      switch result {
        case .success(let info):
        debugPrint("login success")
        case .failure(let error):
        debugPrint("login failed code:\(error.code), message:\(error.message)")
      }
    }
    return true
}
```

**登录接口参数说明：**
| 参数 | 类型 | 说明 |
| --- | --- | --- |
| `sdkAppID` | `Int32` | 从 [控制台](https://console.cloud.tencent.com/trtc) 获取，通常是以 `140` 或 `160` 开头的 10 位整数。 |
| `userID` | `String` | 当前用户的唯一 ID，仅包含英文字母、数字、连字符和下划线。为避免多端登录冲突，**请勿使用**`1`、`123`**等简单 ID**。 |
| `userSig` | `String` | 用于腾讯云鉴权的票据。更多信息请参见 如何计算及使用 UserSig。<br>**注意：**<br>- 开发环境：可以采用本地 `GenerateTestUserSig.genTestSig` 函数生成 userSig 或者通过 [UserSig 辅助工具](https://console.cloud.tencent.com/im/tool-usersig) 生成临时的 userSig。<br>- 生产环境：为了防止密钥泄露，请务必采用服务端生成 userSig 的方式。详细信息请参考 服务端生成 UserSig。 |

### 步骤4：设置头像和昵称

首次登录的用户没有头像和昵称信息，需要通过 `LoginStore` 的 `setSelfInfo` 接口设置个人信息：
``` swift
import AtomicXCore

func setSelfInfo() {
    let userProfile = UserProfile(userID: "test_001",        // 您已经登录的userID
                                nickname: "tom",             // 设置昵称
                               avatarURL: "http://xxx.png")  // 设置头像URL
    LoginStore.shared.setSelfInfo(userProfile: userProfile) { result in
      switch result {
      case .success():
        debugPrint("setSelfInfo success")
      case .failure(let error):
        debugPrint("setSelfInfo failed code:\(error.code), message:\(error.message)")
      }
    }
}
```

**setSelfInfo接口参数说明：**
| 参数 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `userProfile` | `UserProfile` | 是 | 个人用户信息核心模型，包含：<br>- userID：要设置用户信息的用户 ID。<br>- nickname：昵称信息。<br>- avatarURL：头像链接。 |
| `completion` | `CompletionClosure` | 否 | 设置个人信息接口的结果回调。若失败会返回错误码和错误信息。 |

### 步骤5：创建房间

在 `TUIRoomKit` 组件中，`RoomMainView` 是集成了完整的多人音视频房间功能的核心界面，以下将向开发者演示如何以房主身份将 `RoomMainView` 嵌入到应用中。

#### **实现方式：**
1. **遵守路由导航协议**：`TUIRoomKit` 内部使用 `RouterContext` 协议管理页面间的路由跳转。宿主视图控制器需要声明遵循该协议，以确保组件内部的导航操作（如结束房间、返回上一页）能够正确执行。

2. **懒加载创建视图页面**：在控制器内部以懒加载方式实例化 `RoomMainView`，并为其设置 `routerContext` 属性。该属性使得视图能够通过协议方法调用宿主控制器的导航功能。

3. **构造进房的配置项**：进入房间后是否需要自动打开音视频设备的配置项。

4. **初始化房间主页面**：通过房主身份初始化房间主页面。

5. **将视图添加到控制器**：在控制器的 `viewDidLoad` 方法中，将 `RoomMainView` 加入视图层级，并使用约束布局使其充满整个控制器视图区域。

   > **说明：**
   >
>   - `TUIRoomKit` 的内部页面跳转机制基于 `UINavigationController` 的标准导航方法（push/pop）实现。为确保页面路由功能正常工作，开发者的视图控制器必须作为 `UINavigationController` 的根视图控制器或位于其导航栈内。若未将控制器包装至 `UINavigationController` 中，SDK 内部的跳转操作将因缺少有效的导航上下文而失效，导致页面无法正常切换。
>   - 移动端仅支持创建标准房间，如果您需要创建大型研讨会房间，请参考 Web 快速接入 使用 Web 端创建。

#### **示例代码：**
``` swift
import UIKit
import TUIRoomKit
import SnapKit
import AtomicXCore

// YourMainViewController 代表您加载房间主页面的视图控制器

// 1. YourMainViewController 需要遵守 TUIRoomKit 组件中的 RouterContext 协议
class YourMainViewController: UIViewController, RouterContext {

    // 2. 懒加载创建 TUIRoomKit 中的 RoomMainView 房间主页面
    private lazy var mainView: RoomMainView = {
        // 3. 构造进房的配置项
        var config = ConnectConfig()
        config.autoEnableCamera = true      // 进房后是否自动开启摄像头
        config.autoEnableMicrophone = true  // 进房后是否自动开启麦克风
        config.autoEnableSpeaker = true     // 进房后是否自动开启扬声器

        // 4 房主身份初始化房间主页面
        var options = CreateRoomOptions()
        options.roomName = "roomName"       // 房间名称

        let view = RoomMainView(roomID: "roomID", behavior: .create(options: options), config: config)
        view.routerContext = self
        return view
    }()

    public override func viewDidLoad() {
        super.viewDidLoad()
        // 5. 将 RoomMainView 对象 添加到视图控制器中
        view.addSubview(mainView)
        mainView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
    }
}
```

**RoomMainView 构造函数参数详细说明：**
| 参数 | 类型 | 说明 |
| --- | --- | --- |
| `roomID` | `String` | - 字符串类型的房间唯一标识符。<br>- 限制长度为 0-48 字节。<br>- 建议仅包含数字、英文字母（区分大小写）、下划线（_）和连字符（-）。避免使用空格和中文字符。 |
| `behavior` | `RoomBehavior` | 房间主页面初始化来源。<br>- create：房主身份创建房间的方式需要构造创建房间配置项。<br>- 关于 `CreateRoomOptions` 的详细用法请参考：CreateRoomOptions 结构体详细说明。<br>- join：参与者身份加入房间。 |
| `config` | `ConnectConfig` | 进房后音视频设备控制的配置项。 |

**ConnectConfig 参数详细说明****：**
| 参数 | 类型 | 说明 |
| --- | --- | --- |
| autoEnableMicrophone | `Bool` | 进房后是否自动开启麦克风。<br>- true：自动开启 （默认值）。<br>- false：不自动开启。 |
| autoEnableCamera | `Bool` | 进房后是否自动开启摄像头。<br>- true：自动开启 （默认值）。<br>- false：不自动开启。 |
| autoEnableSpeaker | `Bool` | 进房后是否自动开启扬声器。<br>- true：自动开启 （默认值）。<br>- false：不自动开启。 |

### 步骤6：加入房间

以下示例将向开发者演示如何以参与者身份将`RoomMainView`嵌入到应用中。

#### **实现方式：**
1. **遵守路由导航协议**：`TUIRoomKit` 内部使用 `RouterContext` 协议管理页面间的路由跳转。宿主视图控制器需要声明遵循该协议，以确保组件内部的导航操作（如结束房间、返回上一页）能够正确执行。

2. **懒加载创建视图页面**：在控制器内部以懒加载方式实例化 `RoomMainView`，并为其设置 `routerContext` 属性。该属性使得视图能够通过协议方法调用宿主控制器的导航功能。

3. **构造进房的配置项**：进入房间后是否需要自动打开音视频设备的配置项。

4. **初始化房间主页面**：通过参与者身份初始化房间主页面。

5. **将视图添加到控制器**：在控制器的 `viewDidLoad` 方法中，将 `RoomMainView` 加入视图层级，并使用约束布局使其充满整个控制器视图区域。

#### 代码示例：
``` swift
import UIKit
import TUIRoomKit
import SnapKit
import AtomicXCore
// YourMainViewController 代表您加载房间主页面的视图控制器

// 1. YourMainViewController 需要遵守 TUIRoomKit 组件中的 RouterContext 协议
class YourMainViewController: UIViewController, RouterContext {

    // 2. 懒加载创建 TUIRoomKit 中的 RoomMainView 房间主页面
    private lazy var mainView: RoomMainView = {
        // 3. 构造进房的配置项
        var config = ConnectConfig()
        config.autoEnableCamera = true      // 进房后是否自动开启摄像头
        config.autoEnableMicrophone = true  // 进房后是否自动开启麦克风
        config.autoEnableSpeaker = true     // 进房后是否自动开启扬声器

        // 4. 参与者身份初始化房间主页面
         let view = RoomMainView(roomID: "roomID", behavior: .join, config: config)
        view.routerContext = self
        return view
    }()

    public override func viewDidLoad() {
        super.viewDidLoad()

        // 5. 将 RoomMainView 对象 添加到视图控制器中
        view.addSubview(mainView)
        mainView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
    }
}
```

**参数详细说明请参考：**

[RoomMainView 构造函数参数详细说明]( 构造函数参数详细说明)和 [ConnectConfig 参数详细说明]( 参数详细说明)

> **说明：**
>

> 使用 **TUIRoomKit** 组件进入大型研讨会房间时，需确保Web端创建的研讨会房间的房间ID以 `webinar_` 开头。
>

## 核心功能

接入`RoomMainView`代码后，开发者将得到一个完整的多人音视频页面，内部包含成员管理，音视频设备控制，房间信息展示等功能，这是 `TUIRoomKit` 组件的核心。
| 标准房间 | 大型研讨会房间 |
| --- | --- |
|  |  |

## 界面定制

> **注意：**
>

> 界面定制、图标定制、文案定制这部分章节内容，涉及到需要修改`TUIRoomKit` 组件源码，通过 **CocoaPods** 依赖管理器集成`TUIRoomKit`将被视为“不可变”的依赖项。每次执行 pod install 时，**CocoaPods** 会：
>
> - 检查 Podfile.lock 中记录的版本号。
> - 从远程仓库重新下载对应版本的源码。
> - 用下载的原始代码覆盖 Pods/ 目录下的现有文件。

> **因此，任何对 Pods/ 目录的手动修改都只是临时性的，下次执行安装命令时即被还原。**
>

> **推荐解决方案：**
>
> - Fork [TUIRoomKit](https://github.com/Tencent-RTC/TUIKit_iOS) 的官方仓库。
> - 在 fork 的仓库中修复问题并提交。
> - 修改 Podfile，指向自定义仓库和分支。
> `pod 'TUIRoomKit', :git => 'https://github.com/your-username/TUIRoomKit.git', :branch => 'your-branch'`

`RoomMainView`房间主页面内功能丰富，可定制化度高，开发者可以根据实际产品需求，对 UI 进行定制化修改，以适配业务交互场景。以下将详细为开发者展示`RoomMainView`页面中视图组件，便于开发者快速修改。
| 标准房间 | 大型研讨会房间 |
| --- | --- |
|  |  |

`RoomMainView`**中的组件详细说明**
| 组件 | 功能描述 | 定制化建议 |
| --- | --- | --- |
| [RoomMainView](https://github.com/Tencent-RTC/TUIKit_iOS/blob/main/room/Source/View/RoomMainView.swift) | 房间主视图容器，负责协调各子组件的布局与数据流转。 | 可调整整体背景、安全区域适配、组件显隐逻辑。 |
| [RoomTopBarView](https://github.com/Tencent-RTC/TUIKit_iOS/blob/main/room/Source/View/Main/RoomTopBarView.swift) | 顶部导航栏，包含房间信息、摄像头和声音控制、退出房间功能入口。 | 可替换图标、调整背景透明度、添加自定义按钮（例如录制、 窗口化）。 |
| [RoomView](https://github.com/Tencent-RTC/TUIKit_iOS/blob/main/room/Source/View/Main/RoomView.swift) | 视频流展示区域，采用瀑布流布局管理多个用户视频画面。 | 可修改布局算法（行列数、间距）、分页指示器样式、空状态视图。 |
| [RoomViewVideoStreamCell](https://github.com/Tencent-RTC/TUIKit_iOS/blob/main/room/Source/View/Main/RoomView/RoomViewCell.swift) | 单个视频流单元格，承载用户视频画面与基本信息。 | 可自定义视频渲染层、用户信息面板（头像、徽章）、互动控件（语音波形）。 |
| [RoomBottomBarView](https://github.com/Tencent-RTC/TUIKit_iOS/blob/main/room/Source/View/Main/RoomBottomBarView.swift) | 底部工具栏，集成麦克风、摄像头、成员管理操作按钮。 | 可重新排列按钮顺序、修改按钮样式（颜色、尺寸）、添加业务相关功能（例如屏幕分享、会中呼叫、美颜）。 |

## 图标定制

接入 `TUIRoomKit` 组件后，开发者可以根据实际 UI 交互需求直接替换组件下的图标资源， 以适配开发者的业务场景。

`TUIRoomKit` 使用 `TUIRoomKit.xcassets`管理 UI 所需的图片资源，您可以借助 Xcode 图形化工具快速修改自定义界面所需的图标。

**常用的图片文件列表**
| 图标 | 文件名 | 说明 |
| --- | --- | --- |
|  | camera_close.png | 摄像头关闭图标 |
|  | camera_open.png | 摄像头开启图标 |
|  | room_mic_off_red.png | 麦克风关闭图标 |
|  | room_mic_on_big.png | 麦克风开启图标 |
|  | room_admin_tag.png | 管理员身份标识图标 |
|  | room_owner_tag.png | 房主身份标识图标 |

## 文案定制

`TUIRoomKit` 使用更为方便的 [Apple Strings Catalog](https://developer.apple.com/documentation/xcode/localizing-and-varying-text-with-a-string-catalog) 工具来管理 UI 所需的文案显示，您可以很直观的通过  Xcode 视图化管理工具修改需要调整的文案：

> **说明：**
>

> [Apple Strings Catalog](https://developer.apple.com/documentation/xcode/localizing-and-varying-text-with-a-string-catalog) (.xcstrings) 是在 Xcode 15 中引入的本地化格式。它增强了开发者管理本地化字符串的方式，支持处理复数、设备特定变体等的结构化格式。这种格式正成为管理 iOS 和 macOS 应用程序本地化的推荐方法。
>

## 常见问题

### pod install 执行后本地安装找不到 TUIRoomKit 最新版本？

如果无法安装 `TUIRoomKit` 最新版本，请按以下步骤操作：
1. 在 Podfile 所在目录下删除 `Podfile.lock`和 `Pods`，您可以选择手动删除或终端执行以下命令：

   ``` bash
   // cd 到 Podfile 所在目录下

   rm -rf Pods/
   rm Podfile.lock
   ```
2. 在 Podfile 所在目录下执行 `pod install --repo-update`：

   ``` bash
   // cd 到 Podfile 所在目录下

   pod install --repo-update
   ```

### 每次进房都需要调用登录吗？

不需要。通常您只需要完成一次 `LoginStore.shared.login` 调用即可，我们建议您将 `LoginStore.shared.login` 和

`LoginStore.shared.logout` 与自己的登录业务关联。

### Podfile 文件有没有示例配置可以参考？

您可以参考 [GitHub TUIKit_iOS Example](https://github.com/Tencent-RTC/TUIKit_iOS/tree/main/application) 工程 `Podfile` 示例文件。
