帮你快速理解、总结文档立即下载

iOS(UIKit)

最近更新时间:2026-09-04 16:44:09
我的收藏
TUIKit 是基于 IM SDK 的一款 UI 组件库,可通过 UI 组件快速实现聊天、会话、搜索、关系链、群组等功能。本文介绍如何快速集成 TUIKit 并实现核心功能。

集成 TUIKit

TUIKit 采用数据驱动的响应式架构与原生 iOS UIKit 体系(非声明式 UI ),以源码方式开放集成。它提供会话列表、聊天、联系人、搜索、群组等完整 UI 能力。

前提条件

Xcode:16.0 或以上版本(推荐 Xcode 16.x 系列)。
iOS:14.0 及以上真机(暂时不支持模拟器)。
CocoaPods:1.12.0 及以上版本(推荐 1.16.x)。如尚未安装,请参考 CocoaPods Getting Started 进行安装。
一个有效的腾讯云账号及 Chat 应用。可参考 开通服务 从控制台获取以下信息:
SDKAppID:App 在控制台获取的 Chat 应用的 ID,为应用的唯一标识。
SDKSecretKey:应用的密钥。

集成并引入组件

说明:
Demo:IM 在 CNBGitHub 上提供即时通信完整 Demo,5 分钟跑通聊天 + 音视频通话全功能

下载源码

CNB 或者 GitHub 克隆 TUIKit iOS 源码
# 从 CNB 中克隆代码
git clone https://cnb.cool/tencent/cloud/trtc/TUIKit_iOS.git

# 从 GitHub 中克隆代码
git clone https://github.com/Tencent-RTC/TUIKit_iOS.git
将仓库根目录下的 chatcall 文件夹整体复制到您的工程根目录下。复制完成后的目录结构如下:
YourApplication/
├── source/ # 您的工程代码
├── call/ # 音视频通话组件
│ └── TUICallKit_Swift.podspec
│ └── TUICallKit_Swift/
├── chat/ # Chat 源码
│ ├── demo/ # 示例工程
│ └── uikit/ # TUIChatKit 组件库
├── Podfile # 依赖配置文件
├── YourApplication.xcworkspace # 您的项目文件
说明:
TUIKit_iOS 是包含多个产品的开源仓库,Chat 的 UI 源码位于 chat/ 目录下(chat/uikit 为 UIKit 组件库,chat/demo 为示例工程),其依赖的音视频通话组件 call/TUICallKit_Swift 位于仓库根目录。模块目录可放在工程任意位置,只需在 Podfile 中设置正确的相对路径即可。

集成组件

1. 在 Podfile 中引入对应模块(请按源码实际存放位置调整相对路径):
# 请使用您的真实项目名称替换 your_project_name
target 'your_project_name' do
# 补充如下内容 增加 TUIChatKit 和 TUICallKit_Swift 这两个依赖
# 注意 path 的相对路径
pod 'TUIChatKit', :path => 'chat/uikit/TUIChatKit.podspec'
pod 'TUICallKit_Swift', :path => 'call/TUICallKit_Swift.podspec'
end

2. Podfile 修改完毕后,执行以下命令,安装 TUIKit 组件。
pod install

# 如果无法安装 TUIKit 最新版本,执行以下命令更新本地的 CocoaPods 仓库列表。
# pod repo update
# pod update


接入步骤

完成上述集成后,参考以下步骤,您仅需几行代码即可在项目中快速搭建会话列表、聊天、联系人等核心界面。

步骤1:配置用户鉴权

即时通信 IM 控制台 根据 UserID 获取 UserSig,用于后续登录时的用户鉴权。


步骤2:用户登录

登录鉴权后才能正常使用组件的功能。调用 LoginStorelogin 接口,传入上文获取的 sdkAppID、userID、userSig 进行登录鉴权:
Swift
import AtomicXCore
import TUIChatKit
import UIKit

let yourSdkAppID: Int32 = 10_000_000_00 // 填写你的实际sdkAppID
let testUserID = "testUserID" // 你的测试用户ID
let userSig = "xxxxxxx" // 你的测试用户ID对应的 userSig (从IM 控制台获取,看上面的截图)

