Conversation List | Chat | Audio/Video Call |
![]() | ![]() | ![]() |
AtomicXCore and provide SwiftUI pages through TUIChatKit_Swift. You can directly use ConversationsPage, ChatPage, and ContactsPage without assembling the chat UI yourself.iOS Deployment Target to 15.0 or later, and keep it consistent with platform :ios in the Podfile.SDKAppID, UserID, and UserSig. See Activate the Service.git clone https://github.com/Tencent-RTC/TUIKit_iOS_SwiftUI.git
chat folder from the repository root to your project root directory. The directory structure after copying is as follows:YourApplication/├── source/ # Your project code├── chat/ # Chat source code│ ├── demo/ # Demo project│ ├── demo_mini/ # Minimal demo project│ └── uikit/ # TUIChatKit component library│ ├── TUIChatKit_Swift.podspec│ ├── components/ # UI components│ ├── page/ # Complete pages│ └── resources/ # Images and localization resources├── Podfile # Dependency configuration file├── YourApplication.xcworkspace # Your project file
TUIKit_iOS_SwiftUI is an open-source repository containing multiple products. The Chat UI source code is located in the chat/ directory (chat/uikit is the SwiftUI component library, and chat/demo is the demo project). Module directories can be placed anywhere in your project; just set the correct relative paths in the Podfile. When integrating into your own project, delete the demo and demo_mini directories.Podfile, adjusting the relative paths based on where the source code is located. The following assumes that the entire chat folder has been copied to the project root directory and that the Podfile is in the same project root directory.platform :ios, '15.0'# Replace YourApplication with your app target name. The dependency version range matches the current chat demo.target 'YourApplication' douse_frameworks! :linkage => :staticpod 'TUIChatKit_Swift', :path => './chat/uikit/TUIChatKit_Swift.podspec'pod 'AtomicXCore', '>= 4.3.10', '< 5.0'# Add this when you need audio/video calls# pod 'TUICallKit_Swift'end
pod install# If the latest TUIKit version cannot be installed, run the following commands to update the local CocoaPods repository list.# pod repo update# pod update
UserSig based on the UserID in Console > Development Tools > UserSig Tools. The UserSig is used for login authentication.
UserSig on your server and have your app request it from your business server. Do not write the SDKSecretKey into the client. For details, see Generating UserSig on the Server.login API of LoginStore and pass in the sdkAppID, userID, and userSig obtained above for login authentication. The code is as follows:import AtomicXCore// let yourSdkAppID: Int32 = 10_000_000_00 Replace with your actual SDKAppID// let testUserID = "testUserID" Replace with your test user ID// let userSig = "xxxxxxx" The UserSig of this user, obtained from the console in Step 1LoginStore.shared.login(sdkAppID: yourSdkAppID, userID: testUserID, userSig: userSig) { result inDispatchQueue.main.async {switch result {case .success:// Enter the conversation list UI, etc. (Step 3)case .failure(let error):print("login failed: \\(error.code) \\(error.message)")}}}
ConversationsPage to display the conversation list. When the user taps a conversation, onConversationClick returns a NavigationInfo, and you open the chat page in the callback:import SwiftUIimport AtomicXCoreimport TUIChatKit_Swift// Enter the conversation list pageNavigationLink(destination: ConversationsDestination())private struct ConversationsDestination: View {@State private var navigationInfo: NavigationInfo?@State private var showChat = falsevar body: some View {ConversationsPage(config: nil, // Conversation action configuration; nil uses the default configurationonConversationClick: { info in // Callback for opening a conversation; returns the conversation and an optional message to locatenavigationInfo = infoshowChat = true}).navigationBarHidden(true).background(chatNavigationLink)}// Respond to onConversationClick to enter the chat page. For the definition of ChatPageDestination, see Step 4: Build the Chat Interface@ViewBuilderprivate var chatNavigationLink: some View {if let info = navigationInfo {NavigationLink(destination: ChatPageDestination(conversation: info.conversation,locateMessage: info.locateMessage),isActive: $showChat) { EmptyView() }.hidden()}}}
ConversationInfo to specify the conversation to enter. conversationID and type are required key fields, and title is used as the initial title of the chat page's navigation bar. You can optionally pass in messageListConfig and messageInputConfig to configure the features and styles of the message list and message input modules.import SwiftUIimport AtomicXCoreimport TUIChatKit_Swift// Enter a one-to-one chatNavigationLink("Enter one-to-one chat",destination: ChatPageDestination(conversation: makeTestC2CConversationInfo(),locateMessage: nil))private func makeTestC2CConversationInfo() -> ConversationInfo {var conversation = ConversationInfo(conversationID: ChatUtil.getC2CConversationID('test2'))conversation.type = .c2cconversation.title = "Chat with \\(MiniTestAccount.c2cChatUserID)"return conversation}// Enter a group chatNavigationLink("Enter group chat",destination: ChatPageDestination(conversation: makeTestGroupConversationInfo(),locateMessage: nil))private func makeTestGroupConversationInfo() -> ConversationInfo {var conversation = ConversationInfo(conversationID: ChatUtil.getGroupConversationID('testGroup'))conversation.type = .groupconversation.title = "Test group: \\(MiniTestAccount.chatGroupID)"return conversation}private struct ChatPageDestination: View {@Environment(\\.dismiss) private var dismisslet conversation: ConversationInfovar locateMessage: MessageInfo? = nilvar body: some View {ChatPage(conversation: conversation, // Conversation informationlocateMessage: locateMessage, // Message to locate; nil means no message is locatedmessageListConfig: nil, // Message list configuration; nil uses the default configurationmessageInputConfig: nil, // Input configuration; nil uses the default configurationisShowMoreButton: false, // Whether to show the More button in the navigation barshowsNavigationBar: true, // Whether to show the SDK-drawn navigation bartopBannerView: nil, // Custom top banner; nil means no banneronBack: { dismiss() }, // Back button tap callbackonUserClick: nil, // User tap callback; returns the user IDonMoreClick: nil // Callback for tapping the navigation bar title or More button).navigationBarHidden(true)}}
<key>NSCameraUsageDescription</key><string>Camera access is required to send photos or videos</string><key>NSMicrophoneUsageDescription</key><string>Microphone access is required to send voice messages</string><key>NSPhotoLibraryAddUsageDescription</key><string>Photo library access is required to save photos or videos</string><key>NSPhotoLibraryUsageDescription</key><string>Photo library access is required to send photos or videos</string>
import SwiftUIimport AtomicXCoreimport TUIChatKit_Swiftprivate struct ContactsDestination: View {var body: some View {ContactsPage(config: nil, // Contact list configuration; nil uses the default configurationonContactClick: { item in // Contact tap callback; open the contact's information// openChat(makeC2CConversation(item))},onGroupClick: { item in // Group tap callback; open the group's information// openChat(makeGroupConversation(item))}).navigationBarTitleDisplayMode(.inline).navigationBarHidden(true)// .background(chatNavigationLink) // Attach a hidden navigation link used to open the chat page}}
LoginStore login only establishes the messaging channel. After login succeeds, the call engine needs to be initialized separately:import RTCRoomEngineimport TUICallKit_Swiftfunc initializeCall(sdkAppID: Int32, userID: String, userSig: String) {TUICallEngine.createInstance().`init`(sdkAppID, userId: userID, userSig: userSig) {TUICallKit.createInstance().enableIncomingBanner(enable: true)} fail: { code, message inprint("initCallEngine failed: \\(code) \\(message ?? "")")}}
import TUICallKit_Swiftfunc startVideoCall(userID: String) {TUICallKit.createInstance().calls(userIdList: [userID], // List of callee user IDs. Pass one element for a one-to-one call, or multiple elements for a group callmediaType: .video, // Call type: .video for a video call, .audio for a voice callparams: nil,completion: nil)}
import SwiftUIimport AtomicXCoreimport TUIChatKit_Swift// Build a messageInputConfig without audio/video calls. After this config is passed in, the More panel of the input view has no audio/video call entriesprivate func makeMessageInputConfig () -> ChatMessageInputConfig {var inputConfig = ChatMessageInputConfig()inputConfig.isShowVideoCall = false // Disable video callsinputConfig.isShowAudioCall = false // Disable audio callsreturn inputConfig}
chat/demo_mini. Page configuration parameters can be omitted or set to nil, in which case the component uses the default configuration. You only need to set the options you want to override.TUIChatKit_Swift to avoid mixing in UIKit APIs.TUIChatKit_Swift, so your source code should use import TUIChatKit_Swift. Make sure the path in the Podfile is correct, run pod install, and then open the .xcworkspace. The resource bundle ChatUIKitBundle does not need to be renamed..environmentObject(ThemeState.shared) into the root view and hide the system navigation bar. ChatPage.onBack is a callback for the back event, and you need to perform the back navigation yourself.SDKAppID, UserID, and UserSig match and whether the signature has expired. During development, regenerate a test signature. In production, check the parameters your server uses to generate the signature.フィードバック