Release Notes
Announcements
git clone https://github.com/Tencent-RTC/TUIKit_iOS_SwiftUI.git
atomic-x/├── Sources/ # UI component source code (required for integration)│ ├── MessageList/ # Message list component│ ├── MessageInput/ # Message input component│ ├── ConversationList/ # Conversation list component│ ├── ContactList/ # Contact list component│ ├── BaseComponent/ # Base components│ └── ... # Other UI components├── Resources/ # Resource files (required for integration)│ ├── assets/ # Image assets│ └── strings/ # Localization string fileschat/├── uikit/ # Page components (reference implementation)│ ├── ChatPage.swift│ ├── ContactsPage.swift│ └── ConversationsPage.swift└── demo/ # Demo application (optional reference)

pod 'AtomicX/Chat', :path => '../TUIKit_iOS_SwiftUI/atomic-x/AtomicX.podspec'pod 'AtomicX/Chat', :path => './TUIKit_iOS_SwiftUI/atomic-x/AtomicX.podspec'pod 'AtomicX/Chat', :path => '/TUIKit_iOS_SwiftUI/atomic-x/AtomicX.podspec'platform :ios, '14.0'target 'Demo' douse_frameworks! :linkage => :staticpod 'AtomicX/Chat', :path => './TUIKit_iOS_SwiftUI/atomic-x/AtomicX.podspec'pod 'ChatUIKit', :path => './TUIKit_iOS_SwiftUI/chat/uikit/ChatUIKit.podspec'pod 'AtomicXCore', '3.4.0'end#Pods configpost_install do |installer|installer.pods_project.targets.each do |target|target.build_configurations.each do |config|config.build_settings['SWIFT_VERSION'] = '5.0'#Do not strip Swift symbolsconfig.build_settings['STRIP_SWIFT_SYMBOLS'] = 'NO'config.build_settings['DEBUG_INFORMATION_FORMAT'] = 'dwarf-with-dsym'#Fix Xcode14 Bundle target errorconfig.build_settings['EXPANDED_CODE_SIGN_IDENTITY'] = ""config.build_settings['CODE_SIGNING_REQUIRED'] = "NO"config.build_settings['CODE_SIGNING_ALLOWED'] = "NO"config.build_settings['ENABLE_BITCODE'] = "NO"config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = "14.0"endendend
pod install
pod install command will automatically install all required dependencies:
<key>NSCameraUsageDescription</key><string>The app needs access to the camera to take photos and videos</string><key>NSMicrophoneUsageDescription</key><string>The app needs access to the microphone to record audio</string><key>NSPhotoLibraryUsageDescription</key><string>The app needs access to the photo library to select images and videos</string>

import AtomicXCore// User loginLoginStore.shared.login(sdkAppID: sdkAppID, userID: userID, userSig: userSig, completion: { [weak self] result inguard let self = self else { return }switch result {case .success:// Login successful, you can navigate to the chat or conversation pagecase .failure(let error):// Login failed, you can show an error dialog}})