LoginStore.shared.login(sdkAppID: yourSdkAppID, userID: testUserID, userSig: userSig) { [weak self] result in
DispatchQueue.main.async {
switch result {
case .success:
// 登录成功后 显示会话列表
// self?.showConversationList()
case .failure(let error):
print("login failed: \\(error.code) \\(error.message)")
}
}
}
警告:
在正式的生产环境中,建议在您的服务端生成 UserSig,在需要时由 App 向业务服务器发起请求获取动态 UserSig 进行鉴权。详见 服务端生成 UserSig

步骤3:构建会话列表界面

登录成功后(步骤 2),即可展示会话列表。只需创建 ConversationsPage 对象,并将其 push 到导航控制器:
Swift
import AtomicXCore
import TUIChatKit
import UIKit

func showConversationList() {
let conversationsPage = ConversationsPage(onConversationClick: { [weak self] info in
// 点击会话列表中的某条会话后,进入对应的聊天页
// self?.showChat(info.conversation)
})
navigationController.pushViewController(conversationsPage, animated: true)
}
ConversationsPage 会自动从本地数据库加载最近会话。当用户点击某条会话时,ConversationsPage 会通过 onConversationClick 回调,把所选会话的信息传递给上层,您可以在该回调中创建并进入聊天页(见 步骤 4)。

步骤4:构建聊天界面

聊天页由 ChatPage 承载,负责消息的展示与收发。构造 ChatPage 时必须传入一个 ConversationInfo,用于指定要进入的会话。其中 conversationIDtype 是必填的关键字段,title 用于聊天页导航栏标题的初始展示。
Swift
import AtomicXCore
import TUIChatKit
import UIKit

// 进入单聊
let userID = "test_user"
var conversation = ConversationInfo(conversationID: ChatUtil.getC2CConversationID(userID))
conversation.type = .c2c
conversation.title = "与 \\(userID) 聊天"
showChat(conversation)

// 进入群聊
let groupID = "@TGS#xxxxxx"
var groupConversation = ConversationInfo(conversationID: ChatUtil.getGroupConversationID(groupID))
groupConversation.type = .group
groupConversation.title = "测试群"
showChat(groupConversation)

func showChat(_ info: ConversationInfo) {
let chatPage = ChatPage(conversation: info, onBack: { [weak self] in
self?.navigationController.popViewController(animated: true)
})
navigationController.pushViewController(chatPage, animated: true)
}
注意:
在聊天界面使用 相册/录像/视频通话等需要声明对应的权限,请在 App 的 Info.plist 中声明如下权限:
<key>NSCameraUsageDescription</key>
<string>需要访问您的相机权限,开启后才能发送图片或视频</string>
<key>NSMicrophoneUsageDescription</key>
<string>需要访问您的麦克风权限,开启后才能发送语音</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>需要访问您的相册权限,开启后保存图片或视频</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>需要访问您的相册权限,开启后才能发送图片或视频</string>

步骤5:构建联系人界面

联系人页由 ContactsPage 承载,展示当前用户的好友列表(按字母索引分组)与群列表入口 等。页面自带导航栏,右上角的 +按钮内置了添加好友加入群聊两个功能入口。
Swift
import AtomicXCore
import TUIChatKit
import UIKit

func showContacts() {
let contactsPage = ContactsPage(
onContactClick: { [weak self] contact in
// 点击好友列表中的某个联系人回调(ContactInfo),可在该回调中进入单聊
// self?.showChat(with: contact.userID, title: contact.nickname ?? contact.userID)
},
onGroupClick: { [weak self] group in
// 点击群列表中的某个群的回调(GroupInfo),可在该回调中进入群聊
// self?.showGroupChat(with: group.groupID, title: group.groupName)
}
)
navigationController.pushViewController(contactsPage, animated: true)
}

步骤 6:音视频通话

音视频通话能力由 TUICallKit_Swift 组件提供(Podfile 中需添加 pod 'TUICallKit_Swift')。
1. 开通音视频通话服务,请参考 开通音视频服务。
2. 登录成功后初始化通话引擎。
LoginStore 登录只建立了消息通道,在登录成功后,通话引擎需单独初始化:
Swift

import RTCRoomEngine
import TUICallKit_Swift

