tencent cloud

即时通信 IM

iOS(SwiftUI)

下载
聚焦模式
字号
最后更新时间: 2026-06-03 17:49:47
本文会引导您在 TUIKit SwiftUI 上实现搜索。
注意:
“本地搜索”为 Chat 专业版、专业版 Plus、企业版功能,购买专业版、专业版 Plus 或企业版 后可使用。

开发环境要求

Xcode 15 及以上
iOS 15.0 及以上

前置条件

在构建界面之前,请确保您已经完成了以下 4 件事:
1. 在控制台创建了一个应用。
2. 在控制台创建了至少 2 个用户账号。
3. 集成了 TUIKit SwiftUI
4. 调用 LoginStorelogin 接口登录组件。
注意:
1. 每次启动应用,登录一次即可。
2. 请确保登录成功,我们建议您在登录成功的回调里进行下文的操作。
如果您尚未完成以上 4 步,请先参考 快速开始 中的对应步骤完成。

步骤说明

本地搜索界面由 Search 组件实现。建议在体验搜索功能前,本地制造一些业务数据,例如联系人、消息、群聊,否则搜不到任何信息。
注意,如果直接使用示例代码,需要预填充以下参数:
sdkAppID,上文获取的 sdkAppID。
userID,操作者的 userID,也就是 快速开始 中创建的 user1。
userSig,操作者的 userSig,也就是 快速开始 中创建的 user1 的 userSig。
App 启动即加载搜索入口 SearchBar,点击 SearchBar 输入搜索词触发搜索,示例代码如下:
// ContentView.swift
import SwiftUI

struct ContentView: View {
var body: some View {
SearchPage()
}
}

// SearchPage.swift
import AtomicX
import AtomicXCore
import SwiftUI

public struct SearchPage: View {
@StateObject private var themeState = ThemeState.shared
@State private var isLoggedIn = false
@State private var isLoggingIn = true
@State private var loginError: String? = nil

private let sdkAppID: Int32 = 1234567890 // TODO: Fill in the sdkAppID here
private let userID = "" // TODO: Fill in your userID here
private let userSig = "" // TODO: Fill in your generated userSig here

public var body: some View {
Group {
if isLoggedIn {
searchContentView
} else if isLoggingIn {
ProgressView("Logging in...")
} else {
VStack(spacing: 12) {
Image(systemName: "exclamationmark.triangle")
.font(.system(size: 40))
.foregroundColor(.orange)
Text(loginError ?? "Login failed")
.foregroundColor(.secondary)
}
}
}
.environmentObject(themeState)
.onAppear {
login()
}
}

// MARK: - Search Content

private var searchContentView: some View {
VStack(spacing: 0) {
navigationBarView

Divider()
.background(.gray)

// Add SearchBar to this page.
SearchBar(onTapItem: { result in
handleSearchResult(result)
})
.padding(.vertical, 8)

Spacer()
}
.background(themeState.colors.bgColorOperate.ignoresSafeArea(edges: .top))
}

// MARK: - Navigation Bar

private var navigationBarView: some View {
HStack {
Image(systemName: "magnifyingglass")
.font(.system(size: 24))
.foregroundColor(.gray)
Text("Search")
.font(.system(size: 17, weight: .semibold))
.foregroundColor(themeState.colors.textColorPrimary)
Spacer()
}
.padding(.horizontal, 16)
.frame(height: 44)
}

// MARK: - Handle Search Result

private func handleSearchResult(_ result: Any) {
if let friendInfo = result as? FriendSearchInfo {
// Handle friend search result
let conversationID = ChatUtil.getC2CConversationID(friendInfo.userID)
print(">>>>> Search result - Friend: \\(friendInfo.userID), conversationID: \\(conversationID)")
} else if let groupInfo = result as? GroupSearchInfo {
// Handle group search result
let conversationID = ChatUtil.getGroupConversationID(groupInfo.groupID)
print(">>>>> Search result - Group: \\(groupInfo.groupID), conversationID: \\(conversationID)")
} else if let messageDict = result as? [String: Any],
let messageInfo = messageDict["message"] as? MessageInfo,
let conversationID = messageDict["conversationID"] as? String
{
// Handle message search result (from search detail view)
let conversationName = messageDict["conversationName"] as? String ?? "Unknown"
print(">>>>> Search result - Message in \\(conversationName), conversationID: \\(conversationID), messageID: \\(messageInfo.id)")
} else if let conversationDict = result as? [String: Any],
let conversationID = conversationDict["conversationID"] as? String
{
// Handle conversation search result (from detail view)
let conversationName = conversationDict["conversationName"] as? String ?? "Unknown"
print(">>>>> Search result - Conversation: \\(conversationName), conversationID: \\(conversationID)")
} else {
print(">>>>> Search result - Unknown type: \\(result)")
}
}

// MARK: - Login

private func login() {
guard !userSig.isEmpty else {
isLoggingIn = false
loginError = "userSig is empty. Please fill in a valid userSig."
return
}
// Login is required when page appears.
LoginStore.shared.login(sdkAppID: sdkAppID, userID: userID, userSig: userSig) { result in
switch result {
case .success:
print(">>>>> SearchPage login success, userID: \\(userID)")
isLoggedIn = true
isLoggingIn = false
case .failure(let error):
print(">>>>> SearchPage login failed: \\(error.code), \\(error.message)")
loginError = "Login failed: \\(error.code), \\(error.message)"
isLoggingIn = false
}
}
}
}

运行效果如下:

注意:
上述示例代码中的 SearchPage 中的 handleSearchResult 目前仅打印搜索结果信息。实际使用时,您需要在此处实现页面跳转逻辑:根据搜索结果的类型(好友、群组、消息或会话),跳转到对应的聊天页面。如果搜索结果是消息类型,还可以在进入聊天页后自动定位到该条消息。

常见问题

如何搜索富媒体消息?

富媒体消息包含文件、图片、语音、视频消息。
对于文件消息,界面通常显示文件名,因此创建时可以设置 fileName 参数,作为被搜索的内容,如果 fileName 不设置则会从 filePath 提取文件名,并保存到本地和服务器。
而对于图片、语音、视频消息,界面通常显示缩略图或时长,可以指定消息类型做分类搜索,但不能通过关键字搜索。

帮助和支持

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

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

文档反馈