chat/uikit/ConversationsPage.swift. The ConversationsPage does the following:import AtomicXimport AtomicXCoreimport SwiftUIpublic struct ConversationsPage: View {...public var body: some View {VStack(spacing: 0) {headerViewConversationList(onConversationClick: { conversation in// Customize onConversationClick eventonShowMessage?(NavigationInfo(conversation: conversation))}).environmentObject(themeState)}.onReceive(contactListStore.state.subscribe(StatePublisherSelector(keyPath: \\ContactListState.friendList))) { friendList inif self.friendList != friendList {self.friendList = friendList}}.onAppear {contactListStore.fetchFriendList(completion: { _ in })}.overlay(// Show this menu when "+" is tapped.ChatsMenuOverlay(showChatsMenu: $showChatsMenu,showStartConversation: $showStartConversation,showUserPicker: $showUserPicker))...}...}private var headerView: some View {HStack {Text(LocalizedChatString("TabChats")).font(.system(size: 34, weight: .semibold)).tracking(0.3).foregroundColor(themeState.colors.textColorPrimary).background(themeState.colors.listColorDefault).padding(.leading, 16)Spacer()if AppBuilderConfig.shared.enableCreateConversation {Button(action: {showChatsMenu.toggle()}) {Image(systemName: "plus").font(.system(size: 20)).foregroundColor(themeState.colors.buttonColorPrimaryDefault).frame(width: 28, height: 28).cornerRadius(14)}.padding(.trailing, 16)}}.padding(.top, 12).padding(.bottom, 16)}

chat/uikit/ChatPage.swift. The ChatPage does the following:import AtomicXimport AtomicXCoreimport SwiftUIpublic struct ChatPage: View {...public var body: some View {return VStack(spacing: 0) {self.navigationBarViewDivider().background(self.themeState.colors.strokeColorPrimary)VStack(spacing: 0) {MessageList(conversationID: self.conversation.id,listStyle: self.listStyle,locateMessage: self.locateMessage,onUserClick: { userID inonUserAvatarClick?(userID)})self.messageInputAreaView}.ignoresSafeArea(.keyboard)}.toast(toast)}// Headerprivate var navigationBarView: some View {HStack {Button(action: {onBack?()}) {Image(systemName: "chevron.left").font(.system(size: 18, weight: .semibold)).foregroundColor(themeState.colors.textColorLink)}.padding(.leading, 16)Button(action: {onNavigationAvatarClick?()}) {HStack(spacing: 12) {Avatar(url: conversation.avatarURL,name: conversation.title ?? conversation.conversationID,size: .s)VStack(alignment: .leading, spacing: 2) {Text(conversation.title ?? conversation.conversationID).font(.system(size: 17, weight: .semibold)).foregroundColor(themeState.colors.textColorPrimary).lineLimit(1)if conversation.type == .group {Text("Group Chat").font(.system(size: 12)).foregroundColor(themeState.colors.textColorSecondary)}}}}.buttonStyle(PlainButtonStyle())Spacer()}.frame(height: 44)}// MessageInputprivate var messageInputAreaView: some View {VStack(spacing: 0) {MessageInput(text: $messageText,conversationID: conversation.id,style: inputStyle,onHeightChange: { height inself.inputAreaHeight = height}).padding(.bottom, 8)}}...}

chat/uikit/ContactsPage.swift. The ContactsPage does the following:import AtomicXimport AtomicXCoreimport SwiftUIpublic struct ContactsPage: View {...public var body: some View {VStack(spacing: 0) {headerViewContactList(contactStore: contactStore,onShowMessage: onShowMessage,onContactClick: onContactClick,onGroupClick: onGroupClick,onNewFriendsClick: onNewFriendsClick,onGroupApplicationsClick: onGroupApplicationsClick,onGroupListClick: onGroupListClick,onBlackListClick: onBlackListClick)}.overlay(Group {if showAddContactMenu {VStack {HStack {Spacer()AddContactPopView(onDismiss: {showAddContactMenu = false},onShowAddFriend: {showAddFriend = true},onShowJoinGroup: {showJoinGroup = true}).padding(.trailing, 16).padding(.top, 50)}Spacer()}.background(Color.clear.contentShape(Rectangle()).onTapGesture {showAddContactMenu = false}).animation(.easeInOut(duration: 0.2), value: showAddContactMenu)}}).sheet(isPresented: $showAddFriend) {AddFriendView(contactStore: contactStore)}.sheet(isPresented: $showJoinGroup) {JoinGroupView(contactStore: contactStore)}}private var headerView: some View {HStack {Text(LocalizedChatString("TabContacts")).font(.system(size: 34, weight: .semibold)).tracking(0.3).foregroundColor(themeState.colors.textColorPrimary).padding(.leading, 16)Spacer()Button(action: {showAddContactMenu = true}) {Image(systemName: "plus").font(.system(size: 20)).foregroundColor(themeState.colors.buttonColorPrimaryDefault).frame(width: 28, height: 28).cornerRadius(14)}.padding(.trailing, 16)}.padding(.top, 12).padding(.bottom, 16)}...}
Page | Webhook | Recommended Navigation Logic |
ConversationsPage | onConversationClick: ((NavigationInfo) -> Void)? | Triggered when a conversation is tapped in the conversation list; recommended to navigate to the chat page (ChatPage). |
ContactPage | onContactClick: ((AZOrderedListItem) -> Void)? | Triggered when a contact cell is tapped; recommended to navigate to the contact detail page (C2CChatSetting). |
| onGroupClick: ((AZOrderedListItem) -> Void)? | Triggered when a group cell is tapped; recommended to navigate to the group chat page (ChatPage). |
ChatPage | onBack: (() -> Void)? | Triggered when the back button is tapped; recommended to return to the previous page. |
| onUserAvatarClick: ((String) -> Void)? | Triggered when a user avatar is tapped in a message; recommended to navigate to the user info page (C2CChatSetting). |
| onNavigationAvatarClick: (() -> Void)? | Triggered when the avatar in the navigation bar is tapped; recommended to navigate to the user info page (C2CChatSetting) or group info page (GroupChatSetting). |
// Navigate when a conversation list cell is tappedConversationsPage(onShowMessage: { navigationInfo inshowChatPage(conversation: navigationInfo.conversation, locateMessage: navigationInfo.locateMessage)})// Navigate from the contacts pageContactsPage(onContactClick: { user inshowContactDetail(user)},onGroupClick: { group inlet conversation = createConversationFromGroup(group)showChatPage(conversation: conversation)})// ChatNavPage wraps ChatPage with a navigation barChatNavPage(conversation: conversation,locateMessage: currentLocateMessage,onBack: {dismissChatPage()},onContactDelete: {dismissChatPage()},onGroupDelete: {dismissChatPage()},onNavigateToChat: { newConversation in// First dismiss current chat page, then navigate to the new chatdismissChatPage()DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {showChatPage(conversation: newConversation)}})
Was this page helpful?
You can also Contact sales or Submit a Ticket for help.
Help us improve! Rate your documentation experience in 5 mins.
Feedback