func initCallEngine() {
let youSdkAppID: Int32 = 10_000_000_00 // 填写你的实际sdkAppID
let testUserID = "testUserID" // 你的测试用户ID
let userSig = "xxxxxxx" // 你的测试用户ID对应的 userSig (从IM 控制台获取,看上面的截图)

TUICallEngine.createInstance().`init`(youSdkAppID, userId: testUserID, userSig: userSig) {
// enableIncomingBanner(true) 用于开启被叫时的来电横幅通知
TUICallKit.createInstance().enableIncomingBanner(enable: true)
} fail: { code, message in
print("initCallEngine failed: \\(code), \\(message ?? "")")
}
}

3. 发起通话。
Swift
func startVideoCall() {
TUICallKit.createInstance().calls(
userIdList: ["liu100"], // 被叫用户 ID 列表。单人通话传一个元素;传多个则为群组通话
mediaType: .video, // 通话类型:.video 视频通话、.audio 语音通话
params: nil,
completion: nil
)
}
调用后 TUICallKit 会自动弹出全屏通话界面(含呼叫等待、接通、挂断全流程 UI),无需自行实现。
4. 如何移除音视频通话功能?
ChatPage 默认集成了音视频通话功能,如果你不需要音视频通话功能。可以在 步骤 4 创建聊天界面 中关闭音视频通话开关,代码如下所示:
Swift
func showChat(_ info: ConversationInfo) {
// 在输入配置中关闭输入面板中的视频通话和音频通话功能
let inputConfig = ChatMessageInputConfig(isShowVideoCall: false, isShowAudioCall: false)
let chatPage = ChatPage(conversation: info, messageInputConfig: inputConfig, onBack: { [weak self] in
self?.navigationController.popViewController(animated: true)
})
navigationController.pushViewController(chatPage, animated: true)
}

AI 助手:知识咨询与代码集成

在接入 IM SDK 过程中,您可以通过 MCP 使用 AI 助手,快速完成知识咨询、报错排查和 UIKit 集成代码生成。支持 Web/Android/iOS/Flutter/uni-app 等平台,答案基于官方文档。适用于查询 SDK API、UI 组件用法、服务端 API 与 IM 产品配置等场景,立即体验,提出您的第一个问题

常见问题

音视频常见问题

TUICallKit 和自己集成的音视频库冲突了?

腾讯云的音视频库不能同时集成,可能存在符号冲突,可以按照下面的场景处理。
1. 如果您使用了 TXLiteAVSDK_TRTC 库,不会发生符号冲突。可直接在 Podfile 文件中添加依赖,
pod 'TUICallKit_Swift'
2. 如果您使用了 TXLiteAVSDK_Professional 库,会产生符号冲突。您可在 Podfile 文件中添加依赖,
pod 'TUICallKit_Swift/Professional'
3. 如果您使用了 TXLiteAVSDK_Enterprise 库,会产生符号冲突。建议升级到 TXLiteAVSDK_Professional 后使用 TUICallKit_Swift/Professional。

通话邀请的超时时间默认是多久?

通话邀请的默认超时时间是 30 秒。

在邀请超时时间内,被邀请者如果离线再上线,能否立即收到邀请?

如果是单聊通话邀请,被邀请者离线再上线可以收到通话邀请,TUIKit 内部会自动唤起通话邀请界面。
如果是群聊通话邀请,被邀请者离线再上线后会自动拉取最近 30 秒内的邀请,TUIKit 会自动唤起群通话界面。

如何移除音视频通话功能?

ChatPage 默认集成了音视频通话功能,如果你不需要音视频通话功能。可以在 步骤 3 创建聊天界面 中关闭音视频通话开关,代码如下所示:
Swift
func showChat(_ info: ConversationInfo) {
// 在输入配置中关闭输入面板中的视频通话和音频通话功能
let inputConfig = ChatMessageInputConfig(isShowVideoCall: false, isShowAudioCall: false)
let chatPage = ChatPage(conversation: info, messageInputConfig: inputConfig, onBack: { [weak self] in
self?.navigationController.popViewController(animated: true)
})
navigationController.pushViewController(chatPage, animated: true)
}

上架常见问题

上架 App Store 时打包失败,提示 Unsupported Architectures?

问题现象如下图,打包时提示 ImSDK_Plus.framework 中包含了 App Store 不支持的 x86_64 模拟器版本。该问题是由于 IMSDK 为了方便开发者调试,发布时会默认带上模拟器版本。



