什么是 TUIKit
TUIKit 是基于 腾讯云 IM SDK 开发的一款即时通讯 UI 组件库,包括会话、聊天、搜索、关系链、群组、音视频通话等能力。通过 TUIKit,可快速集成包含 UI 界面的全平台即时通讯应用。
TUIKit 简化了基于 腾讯云 IM SDK 的应用开发过程。它不仅能助您快速实现 UI 功能,也支持调用 腾讯云 IM SDK 相应的接口实现即时通讯业务逻辑和数据处理。因此,您在使用 TUIKit 时仅需关注自身业务或个性化扩展。
概览
目前包含的一级组件如下:
组件名 | 组件功能 |
会话列表组件 | |
核心聊天组件 | |
添加好友组件/添加群组组件 | |
黑名单列表组件/新的联系人申请列表组件 | |
好友列表组件/群组列表组件 | |
用户信息组件/群组信息组件 | |
全局搜索组件/会话内搜索组件 |
准备步骤
环境要求
环境 | 版本 |
Flutter | 最低要求 Flutter 3.0.0 版本,Dart 2.17.0 版本。 |
Android | Android Studio Dolphin | 2021.3.1 及以上版本,Android Gradle plugin 4.1.0 以上版本。 |
iOS | Xcode 12.0 及以上版本,请确保您的项目已设置有效的开发者签名。 |
支持平台
TUIKit 拥有自适应 UI 界面,可同时用于 移动端 及 桌面端。并支持以下所有平台,针对不同平台有不同的特色能力。方便您一套代码开发全平台应用。
平台 | 支持状态 |
iOS | 支持 |
Android | 支持 |
Web | 支持,0.1.5版本起 |
macOS | 支持,2.0.0 版本起 |
Windows | 支持,2.0.0 版本起 |
混合开发 (将 Flutter SDK 添加至现有原生应用) | 1.0.0版本起支持 |
前提条件
2. 参照 创建并升级应用 创建应用,并记录好
SDKAppID
。3. 在 IM 控制台 选择您的应用,在左侧导航栏依次单击 开发辅助 > UserSig 生成&校验 ,创建两个 UserID 及其对应的 UserSig,复制
UserID
、签名(Key)
、UserSig
这三个,后续登录时会用到。说明:
该账户仅限开发测试使用。应用上线前,正确的
UserSig
签发方式是由服务器端生成,并提供面向 App 的接口,在需要 UserSig
时由 App 向业务服务器发起请求获取动态 UserSig
。更多详情请参见 服务端生成 UserSig。
接入步骤
如下会介绍如何使用 Flutter TUIKit 快速构建一个简单的即时通信应用。
步骤1:创建 Flutter 应用并添加权限
配置权限
由于 TUIKit 运行,需要拍摄/相册/录音/网络等权限,需要您在 Native 的文件中手动声明,才可正常使用相关能力。
Android
打开
android/app/src/main/AndroidManifest.xml
,在 <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
打开
ios/Podfile
,在文件末尾新增如下权限代码。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
说明:
安装 TUIKit
TUIKit 已经内置了 IM SDK,因此您只需要安装
tencent_cloud_chat_uikit
,而不需要再安装基础 IM SDK。TUIKit 已经开源,您可以引入在线版本,也可以在 GitHub 上 fork 后本地引入使用。在进行后续步骤之前,您可以通过我们的TUIKit介绍页或在线Demo体验来判断现有TUIKit默认样式和您预期的样式之间的差异。
如果差异不是特别大,建议您引入我们的在线版本,并使用组件开放的配置参数和builder进行微调。
flutter pub add tencent_cloud_chat_uikit
如果差异较大,我们更建议您fork一份我们的 TUIKit 源码,并直接修改fork后的版本,并将其引入您的项目中。如果需要更新至我们的最新版本,您可以使用 git upstream 的方式,将新版本的更改从我们的GitHub仓库同步到您的fork仓库中。
步骤2:初始化
注意:
如果您需要同时使用 IM TUIKit 和 音视频通话 Callkit,请务必确保本步骤 IM 的初始化及登录完成后,再执行 Callkit 的初始化相关操作。
为尊重表情设计版权,IM Demo/TUIKit 工程中不包含大表情元素切图,正式上线商用前请您替换为自己设计或拥有版权的其他表情包。下图所示默认的小黄脸表情包版权归腾讯云所有,可有偿授权使用,如需获得授权可 提交工单 联系我们。
1. 在您应用启动时,初始化 IM。
2. 请务必保证先执行
TIMUIKitCore.getInstance()
,再调用初始化函数 init()
,并将您的sdkAppID
传入。3. 为方便您获取API报错及建议提醒用户的提示语,此处建议挂载一个 onTUIKitCallbackListener 监听,详见此部分。
/// 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 IM application when integrating// language: LanguageEnum.en, // 界面语言配置,若不配置,则跟随系统语言loglevel: LogLevelEnum.V2TIM_LOG_DEBUG,onTUIKitCallbackListener: (TIMCallback callbackValue){}, // [建议配置,详见此部分](https://cloud.tencent.com/document/product/269/70746#callback)listener: V2TimSDKListener());super.initState();}}
登录测试账户
1. 此时,您可以使用最开始的时候,在控制台生成的测试账户,完成登录验证。
2. 调用
_coreInstance.login
方法,登录一个测试账户。import 'package:tencent_cloud_chat_uikit/tencent_cloud_chat_uikit.dart';final CoreServicesImpl _coreInstance = TIMUIKitCore.getInstance();_coreInstance.login(userID: userID, userSig: userSig);
说明:
在下方的步骤3-5中,我们将教您如何使用我们常用组件的最基础用法,移动端和桌面端保持一致,使用同一套代码和文件。
步骤3:实现 - 会话列表页面
您可以以会话列表作为您的 IM 功能首页,其涵盖了与所有有聊天记录的用户及群聊的会话。
您仅需传入一个
onTapItem
事件的处理函数,用于跳转至具体会话聊天页的导航。关于 Chat
类,会在下一步讲解。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) {// 如果需要适配桌面端,此处需要参考 Demo 代码修改。Navigator.push(context,MaterialPageRoute(builder: (context) => Chat(selectedConversation: selectedConv,),));},),);}}
步骤4:实现 - 会话聊天页面
该页面由顶部主体聊天历史记录及底部发送消息模块组成。
建议您传入一个
onTapAvatar
事件的处理函数,用于跳转至联系人的详细信息页。关于 UserProfile
类,会在下一步讲解。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: (_) {// 如果需要适配桌面端,此处需要参考 Demo 代码修改。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`.);}
如果您的业务场景,不是直接从 Conversation Widget 进入Chat Widget,那么将无法自动获得 上方代码中的
V2TimConversation selectedConversation
会话对象。此时,您可根据以下方法,手动 new 一个 V2TimConversation
对象实例,传入 TIMUIKitChat 组件中。TIMUIKitChat(conversation: V2TimConversation(conversationID: "c2c_10040818", // 单聊:"c2c_${对方的userID}" ; 群聊:"group_${groupID}"userID: "", // 仅单聊需要此字段,对方userIDgroupID: "", // 仅群聊需要此字段,群groupIDshowName: "", // 顶部 AppBar 显示的标题type: 1, // 单聊传1,群聊传2// 以上是最简化最基础的必要配置,您还可在此指定更多参数配置,根据 V2TimConversation 的注释),// ......其他 TIMUIKitChat 的配置参数);
步骤5:实现 - 用户详情页面
该页面默认,可在只传入一个
userID
的情况下,自动根据是否是好友,生成用户详情页。说明:
如果您希望自定义该页面,请优先考虑使用
profileWidgetBuilder
传入需自定义的 profile 组件并配合 profileWidgetsOrder
确定纵向排列顺序;如果无法满足,才可使用 builder
。
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,),);}}
此时,您的应用已经可以完成消息收发,管理好友关系,展示用户详情及展示会话列表。
步骤6:搭建应用整体架构
在 TUIKit 2.0.0 版本之后,我们实现了自适应移动端和桌面端的 UI 布局,同时保持了组件用法的一致性。
然而,在应用架构方面,您仍需要针对移动端和桌面端两种不同的模式进行独立适配,包括组件的放置位置、组件间的跳转方式以及页面的整体布局。
平台识别及组件选用
在深入了解本部分内容之前,我们将首先指导您如何利用 TUIKit 提供的方法进行平台识别及平台组件选择,以确保您的业务代码与我们的 TUIKit 组件内部实现的效果保持一致性。
以下功能是我们为桌面端适配开发的通用功能,TUIKit 内部已经实现了这些功能,您可以在您的项目中直接使用。
屏幕类型适配方案
为了实现移动和桌面端的适应,我们推荐您本方案。它可以根据屏幕是桌面宽屏还是手机竖屏来决定展示方式和务逻辑。此方案还能够完成 Web 端的适配。
您可以通过执行以下代码来判断是否为桌面端。通常情况下,无需传入
context
,仅在应用启动后第一次执行时需要。import 'package:tencent_cloud_chat_uikit/ui/utils/screen_utils.dart';final isDesktopScreen = TUIKitScreenUtils.getFormFactor(context) == DeviceType.Desktop;
系统平台识别
尽管在大多数情况下屏幕类型判断足以适配桌面端,但在某些特定场景下仍需当前系统类型例如,分别申请各系统的隐私权限,分别获取各系统的存储路径等。
此外,根据相关隐私政策,建议您不要频繁调用系统API以获取当前系统类型。因此,我们推荐您使用我们提供的系统平台识别能力进行此操作。我们仅在应用启动时获取一次系统类型,并将其存储在全局变量中,以便后续调用时直接返回该参数。
import 'package:tencent_cloud_chat_uikit/ui/utils/platform.dart';final bool isAndroid = PlatformUtils().isAndroid; // 判断当前是否是 Android 设备final bool isWeb = PlatformUtils().isWeb; // 判断当前是否是网页final bool isIOS = PlatformUtils().isIOS; // 判断当前是否是 iOS 设备final bool isWindows = PlatformUtils().isWindows; // 判断当前是否是 Windows 桌面系统final bool isMacOS = PlatformUtils().isMacOS; // 判断当前是否是 macOS 桌面系统final bool isMobile = PlatformUtils().isMobile; // 判断当前是否是手机 app 应用,包含了 Android 及 iOS 设备。final bool isDesktop = PlatformUtils().isDesktop; // 判断当前是否是桌面端应用,包含了 Windows 及 macOS 系统。
根据平台自动选择对应 Widget
在进行桌面端与移动端适配兼容时,有时仅进行细微调整可能不够。可能需要动态展示两个不同的
Widget
。例如,一个组件在移动端需要占据整个页面,具备相应的 Scaffold
和 Appbar
,而在桌面端,仅需作为一个 Modal
弹窗。针对这种场景,我们开发了一个通用的 TUIKitScreenUtils.getDeviceWidget()
方法,传入移动端和桌面端的组件,根据平台类型自动返回对应的组件。使用该方法的示例如下:
TUIKitScreenUtils.getDeviceWidget(desktopWidget: Container(), // 桌面端 Widget。defaultWidget: Container(), // 默认 Widget,必传。当对应平台的 Widget 没有传入时,用此 Widget 兜底。mobileWidget: Container(), // 移动端 Widget。);
假设我们想实现一个组件,在移动端需要占据整个页面,具备相应的
Scaffold
和 Appbar
,而在桌面端则不需要。可以将核心组件部分抽离,使用该方法为移动端添加一个 Scaffold
框架,而桌面端则不需要该框。示例代码如下:@overrideWidgetbuild(BuildContext context) {Widget widgetBody() {return const TIMUIKitBlackList(); // 这里替换成实际需要展示的 Widget}return TUIKitScreenUtils.getDeviceWidget(desktopWidget: widgetBody(), // 桌面端直接展示组件defaultWidget: Scaffold( // 如非特殊情况,移动端可以使用 defaultWidget 默认,包含 ScaffoldappBar: AppBar(),body: widgetBody(),));}
整体架构设计实践
说明:
如果您的应用需要一套代码同时支持移动端和桌面端,我们建议您先阅读移动端部分,再阅读桌面端部分;如果只需要特定平台,可以单独阅读相应平台的实现。
为了获得更好的展示效果,我们的一级组件通常需要独占一整个手机页面。
但是,为了帮助您更好地完成自定义匹配您的业务需求,我们的一级组件都不会内部处理多组件间的跳转,除
TIMUIKitChat
外还不包含 Scaffold
和 Appbar
。这意味着,在使用我们的一级组件时,您需要根据业务需求决定是否以及如何配置
Scaffold
和 Appbar
,并监听暴露出来的点击事件和其他需要跳转的事件,处理 Navigator.push()
跳转。例如,在上方的步骤3中,我们演示了如何通过监听
TIMUIKitConversation
会话列表组件的 onTapItem
点击某个会话的事件回调,跳转至具体某个会话聊天页面。TIMUIKitConversation(onTapItem: (selectedConv) {Navigator.push(context,MaterialPageRoute(builder: (context) => Chat(selectedConversation: selectedConv,),));});
当然,您还可以根据需要,为这些 dart 文件实现的一级组件类,可选配置
Scaffold
和 Appbar
。因 TIMUIKitChat
的顶部 Appbar 逻辑较为复杂,例如包含 “对方正在输入中” 及 “未读数” 展示等等功能,因此TIMUIKitChat
包含了 Scaffold
和 Appbar
,其余一级组件不包含。当然,大部分从我们一级组件自动跳转进入的二级或更深层级的组件,如群管理页面组件,因导航逻辑在组件内部处理,且业务模块较为独立。因此包含了
Scaffold
和 Appbar
。说明:
对于此类
Appbar
,您可通过配置主题的方式,配置 appbarBgColor
appbarTextColor
chatHeaderBgColor
chatHeaderTitleTextColor
等参数以自定义颜色及样式。整体布局
说明:
桌面端的整体架构和移动端较为不同。
区别于移动端通过
Navigator.push()
导航路由的方式切换不同组件及页面,桌面端不太适合频繁进行整体的导航。相信大家在使用微信/新版QQ/飞书等桌面端 IM 软件中已经有所体会,所有的交互操作,都在同一个窗口中完成。通过左侧 Tab 的方式,切换右侧的核心模块。
常见的模块包括:
左侧 Tab icon | 右侧模块内容 |
聊天 | 会话列表 + 每个具体的聊天 + 联系人信息 + 群组信息 |
通讯录 | (联系人列表 or 群组列表) + (联系人 or 群组详情) |
我的 | 设置 or 配置个人信息 |
头像 | 配置个人信息 |
因此,我们建议您采用,建立一个类似于我们 Demo 的 home_page.dart 文件,完成这个两栏式布局。维护一个
index
用于确定当前所在页面,左侧防止一个 LeftBar 用于切换 Tab;右侧放置一个使用 Expand
撑开的 IndexedStack
放置核心页面内容。现在,基于上方提供的 Demo 源码,分别简单介绍一下几个右侧常见的页面,用于上图
Expand(IndexedStack)
部分,的架构布局设计实践。1. 会话列表及会话聊天页面
建议您,参考我们的 Demo 代码,新建一个
dart
文件,用于放置 ConversationAndChat
Widget 类,用于承载本部分业务逻辑。这个类,可以引入您在前序步骤制作的
Chat
, Conversation
, UserProfile
组件,并基本保持这几个用于承载一级组件的 class 代码不变。这个类采用 Row 布局,左侧放置
ConstrainedBox
用于限制宽度的 Conversation
组件,右侧可用 Expand
撑开放置 Chat
组件。此外,还可以 Stack
配合 AnimatedPositioned
动画修改位置的形式,在最右侧浮动一个 UserProfile
或 GroupProfile
组件,用于点击查看联系人或群组详情,在点击时从屏幕外侧进入,并在用完后,回到屏幕外侧。这个
ConversationAndChat
类需要包含状态,记录当前的 V2TimConversation? currentConversation
会话。监听这个 onConversationChanged
事件,并将当前切换至的会话,通过 setState
的方式,记录,并传入 Chat
组件,用于更改当前右侧显示的会话聊天。
2. 联系人页面
联系人页面,通常需要包含以下几个能力:展示联系人列表 / 展示加入的群聊列表/ 展示新的好友申请 / 展示黑名单 / 展示联系人详情 / 展示群组详情 / 搜索联系人或群 / 跳转至会话(单聊和群聊)。
为本部分的代码新建一个 dart 文件,并新建一个
ContactsAndProfile
Widget 类,用于承载本部分业务逻辑。本部分的结构,和上方 会话列表及会话聊天页面 类似,一样采用 Row 布局配合
ConstrainedBox
和 Expand
使用。左侧 ConstrainedBox
用于放置 Contact
及 GroupList
等列表组件,右侧 Expand
用于放置 UserProfile
或 GroupProfile
等信息组件。此外,这个页面有个特殊的特性在于,您可能需要实现跳转至单聊会话或群聊会话的能力,一键进入会话。这部分代码不属于 TUIKit部分,需要您根据自己的业务需要,单独适配。Demo 效果如图所示,图片后有实现思路介绍。
同样,
ContactsAndProfile
也需要配置一个 onNavigateToChat
方法,将监听到的 onClickSendMessage
事件加以转发。此时,在 home_page.dart 引入这个
ContactsAndProfile
组件的位置,监听这个事件,维护一份在 state 中,并转发至 ConversationAndChat
Widget 中。ConversationAndChat 组件类中,可通过
didUpdateWidget
动态刷新外部传入的 V2TimConversation
会话,更新当前聊天页面和会话列表所在的会话。为了达到这个目的,还需要为此前制作的
Chat
Widget 新增一个 directToChat
方法,让外部可以指定当前所在的会话聊天。以及,为
Conversation
组件类新增一个 directToChat
方法,让外部可以指定当前所在的会话,以更新展示当前选中的样式。(默认选中的会话是蓝色背景,未选中白色背景,置顶灰色背景)。此时,即可完成这个从通讯录跳转至会话聊天的能力开发。
3. 其他页面
其他页面的开发思路也类似。
核心还是,尽可能少的修改为每个一级组件配置的全平台通用类,而通过外部页面承载的方式,来实现桌面端适配。
以达到一套代码,一次开发,一个模块全端仅一处维护的目的。
桌面端特色能力
由于桌面多种种特性,例如切换组件不导航跳转,我们为桌面端也制作了一些特色能力,公共通用组件,供您直接使用。
组件一:Modal 弹窗:您可用我们的,也可自定义 TUIKit 中所有弹窗
TUIKit中,大部分在移动端用新页面组件承载的模块,在适配桌面端时,采用了 Modal 弹窗的形式进行处理。
为了保证体验一致性,整个TUIKit中,所有的弹窗均使用同一个组件。该弹窗组件支持配置 标题 / 发送按钮 / 取消按钮 / 宽高 / 位置 等参数。可用于承载二级组件 / 小配置项修改 / 右键菜单 等模块。
1. 您的项目可也用我们的:
您的项目中,如果需要使用弹窗,可以直接选用我们的。保证整个程序中所有弹窗的一致性。
以下展示 showPopupWindow 展示 Modal 的方法的基础用法。更多自定义配置,如展示位置等,可查看该方法注释。
import 'package:tencent_cloud_chat_uikit/ui/widgets/wide_popup.dart';TUIKitWidePopup.showPopupWindow(context: context,title: Modal名称,operationKey: TUIKitWideModalOperationKey.custom,width: MediaQuery.of(context).size.width * 0.4, // 宽度height: MediaQuery.of(context).size.width * 0.5, //高度child: (onClose) => 具体要展示的内部组件(groupID: groupID,controller: _chatController,onClosed: onClose,),);
2. 自定义整个 TUIKit 中所有或部分 Modal 弹窗:
可监听
TIMUIKitConfig
的 showDesktopModalFunc
方法,并根据提供的参数(如点击确认事件回调 /当前的操作类型 operationKey
/ 位置)等信息,构建您自己的弹窗。每次 TUIKit 内部需要弹窗前,都会触发这个回调,并通过
operationKey
字段给您当前弹窗的场景,如果根据 operationKey
判定当前弹窗类型,您需要自定义弹窗,请返回 true
否则返回 false
使用 TUIKit 默认 Modal 弹窗。组件二:二次确认弹窗
TUIKit中的二次确认弹窗暂不支持自定义,不过如果您的业务代码有需要的话,也可以使用我们的,保证体验相近。
与上方 Modal 类似,调用
TUIKitWidePopup.showSecondaryConfirmDialog()
方法即可。参数和配置可查看注释说明。组件三:鼠标右键菜单
有别与移动端的长按或侧滑出现菜单的操作,桌面端通常采用点击或鼠标右键出现菜单列表的方式,进行功能交互。如图:
配合上述组件一:
TUIKitWidePopup.showPopupWindow()
使用。 提供
TUIKitColumnMenu
菜单列表组件,其中每个菜单项都是一个 ColumnMenuItem
组件,可以定义菜单项的显示 label
文字,左侧 icon
图标,及点击事件。并提供 closeFunc
方法,用于在点击事件末尾,关闭右键菜单。需要点击的按钮用 InkWell 包裹,监听 onTapDown 等可以获取到 TapDownDetails 的事件,获得点击鼠标位置,并将位置加以传入。当然,这里您还需要根据实际放置位置,考虑边界因素的影响,避免这个菜单出界,利用 min 方法和 MediaQuery.of(context).size 等参数配合决定 offset 位置。
以下展示最基础用法,更多用法可参考方法注释:
return InkWell(onTapDown: (details){TUIKitWidePopup.showPopupWindow(isDarkBackground: false,operationKey: TUIKitWideModalOperationKey.custom,borderRadius: const BorderRadius.all(Radius.circular(4)),context: context,// 下面的 offset 需要根据实际情况及 details 加以计算。offset: Offset(details.globalPosition.dx + 10, details.globalPosition.dy - 200),child: (closeFunc) => TUIKitColumnMenu(data: [ColumnMenuItem(label: TIM_t("个人中心"), onClick: (){// 你定义的点击事件closeFunc();}),ColumnMenuItem(label: TIM_t("个人中心"), onClick: (){// 你定义的点击事件closeFunc();}),],));},child: Container(),);
附加1:TUIKit 的更多能力
您还可以继续使用以下 TUIKit 组件快速实现完整 IM 功能。
TIMUIKitContact:联系人列表页面。
TIMUIKitGroupProfile:群资料页面,使用方式与
TIMUIKitProfile
基本一致。TIMUIKitGroup:群列表界面。
TIMUIKitBlackList:黑名单列表界面。
TIMUIKitNewContact:联系人(好友)申请列表。如需在外部显示小红点,可使用
TIMUIKitUnreadCount
小红点组件,其会自动挂载监听。本地搜索:
TIMUIKitSearch
全局搜索组件,支持全局搜索联系人/群组/聊天记录,也支持使用 TIMUIKitSearchMsgDetail
在特定会话中搜索聊天记录。两种模式取决于是否传入 conversation
。附加2:[选装] 使用 Controller 控制 TUIKit
说明:
建议在 tencent_cloud_chat_uikit 0.1.5 及以后版本中使用本功能。
通过上述步骤的快速集成,您已经可以搭建一套可用的 IM 模块。如果您有其他额外的控制操作需求,可以使用组件配套的 controller 完成。
使用场景如,在会话列表页面中,您可自定义会话 item 的侧滑菜单,提供置顶会话/删除会话/删除历史消息等功能;抑或是发送消息,满足您的额外消息发送需求,例如通过您自行开发的送礼界面发送一条礼物消息。
目前我们提供三个 controller,如下:
组件 | 控制器 | 功能 |
刷新历史消息列表/更新单条消息/手动发送额外的消息/为消息设置自定义字段 等 | ||
获取及刷新会话列表/会话置顶/设置会话的草稿/清空会话内所有消息/删除会话/滚动到特定会话等 | ||
删除联系人好友/置顶当前联系人的会话/将用户加入黑名单/修改被加好友方式/更新联系人备注名/设置联系人消息免打扰/添加联系人好友/更新自己的资料等 |
1. 在使用到 TIMUIKitChat 的类中,实例化一个 TIMUIKitChatController 对象。
final TIMUIKitChatController _chatController = TIMUIKitChatController();
2. 将此对象传入 TIMUIKitChat 的
controller
参数中。@overrideWidget build(BuildContext context) {return TIMUIKitChat(controller: _chatController,// ...其他参数);}
3. 在这个类中,即可使用控制器,完成自定义操作。例如发送一条地理位置消息:
_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);}
附加3:[选装] 使用更多插件丰富 TUIKit 使用体验
除 TUIKit 本体基础功能外,我们还提供了四个选装插件,帮助您丰富 IM 能力。
消息推送插件:支持厂商原生离线推送能力及在线推送能力,并支持推送您的其他业务消息,帮助您提高消息触达率。
音视频通话插件:支持类似微信的一对一/群组音视频通话。
说明
常见问题
Android 端报错 compileSdkVersion
不合适怎么办?
1. 请在您项目的
pubspec.yaml
文件中,指定确保如下两个插件的版本。video_thumbnail: ^0.5.3permission_handler: ^10.0.0flutter_local_notifications: 9.7.0
2. 修改
android/app/build.gradle
文件,保证 android => compileSdkVersion 33
。android {compileSdkVersion 33...}
3. 执行如下命令,重新安装 Android 端依赖。
flutter pub cache cleanflutter pub get
在 Flutter 2.x 上,Android 构建报错 Codepoint 984472 not found in font, aborting.
怎么办?
在您的编译命令中,加入
--no-tree-shake-icons
。如:flutter build apk --no-tree-shake-icons --dart-define=SDK_APPID={您的SDKAPPID}
iOS 端 Pods 依赖无法安装成功怎么办?
尝试方案一:配置运行后,如果报错,可以单击 Product > Clean Build Folder,清除产物后重新 pod install
或 flutter run
尝试方案二:手动删除 ios/Pods
文件夹,及 ios/Podfile.lock
文件,并执行如下命令,重新安装依赖
1. 搭载新款 Apple Silicon 的Mac设备,例如 M1。
cd iossudo arch -x86_64 gem install ffiarch -x86_64 pod install --repo-update
2. 搭载老款 Intel 芯片的 Mac 设备。
cd iossudo gem install ffipod install --repo-update
佩戴 Apple Watch 时,真机调试 iOS 报错怎么办?
请将您的 Apple Watch 调整至飞行模式,并将 iPhone 的蓝牙功能通过
设置 => 蓝牙
彻底关闭。重新启动 Xcode(若打开),并重新
flutter run
即可。Flutter 环境问题如何确认?
如您需得知 Flutter 的环境是否存在问题,请运行 Flutter doctor 检测 Flutter 环境是否装好。
使用 Flutter 自动生成的项目,引入 TUIKit 后,运行 Android 端报错怎么办?
1. 打开
android\\app\\src\\main\\AndroidManifest.xml
,根据如下,补全 xmlns:tools="http://schemas.android.com/tools"
/ android:label="@string/android_label"
及 tools:replace="android:label"
。<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="替换成您的 Android 端包名"xmlns:tools="http://schemas.android.com/tools"><applicationandroid:label="@string/android_label"tools:replace="android:label"android:icon="@mipmap/ic_launcher" // 指定一个 icon 路径android:usesCleartextTraffic="true"android:requestLegacyExternalStorage="true">
2. 打开
android\\app\\build.gradle
,补全 defaultConfig
中 minSdkVersion
及 targetSdkVersion
。defaultConfig {applicationId "" // 替换成您的Android端包名minSdkVersion 21targetSdkVersion 30}
如果国际化界面语言?
如何获取 API 接口调用报错/Flutter 层报错/弹窗提示信息?
请在初始化 TUIKit 时,挂载
onTUIKitCallbackListener
监听。该监听用于返回包括:SDK API 错误 / Flutter 报错 / 一些可能需要弹窗提示用户的场景信息。
通过
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("当前群组不支持@全体成员"));}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);}}},);
下面,分别介绍这三种类型的回调:
SDK API 错误(TIMCallbackType.API_ERROR
)
该场景下,提供 SDK API 原生
errorMsg
及errorCode
。Flutter 报错(TIMCallbackType.FLUTTER_ERROR
)
该错误由监听 Flutter 原生抛出异常产生,提供错误发生时的
stackTrace
(来自FlutterError.onError
)或catchError
(来自 try-catch)。场景信息(TIMCallbackType.INFO
)
建议根据实际情况,将这些信息弹窗提示用户。
具体提示规则和弹窗样式可由您决定。
提供
infoCode
场景码帮助您确定当前的场景,及默认的提示推荐语infoRecommendText
。您可直接弹窗提示我们的推荐语,也可根据场景码自定义推荐语。推荐语语言使用系统语言语言或您指定的语言,请勿根据推荐语来判断场景。
场景码规则如下:
场景码由七位数组成,前五位数确定场景发生的组件,后两位确定具体的场景表现。
场景码开头 | 对应的组件 |
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 | 通用组件 |
全部场景码清单如下:
场景码 infoCode | 推荐提示语 infoRecommendText | 场景描述 |
6660101 | 好友申请已发送 | 用户申请添加其他用户为联系人 |
6660102 | 该用户已是好友 | 用户申请添加其他已是好友的用户为好友时,触发 onTapAlreadyFriendsItem 回调 |
6660201 | 群申请已发送 | 用户申请加入需要管理员审批的群聊 |
6660202 | 您已是群成员 | 用户申请加群时,判断用户已经是当前群成员,触发 onTapExistGroup 回调 |
6660401 | 无法定位到原消息 | 当用户需要跳转至@消息或者是引用消息时,在消息列表中查不到目标消息 |
6660402 | 视频保存成功 | 用户在消息列表,点开视频消息后,选择保存视频 |
6660403 | 视频保存失败 | 用户在消息列表,点开视频消息后,选择保存视频 |
6660404 | 说话时间太短 | 用户发送了过短的语音消息 |
6660405 | 发送失败,视频不能大于 100MB | 用户试图发送大于 100MB 的视频 |
6660406 | 图片保存成功 | 用户在消息列表,点开图片大图后,选择保存图片 |
6660407 | 图片保存失败 | 用户在消息列表,点开图片大图后,选择保存图片 |
6660408 | 已复制 | 用户在弹窗内选择复制文字消息 |
6660409 | 暂未实现 | 用户在弹窗内选择非标功能 |
6660410 | 其他文件正在接收中 | 用户点击下载文件消息时,前序下载任务还未完成 |
6660411 | 正在接收中 | 用户点击下载文件消息 |
6660412 | 视频消息仅限 mp4 格式 | 用户发送了一条非 mp4 格式的视频消息 |
6660413 | 已加入待下载队列,其他文件下载中 | 已加入待下载队列,其他文件下载中 |
6660414 | 正在下载中 | 桌面端图片/视频资源正在下载中,暂时无法打开,过一会下载好了才能打开 |
6660415 | 视频文件异常 | 发送的视频文件资源本身是错误或被损坏,无法发送 |
6661001 | 无网络连接,无法修改 | 当用户试图在无网络环境下,修改群资料 |
6661002 | 无网络连接,无法查看群成员 | 当用户试图在无网络环境下,修改群资料 |
6661003 | 成功取消管理员身份 | 用户将群内其他用户移除管理员 |
6661201 | 无网络连接,无法修改 | 当用户试图在无网络环境下,修改自己或联系人的资料 |
6661202 | 好友添加成功 | 在资料页添加其他用户为好友,并自动添加成功,无需验证 |
6661203 | 好友申请已发出 | 在资料页添加其他用户为好友,对方设置需要验证 |
6661204 | 当前用户在黑名单 | 在资料页添加其他用户为好友,对方在自己的黑名单内 |
6661205 | 好友添加失败 | 在资料页添加其他用户为好友,添加失败,可能是由于对方禁止加好友 |
6661206 | 好友删除成功 | 在资料页删除其他用户为好友,成功 |
6661207 | 好友删除失败 | 在资料页删除其他用户为好友,失败 |
6661401 | 输入不能为空 | 当用户在录入信息时,输入了空字符串 |
6661402 | 请传入离开群组生命周期函数,提供返回首页或其他页面的导航方法 | 用户退出群或解散群时,为提供返回首页办法 |
6661403 | 设备存储空间不足,建议清理,以获得更好使用体验 | 在 login 成功后,会自动检测设备存储空间,如果不足1GB,会提示存储空间不足 |