Component | Description |
Conversation list component | |
Core chat component | |
Friend adding component and group joining component | |
Blocklist component and new contact request list component | |
Contacts component and group list component | |
User profile component and group profile component | |
Global search component and in-conversation search component |
Environment | Version |
Flutter | Flutter 3.0.0 or later and Dart 2.17.0. |
Android | Android Studio Dolphin | 2021.3.1 or later and Android Gradle plugin 4.1.0 or later. |
iOS | Xcode 12.0 or later. Ensure that your project has a valid developer signature. |
Platform | Supported or Not |
iOS | Supported |
Android | Supported |
Web | Supported from v0.1.5 |
macOS | Supported from v2.0.0 |
Windows | Supported from v2.0.0 |
Hybrid development (Adding the SDK for Flutter to your existing native app) | Supported from v1.0.0 |
SDKAppID
.UserID
values and their UserSig
values, and copy the UserID
, Key
, and UserSig
for subsequent logins.
android/app/src/main/AndroidManifest.xml
and add the following permissions in <manifest></manifest>
:<uses-permissionandroid:name="android.permission.INTERNET"/><uses-permissionandroid:name="android.permission.RECORD_AUDIO"/><uses-permissionandroid:name="android.permission.FOREGROUND_SERVICE"/><uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE"/><uses-permissionandroid:name="android.permission.VIBRATE"/><uses-permissionandroid:name="android.permission.ACCESS_BACKGROUND_LOCATION"/><uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/><uses-permissionandroid:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permissionandroid:name="android.permission.CAMERA"/><uses-permissionandroid:name="android.permission.READ_MEDIA_IMAGES"/><uses-permissionandroid:name="android.permission.READ_MEDIA_VIDEO"/>
ios/Podfile
and add the following permission code at the end of the file:post_install do |installer|installer.pods_project.targets.each do |target|flutter_additional_ios_build_settings(target)target.build_configurations.each do |config|config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64'config.build_settings['ENABLE_BITCODE'] = 'NO'config.build_settings["ONLY_ACTIVE_ARCH"] = "NO"endtarget.build_configurations.each do |config|config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)','PERMISSION_MICROPHONE=1','PERMISSION_CAMERA=1','PERMISSION_PHOTOS=1',]endendend
tencent_cloud_chat_uikit
.flutter pub add tencent_cloud_chat_uikit
TIMUIKitCore.getInstance()
first and then call the initialization function init()
. Remember to pass in your sdkAppID
.onTUIKitCallbackListener
instance. For more information, see here./// main.dartimport 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';final CoreServicesImpl _coreInstance = TIMUIKitCore.getInstance();@overridevoid initState() {_coreInstance.init(sdkAppID: 0, // Replace 0 with the SDKAppID of your Chat application when integrating// language: LanguageEnum.en, // Configure the UI language; otherwise, the system language will be used.loglevel: LogLevelEnum.V2TIM_LOG_DEBUG,onTUIKitCallbackListener: (TIMCallback callbackValue){}, // [Configure a listener]. For details, see [here](https://www.tencentcloud.com/document/product/1047/50054#onTUIKitCallbackListener).listener: V2TimSDKListener());super.initState();}}
_coreInstance.login
method to log in with the test account.import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';final CoreServicesImpl _coreInstance = TIMUIKitCore.getInstance();_coreInstance.login(userID: userID, userSig: userSig);
UserSig
distribution method is to use the server to generate UserSig
and provide an application-oriented API. When UserSig
is needed, your application can send a request to the business server for a dynamic UserSig
. For more information, see Generating UserSig.Conversation
class and use the TIMUIKitConversation
component in the body
to render the conversation list.onTapItem
event processing function to redirect users to the specific chat page. The Chat
class is as detailed in the next step.import 'package:flutter/material.dart';import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';class Conversation extends StatelessWidget {const Conversation({Key? key}) : super(key: key);@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("Message",style: TextStyle(color: Colors.black),),),body: TIMUIKitConversation(onTapItem: (selectedConv) {Navigator.push(context,MaterialPageRoute(builder: (context) => Chat(selectedConversation: selectedConv,),));},),);}}
onTapAvatar
event processing function to redirect users to the profile details page. The UserProfile
class is as detailed in the next step.import 'package:flutter/material.dart';import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';class Chat extends StatelessWidget {final V2TimConversation selectedConversation;const Chat({Key? key, required this.selectedConversation}) : super(key: key);String? _getConvID() {return selectedConversation.type == 1? selectedConversation.userID: selectedConversation.groupID;}@overrideWidget build(BuildContext context) {return TIMUIKitChat(conversation: selectedConversation,onTapAvatar: (_) {// To adapt to desktop clients, modify the code here by referring to the Demo code.Navigator.push(context,MaterialPageRoute(builder: (context) => UserProfile(userID: userID),));}, // Callback for the clicking of the message sender profile photo. This callback can be used with `TIMUIKitProfile`.);}
V2TimConversation selectedConversation
conversation object in the code above won’t be obtained automatically. In such cases, you can add a V2TimConversation
object instance and pass in to the TIMUIKitChat
component.TIMUIKitChat(conversation: V2TimConversation(conversationID: "c2c_10040818", // One-to-one chat: "c2c_${userID of the receiver}"; Group chat: "group_${groupID}"userID: "", // userID of the receiver. Required only for one-to-one chatgroupID: "", // groupID of the group. Required only for group chatshowName: "", // Title displayed on top AppBartype: 1, // 1 for one-to-one chat and 2 for group chat// The above configurations are simplified and necessary. You can configure more parameters here based on the notes for `V2TimConversation`.),// ... Other `TIMUIKitChat` configuration parameters);
userID
is passed in.UserProfile
class and use the TIMUIKitProfile
component in the body
to render the user details and relationship chain page.profileWidgetBuilder
to pass in the profile component to be customized and use profileWidgetsOrder
to determine the vertical display order. If the requirements cannot be met, use builder
instead.import 'package:flutter/material.dart';import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';class UserProfile extends StatelessWidget {final String userID;const UserProfile({required this.userID, Key? key}) : super(key: key);@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text("Message",style: TextStyle(color: Colors.black),),),body: TIMUIKitProfile(userID: widget.userID,),);}}
context
is only required when the code is executed for the first time after the application is launched.import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';final bool isAndroid = PlatformUtils().isAndroid; // Determine whether it is an Android device.final bool isWeb = PlatformUtils().isWeb; // Determine whether it is a webpage.final bool isIOS = PlatformUtils().isIOS; // Determine whether it is an iOS device.final bool isWindows = PlatformUtils().isWindows; // Determine whether it is a Windows desktop.final bool isMacOS = PlatformUtils().isMacOS; // Determine whether it is a macOS desktop.final bool isMobile = PlatformUtils().isMobile; // Determine whether it is a mobile application, including both Android and iOS devices.final bool isDesktop = PlatformUtils().isDesktop; // Determine whether it is a desktop application, including both Windows and macOS devices.
Scaffold
and AppBar
on mobile clients, while on desktop, just a Modal
pop-up is needed. To address this, we’ve developed a general method TUIKitScreenUtils.getDeviceWidget()
, which allows you to pass in mobile and desktop components and automatically return the corresponding components based on the platform type.TUIKitScreenUtils.getDeviceWidget(desktopWidget: Container(), // Widget for desktop clientdefaultWidget: Container(), // Default widget, which is required. Use this when there is no corresponding platform widget passed in.mobileWidget: Container(), // Widget for mobile client);
Scaffold
and AppBar
on mobile clients, but not on desktop. You can remove some core components and use this method to add a Scaffold
framework for mobile clients while desktop does not need this framework. Sample code:@overrideWidgetbuild(BuildContext context) {Widget widgetBody() {return const TIMUIKitBlackList(); // Replace this with the actual widget to be displayed}return TUIKitScreenUtils.getDeviceWidget(desktopWidget: widgetBody(), // Display component directly on desktop clientsdefaultWidget: Scaffold( // Use this defaultWidget and add a Scaffold for mobile clients unless special casesappBar: AppBar(),body: widgetBody(),));}
TIMUIKitChat
, all the components do not contain Scaffold
or AppBar
.Scaffold
and AppBar
based on your own business needs, listen for exposed click events and other redirection events, and process Navigator.push()
redirection.onTapItem
of the TIMUIKitConversation
conversation list component to redirect end users to the specific chat page.TIMUIKitConversation(onTapItem: (selectedConv) {Navigator.push(context,MaterialPageRoute(builder: (context) => Chat(selectedConversation: selectedConv,),));});
Scaffold
and AppBar
for the primary component classes implemented by .dart files based on your business needs. Since the logic of the top AppBar
of TIMUIKitChat
is complicated (such as displaying Typing and unread message count), TIMUIKitChat
contains Scaffold
and AppBar
, while other primary components do not.Scaffold
and AppBar
, for example, the group management page component. This is because their navigation logic is processed within the component and their module is relatively independent.AppBar
in secondary or deeper-level components, you can modify UI themes to customize AppBar color and style by configuring parameters such as appbarBgColor
, appbarTextColor
, chatHeaderBgColor
and chatHeaderTitleTextColor
.Navigator.push()
to switch among different components and pages, the desktop client is not suitable for frequent navigation.Tab Icon on the Left | Module Content on the Right |
Chat | Conversation list + specific chat page + contact information + group information |
Contacts | (Contacts or group list) + (Contact details or group details) |
Me/My account | Settings or personal profile settings |
Profile photo | Personal profile settings |
index
to determine the current tab, place a LeftBar on the left to switch tabs, and place an IndexedStack
expanded by Expand
on the right to display core page content.Expand(IndexedStack)
section in the figure.dart
file to place ConversationAndChat
Widget class, which is used to support the business logic.ConversationAndChat
Widget class can introduce the Chat
, Conversation
and UserProfile
components created in above steps and keep the class code for the primary components basically unchanged.ConstrainedBox
on the left to restrict the width of the Conversation
component, and uses Expand
to expand and place the Chat
component. In addition, you can float a UserProfile
or GroupProfile
component on the far right using AnimatedPositioned
animation with Stack
for position changing. This allows your users to enter user profile or group profile page when clicked and return to the panel afterward.ConversationAndChat
class needs to contain states to record the current V2TimConversation? currentConversation
conversation.onConversationChanged
for the Conversation
Widget class created in step 3, as shown in this Demo code. This is used to redirect the conversation clicked by end users to the corresponding chat page.onConversationChanged
event, record the conversation currently switched to by the setState
method, and pass in the Chat
component to change the chat displayed on the right.dart
file for the code of this part and create a ContactsAndProfile
Widget class to support its business logic.ConstrainedBox
and Expand
. Place Contact
, GroupList
and other list components on the left-side ConstrainedBox
and place UserProfile
, GroupProfile
and other profile components on the right-side Expand
.onClickSendMessage
method to the UserProfile
component created in above steps for implementation of triggering event when end users click this custom button. For more information on how to configure this, see Demo codeonNavigateToChat
method for the ContactsAndProfile
to forward the listened onClickSendMessage
event. For demo code, see here.ContactsAndProfile
component in the home_page.dart, listen for the event, and forward this event to the ConversationAndChat
Widget. For demo code, see here.didUpdateWidget
to dynamically update the passed-in V2TimConversation
conversation to update the current chat page and the conversation list. For demo code, see here.directToChat
method to the previously created Chat
Widget to allow other components or modules to specify current chat page. For demo code, see heredirectToChat
method to the Conversation
component class to update the style of a conversation specified by other components and modules. The background color of the selected conversation is blue by default, unselected is white and the pinned is gray. For demo code, see here.showPopupWindow
. For more custom configurations, such as display position, see the notes of the method.import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';TUIKitWidePopup.showPopupWindow(context: context,title: Modal name,operationKey: TUIKitWideModalOperationKey.custom,width: MediaQuery.of(context).size.width * 0.4, // Widthheight: MediaQuery.of(context).size.width * 0.5, //Heightchild: (onClose) => The specific internal component for display(groupID: groupID,controller: _chatController,onClosed: onClose,),);
showDesktopModalFunc
method of TIMUIKitConfig
and build your own pop-ups based on provided parameters (such as, onclick event callbacks, current operation type operationKey
or position).operationKey
field will indicate the scenario for current pop-up display. You can determine the pop-up type based on operationKey
: return true
to display a custom pop-up and return false
to display a TUIKit default Modal pop-up.TUIKitWidePopup.showSecondaryConfirmDialog()
method to build the confirmation pop-ups. Parameters and configurations can be found in the notes.TUIKitWidePopup.showPopupWindow()
:TUIKitColumnMenu
menu list component, where each menu item is a ColumnMenuItem
component that can define the displayed label
text, icon
on the left and click event. closeFunc
method is also provided to close the right-click menu at the end of the click event.InkWell
. Listen on onTapDown
to obtain TapDownDetails
event and click position of the mouse, and then pass in the position. You can also consider boundary based on the menu placement to avoid the menu going out of the bounds and determine the offset position by using the min
method and MediaQuery.of(context).size
parameter.return InkWell(onTapDown: (details){TUIKitWidePopup.showPopupWindow(isDarkBackground: false,operationKey: TUIKitWideModalOperationKey.custom,borderRadius: const BorderRadius.all(Radius.circular(4)),context: context,// Calculate the offset value below based on actual situation and details.offset: Offset(details.globalPosition.dx + 10, details.globalPosition.dy - 200),child: (closeFunc) => TUIKitColumnMenu(data: [ColumnMenuItem(label: TIM_t("Personal center"), onClick: (){// Click event defined by youcloseFunc();}),ColumnMenuItem(label: TIM_t("Personal center"), onClick: (){// Click event defined by youcloseFunc();}),],));},child: Container(),);
TIMUIKitProfile
.TIMUIKitUnreadCount
badge component, which can mount listeners automatically.TIMUIKitSearch
is a global search component, which supports the global search of contacts, groups, and chat records. You can also use TIMUIKitSearchMsgDetail
to search for chat records in a specific conversation. You can choose whether to pass in conversation
to choose between the two search modes.tencent_cloud_chat_uikit
0.1.5 or later.Component | Controller | Feature |
Refreshes the historical message list/Updates a single message/Sends additional messages/Sets custom fields for messages, etc. | ||
Gets and refreshes the conversation list/Pins a conversation to the top/Sets a conversation draft/Clears all messages in a conversation/Deletes a conversation/Navigates to a specific conversation, etc. | ||
Deletes a contact/Pins the conversation with the current contact/Adds a user to the blocklist/Changes the way of being added as a friend/Updates the alias of a contact/Mutes notifications of messages of contacts/Adds a contact/Updates the user profile, etc. |
final TIMUIKitChatController _chatController = TIMUIKitChatController();
controller
parameter of TIMUIKitChat.@overrideWidget build(BuildContext context) {return TIMUIKitChat(controller: _chatController,// ... Other parameters);}
_sendLocationMessage(String desc, double longitude, double latitude) async {final locationMessageInfo = await sdkInstance.v2TIMMessageManager.createLocationMessage(desc: desc,longitude: longitude,latitude: latitude);final messageInfo = locationMessageInfo.data!.messageInfo;_chatController.sendMessage(receiverID: _getConvID(),groupID:_getConvID(),convType: _getConvType(),messageInfo: messageInfo);}
compileSdkVersion
is not compatible?pubspec.yaml
file of your project.video_thumbnail: ^0.5.3permission_handler: ^10.0.0flutter_local_notifications: 9.7.0
android/app/build.gradle
file to ensure android => compileSdkVersion 33
.android {compileSdkVersion 33...}
flutter pub cache cleanflutter pub get
--no-tree-shake-icons
to your compilation command, for example:flutter build apk --no-tree-shake-icons --dart-define=SDK_APPID={your `SDKAPPID`}
pod install
or flutter run
again.ios/Pods
folder and the ios/Podfile.lock
file and run the following command to reinstall the dependencies.cd iossudo gem install ffipod install --repo-update
flutter run
again.Flutter doctor
to detect whether the Flutter environment is ready.android\\app\\src\\main\\AndroidManifest.xml
and complete xmlns:tools="http://schemas.android.com/tools"
/ android:label="@string/android_label"
/ tools:replace="android:label"
as follows:<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="Replace it with your Android package name"xmlns:tools="http://schemas.android.com/tools"><applicationandroid:label="@string/android_label"tools:replace="android:label"android:icon="@mipmap/ic_launcher" // Specify an icon pathandroid:usesCleartextTraffic="true"android:requestLegacyExternalStorage="true">
android\\app\\build.gradle
and complete minSdkVersion
and targetSdkVersion
in defaultConfig
.defaultConfig {applicationId "" // Replace it with your Android package nameminSdkVersion 21targetSdkVersion 30}
onTUIKitCallbackListener
listener when initializing TUIKit.TIMCallbackType
.final CoreServicesImpl _coreInstance = TIMUIKitCore.getInstance();final isInitSuccess = await _coreInstance.init(onTUIKitCallbackListener: (TIMCallback callbackValue){switch(callbackValue.type) {case TIMCallbackType.INFO:// Shows the recommend text for info callback directlyUtils.toast(callbackValue.infoRecommendText!);break;case TIMCallbackType.API_ERROR://Prints the API error to console, and shows the error message.print("Error from TUIKit: ${callbackValue.errorMsg}, Code: ${callbackValue.errorCode}");if (callbackValue.errorCode == 10004 && callbackValue.errorMsg!.contains("not support @all")) {Utils.toast(imt("The current group does not support @all members"));}else{Utils.toast(callbackValue.errorMsg ?? callbackValue.errorCode.toString());}break;case TIMCallbackType.FLUTTER_ERROR:default:// prints the stack trace to console or shows the catch errorif(callbackValue.catchError != null){Utils.toast(callbackValue.catchError.toString());}else{print(callbackValue.stackTrace);}}},);
TIMCallbackType.API_ERROR
)errorMsg
and errorCode
are provided.TIMCallbackType.FLUTTER_ERROR
)stackTrace
(from FlutterError.onError
) or catchError
(from try-catch
) when the error occurred.TIMCallbackType.INFO
)infoCode
is provided to help you identify the current scenario and the default prompt infoRecommendText
.infoCode
. The prompt will be displayed in the system language or the specified language. Do not determine the scenario based on the prompt.infoCode
complies with the following rules:infoCode
consists of seven digits, the first five of which determine the component where the scenario occurred, and the last two of which determine the specific scenario.Start of `infoCode | Component |
66601 | TIMUIKitAddFriend |
66602 | TIMUIKitAddGroup |
66603 | TIMUIKitBlackList |
66604 | TIMUIKitChat |
66605 | TIMUIKitContact |
66606 | TIMUIKitConversation |
66607 | TIMUIKitGroup |
66608 | TIMUIKitGroupProfile |
66609 | TIMUIKitNewContact |
66610 | TIMUIKitGroupProfile |
66611 | TIMUIKitNewContact |
66612 | TIMUIKitProfile |
66613 | TIMUIKitSearch |
66614 | Common components |
infoCode
values is as follows:infoCode | infoRecommendText | Scenario Description |
6660101 | A friend request is sent successfully. | The user requests to add another user to the contacts. |
6660102 | The user is already a friend. | The onTapAlreadyFriendsItem callback is triggered when the user requests to add an existing friend. |
6660201 | A group join request is sent. | The user requests to join a group requiring admin approval. |
6660202 | You are already a group member. | The onTapExistGroup callback is triggered when the user sends a group join request and is identified as an existing group member. |
6660401 | The original message cannot be located. | The target message cannot be found in the message list when the user needs to be redirected to the @message or quote the message. |
6660402 | The video is saved successfully. | |The user selects Save after opening a video message in the message list. |
6660403 | The video failed to be saved. | The user selects Save after opening a video message in the message list. |
6660404 | The recording is too short. | The user sends a too short audio message. |
6660405 | Sending failed. The video cannot exceed 100 MB. | The user attempts to send a video greater than 100 MB in size. |
6660406 | The image is saved successfully. | The user selects Save after opening the large image in the message list. |
6660407 | The image failed to be saved. | The user selects Save after opening the large image in the message list. |
6660408 | Copied | The user selects Copy to copy the text message in the pop-up window. |
6660409 | Unavailable | The user selects a non-standard feature in the pop-up window. |
6660410 | Other files are being received. | The previous download tasks have not been completed when the user clicks to download a file message. |
6660411 | Receiving | The user clicks to download a file message. |
6660412 | Video messages must be in MP4 format. | The user sends a video message in non-MP4 format. |
6660414 | Downloading | [Desktop] The image or video is being downloaded and cannot be opened. Open it when it is downloaded. |
6660415 | Video file exception | Unable to send the file because the video file itself is wrong or damaged. |
6661002 | Unable to view group members due to network disconnection | The user attempts to modify the group profile in an environment without a network connection. |
6661003 | The admin role is canceled successfully. | The user cancels the admin role of another user in the group. |
6661201 | Modification failed due to network disconnection | The user attempts to modify their own profile or that of a contact in an environment without a network connection. |
6661202 | The friend is added successfully. | The user adds another user as a friend on the profile page, who is automatically added successfully without approval. |
6661203 | A friend request is sent. | The user adds another user who requires approval as a friend on the profile page. |
6661204 | The user is on the blocklist. | The user adds another user who is on the blocklist as a friend on the profile page. |
6661205 | The friend failed to be added. | The user failed to add a friend, possibly because the latter forbids being added. |
6661206 | The friend is deleted successfully. | The user successfully deleted a friend on the profile page. |
6661207 | The friend failed to be deleted. | The user failed to delete a friend on the profile page. |
6661401 | The input cannot be empty. | The user enters an empty string. |
6661402 | Pass in a lifecycle function for leaving a group to provide the navigation method to return to the homepage or another page. | A method to return to the homepage is provided when the user leaves or disbands the group. |
6661403 | The device's available storage space is insufficient. We recommend you free up some space to gain a better user experience. | After the user is logged in successfully, the system will automatically check the device's available storage space. If the available space is less than 1 GB, a prompt will be displayed indicating that the available space is insufficient. |
Was this page helpful?