您可以按照下面的步骤,在打包时去掉模拟器版本:
1. 选中您工程的 Target,并点击 Build Phases 选项,在当前面板中添加 Run Script;

2. 在新增的 Run Script 中,添加如下脚本:
#!/bin/sh

# Strip invalid architectures
strip_invalid_archs() {
binary="$1"
echo "current binary ${binary}"
# Get architectures for current file
archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
stripped=""
for arch in $archs; do
if ! [[ "${ARCHS}" == *"$arch"* ]]; then
if [ -f "$binary" ]; then
# Strip non-valid architectures in-place
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
stripped="$stripped $arch"
fi
fi
done
if [[ "$stripped" ]]; then
echo "Stripped $binary of architectures:$stripped"
fi
}

APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"

# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
strip_invalid_archs "$FRAMEWORK_EXECUTABLE_PATH"
done


Xcode 集成常见问题

[Xcodeproj] Unknown object version (60). (RuntimeError)


使用 Xcode 15 创建新工程来集成 TUIKit 时,输入 pod install 后,可能会遇到此问题,原因是使用了较旧版本的 CocoaPods ,此时有两种解决办法:
解决方式一: 修改 Xcode 工程的 Project Format 版本。

解决方式二: 升级本地的 CocoaPods 版本,升级方式本文不再赘述。
您可以在终端输入 pod --version 查看当前的 Pods 版本。

-ld64链接器问题?

Assertion failed: (false && "compact unwind compressed function offset doesn't fit in 24 bits"), function operator(), file Layout.cpp,

或是使用 Xcode 15 集成 TUIRoom 时,因最新链接器导致 TUIRoomEngine 的符号冲突,都属于该问题。

解决方式是:修改链接器配置
Build Settings 中的 Other Linker Flags 中添加"-ld64",即可解决。 参考资料: https://developer.apple.com/forums/thread/735426


Rosetta 模拟器问题?

使用苹果芯片(M1\\M2等系列芯片)时会遇到, 原因是包括 SDWebImage 在内的三方库,并未支持 xcframework,不过苹果依旧给出了适配办法,就是在模拟器上开启 Rosetta 设置, 一般情况下编译时会自动弹出 Rosetta 选项。


Xcode 15 开发者沙盒选项问题?

Sandbox: bash(xxx) deny(1) file-write-create

当您使用 Xcode 15 创建一个新工程时, 可能会因为此选项导致编译运行失败,建议您关闭此选项。


Xcode 16 不支持 Framework 开启 bitcode 问题?

解决方案1:升级 SDK
如果您使用的是包含 Bitcode 的旧版本 SDK(例如 TXIMSDK_iOS),建议您按照本文档的指引,将 SDK 升级至 TXIMSDK_Plus_iOS_XCFramework。
解决方式2: 修改 Podfile 配置
在您的 Podfile 末尾新增如下配置,重新 Pod install。
post_install do |installer|
bitcode_strip_path = 'xcrun --find bitcode_strip'.chop!
def strip_bitcode_from_framework(bitcode_strip_path, framework_relative_path)
framework_path = File.join(Dir.pwd, framework_relative_path)
command = "#{bitcode_strip_path} #{framework_path} -r -o #{framework_path}"
puts "Stripping bitcode: #{command}"
system(command)
end
framework_paths = [
"/Pods/TXIMSDK_iOS/ImSDK.framework/ImSDK",
]
framework_paths.each do |framework_relative_path|
strip_bitcode_from_framework(bitcode_strip_path, framework_relative_path)
end
end

CocoaPods 集成常见问题

若您执行 pod install,出现 Podfile.lock 和 插件依赖的版本不一致时,
此时请删除 Podfile.lock 文件, 并使用 pod repo update 更新本地代码仓库, 之后使用 pod update 重新更新即可。

其他常见问题

表情包的使用

为了尊重版权,IM Demo/TUIKit 工程中默认不包含大表情元素切图。正式上线商用前请您替换为自己设计或拥有版权的其他表情包。下图所示默认的小黄脸表情包版权归腾讯云所有,可有偿授权使用,如需获得授权,您可以通过升级至 IM 企业版套餐 免费使用该表情包。




联系我们

如果您在接入或使用过程中有任何疑问或者建议,欢迎 联系我们 提交反馈。