Flutter即时通讯UI组件插件em_chat_uikit的使用
Flutter即时通讯UI组件插件em_chat_uikit的使用
开发环境
environment:
sdk: '>=3.0.0 <4.0.0'
flutter: '>=3.19.0'
- iOS: 12+
- Android: minSDKVersion 24
安装
flutter pub add em_chat_uikit
结构
.
├── chat_uikit.dart // 库文件
├── chat_uikit_alphabet_sort_helper.dart // 用于纠正联系人字母顺序的工具
├── chat_uikit_defines.dart // UIKit 处理定义类
├── chat_uikit_emoji_data.dart // 消息表情数据类
├── chat_uikit_localizations.dart // 国际化工具类
├── chat_uikit_service // 聊天 SDK 包装类的二次封装,用于将不合规功能适配到 UIKit 功能
├── chat_uikit_settings.dart // 用于设置功能的类,用于打开或关闭某些功能
├── chat_uikit_time_formatter.dart // 用于设置显示时间格式的工具
├── provider // 用户属性工具
│ ├── chat_uikit_profile.dart // 用户属性对象,包括用户的头像、昵称和备注
│ └── chat_uikit_provider.dart // 用户属性提供者,用于在 UIKit 中提供用户属性数据
├── sdk_service // 聊天 SDK 包装,用于包装聊天 SDK 可供开发者使用的 API。UIKit 与包装类交互,而不是直接调用聊天 SDK 的 API
├── tools // 内部工具类
│ ├── chat_uikit_context.dart // 数据上下文,用于存储某些状态
│ ├── chat_uikit_conversation_extension.dart // 对会话列表进行处理的类,用于预处理某些属性
│ ├── chat_uikit_file_size_tool.dart // 用于计算显示的文件大小的工具
│ ├── chat_uikit_helper.dart // 计算边框半径的内部类
│ ├── chat_uikit_highlight_tool.dart // 计算组件高亮值的工具类
│ ├── chat_uikit_image_loader.dart // 图片加载工具类
│ ├── chat_uikit_message_extension.dart // 消息处理类,用于预处理某些属性
│ ├── chat_uikit_time_tool.dart // 默认时间格式类
│ ├── chat_uikit_url_helper.dart // URL 预览工具类
│ └── safe_disposed.dart // ChangeNotifier 的内部处理类
├── ui // UI 组件
│ ├── components // 组件
│ ├── controllers // 视图/小部件控制器
│ ├── custom // UI 自定义
│ ├── models // 模型
│ ├── route // UIKit 中的路由组件
│ ├── views // 视图
│ └── widgets // 小部件
└── universal // 内部类
快速开始
- 创建项目。
flutter create uikit_quick_start --platforms=android,ios
- 添加依赖。
cd uikit_quick_start
flutter pub add em_chat_uikit
flutter pub get
- 添加权限。
- iOS: 在
<project root>/ios/Runner/Info.plist
中添加权限。
NSPhotoLibraryUsageDescription
NSCameraUsageDescription
NSMicrophoneUsageDescription
- 初始化 UIKit。
import 'package:em_chat_uikit/chat_uikit.dart';
void main() {
ChatUIKit.instance
.init(options: Options(appKey: '<!--Your AppKey-->', autoLogin: false))
.then((value) {
runApp(const MyApp());
});
}
- 登录 UIKit。
Future<void> login() async {
try {
await ChatUIKit.instance.loginWithToken(
userId: '<!--user id-->', token: '<!--user token-->');
} catch (e) {
debugPrint('login error: $e');
}
}
- 创建聊天页面。
class ChatPage extends StatefulWidget {
const ChatPage({required this.chatterId, super.key});
final String chatterId;
@override
State<ChatPage> createState() => _ChatPageState();
}
class _ChatPageState extends State<ChatPage> {
@override
Widget build(BuildContext context) {
return MessagesView(
profile: ChatUIKitProfile.contact(
id: widget.chatterId,
),
);
}
}
完整的代码:
import 'package:flutter/material.dart';
import 'package:em_chat_uikit/chat_uikit.dart';
const String appKey = '';
const String userId = '';
const String token = '';
const String chatterId = '';
void main() {
ChatUIKit.instance
.init(options: Options(appKey: appKey, autoLogin: false))
.then((value) {
runApp(MyApp());
});
}
class MyApp extends StatelessWidget {
MyApp({super.key});
final ChatUIKitLocalizations _localization = ChatUIKitLocalizations();
// 这个小部件是你的应用的根节点。
@override
Widget build(BuildContext context) {
return MaterialApp(
supportedLocales: _localization.supportedLocales,
localizationsDelegates: _localization.localizationsDelegates,
localeResolutionCallback: _localization.localeResolutionCallback,
locale: _localization.currentLocale,
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: login,
child: const Text('登录'),
),
ElevatedButton(
onPressed: chat,
child: const Text('聊天'),
),
],
),
),
);
}
Future<void> login() async {
try {
await ChatUIKit.instance.loginWithToken(
userId: userId,
token: token,
);
} catch (e) {
debugPrint('登录错误: $e');
}
}
void chat() {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const ChatPage(
chatterId: chatterId,
),
),
);
}
}
class ChatPage extends StatefulWidget {
const ChatPage({required this.chatterId, super.key});
final String chatterId;
@override
State<ChatPage> createState() => _ChatPageState();
}
class _ChatPageState extends State<ChatPage> {
@override
Widget build(BuildContext context) {
return MessagesView(
profile: ChatUIKitProfile.contact(
id: widget.chatterId,
),
);
}
}
高级使用
提供者(Provider)
提供者是一个数据提供器。如果需要显示用户数据或群组数据,UIKit 会通过提供者请求数据,并且你需要将数据返回给提供者。一旦 UIKit 获取到你的数据,它会刷新 UI 来展示你的数据。以下是一个提供者的例子(example/lib/tool/user_provider_widget.dart
)。
示例
class UserProviderWidget extends StatefulWidget {
const UserProviderWidget({required this.child, super.key});
final Widget child;
@override
State<UserProviderWidget> createState() => _UserProviderWidgetState();
}
class _UserProviderWidgetState extends State<UserProviderWidget> with GroupObserver {
@override
void initState() {
super.initState();
ChatUIKit.instance.addObserver(this);
// 打开数据库
UserDataStore().init(onOpened: onOpened);
// 设置提供者处理器
ChatUIKitProvider.instance.profilesHandler = onProfilesRequest;
}
@override
void dispose() {
ChatUIKit.instance.removeObserver(this);
super.dispose();
}
@override
Widget build(BuildContext context) {
return widget.child;
}
void onOpened() async {
// 1. 将所有存储的数据填充到 UIKit。
await addAllUserInfoToProvider();
// 2. 加载群组信息,检查是否已填充到 UIKit。如果没有,则从服务器获取数据并填充到 UIKit。
await loadGroupInfos();
// 3. 加载用户信息,检查是否已填充到 UIKit。如果没有,则从服务器获取数据并填充到 UIKit。
await loadUserInfos();
// 4. 获取当前用户信息,然后填充到 UIKit。
await fetchCurrentUserInfo();
}
Future<void> fetchCurrentUserInfo() async {
try {
// 不要从数据库检索自己的用户数据,总是从服务器获取最新数据。
Map<String, UserInfo> map = await ChatUIKit.instance.fetchUserInfoByIds([ChatUIKit.instance.currentUserId!]);
ChatUIKitProfile profile = ChatUIKitProfile.contact(
id: map.values.first.userId,
nickname: map.values.first.nickName,
avatarUrl: map.values.first.avatarUrl,
);
UserDataStore().saveUserData(profile);
ChatUIKitProvider.instance.addProfiles([profile]);
} catch (e) {
debugPrint('获取当前用户信息错误: $e');
}
}
// 当 UIKit 需要显示用户信息且缓存不存在时;它需要根据用户属性获取并存储信息到数据库。
List<ChatUIKitProfile>? onProfilesRequest(List<ChatUIKitProfile> profiles) {
List<String> userIds = profiles
.where((e) => e.type == ChatUIKitProfileType.contact)
.map((e) => e.id)
.toList();
if (userIds.isNotEmpty) {
fetchUserInfos(userIds);
}
List<String> groupIds = profiles
.where((e) => e.type == ChatUIKitProfileType.group)
.map((e) => e.id)
.toList();
updateGroupsProfile(groupIds);
return profiles;
}
// 当你创建了一个群组,需要将群组信息填充到 UIKit。
@override
void onGroupCreatedByMyself(Group group) async {
ChatUIKitProfile profile =
ChatUIKitProfile.group(id: group.groupId, groupName: group.name);
ChatUIKitProvider.instance.addProfiles([profile]);
// 保存到数据库
UserDataStore().saveUserData(profile);
}
// 当你自己更改了群组名称,需要更新 UIKit 中的群组信息。
@override
void onGroupNameChangedByMeSelf(Group group) {
ChatUIKitProfile? profile =
ChatUIKitProvider.instance.getProfileById(group.groupId);
profile = profile?.copyWith(name: group.name) ??
ChatUIKitProfile.group(
id: group.groupId,
groupName: group.name,
);
ChatUIKitProvider.instance.addProfiles([profile]);
// 保存到数据库
UserDataStore().saveUserData(profile);
}
// 将所有存储的数据填充到 UIKit。
Future<void> addAllUserInfoToProvider() async {
List<ChatUIKitProfile> list = await UserDataStore().loadAllProfiles();
ChatUIKitProvider.instance.addProfiles(list);
}
// 加载群组信息,检查是否已填充到 UIKit。如果没有,则从服务器获取数据并填充到 UIKit。
Future<void> loadGroupInfos() async {
List<Group> groups = await ChatUIKit.instance.getJoinedGroups();
List<ChatUIKitProfile> profiles = groups
.map((e) => ChatUIKitProfile.group(id: e.groupId, groupName: e.name))
.toList();
if (profiles.isNotEmpty) {
UserDataStore().saveUserDatas(profiles);
ChatUIKitProvider.instance.addProfiles(profiles);
}
}
Future<void> updateGroupsProfile(List<String> groupIds) async {
List<ChatUIKitProfile> list = [];
for (var groupId in groupIds) {
try {
Group group = await ChatUIKit.instance.fetchGroupInfo(groupId: groupId);
ChatUIKitProfile profile = ChatUIKitProfile.group(
id: group.groupId,
groupName: group.name,
avatarUrl: group.extension,
);
list.add(profile);
} on ChatError catch (e) {
if (e.code == 600) {
// 600 表示群组不存在,无法获取数据,提供默认数据。
ChatUIKitProfile profile = ChatUIKitProfile.group(id: groupId);
list.add(profile);
}
debugPrint('加载群组信息错误: $e');
}
}
UserDataStore().saveUserDatas(list);
ChatUIKitProvider.instance.addProfiles(list);
}
// 加载用户信息,检查是否已填充到 UIKit。如果没有,则从服务器获取数据并填充到 UIKit。
Future<void> loadUserInfos() async {
try {
Map<String, ChatUIKitProfile> map =
ChatUIKitProvider.instance.profilesCache;
List<Contact> contacts = await ChatUIKit.instance.getAllContacts();
contacts.removeWhere((element) => map.keys.contains(element.userId));
if (contacts.isNotEmpty) {
List<String> userIds = contacts.map((e) => e.userId).toList();
fetchUserInfos(userIds);
}
} catch (e) {
debugPrint('加载用户信息错误: $e');
}
}
void fetchUserInfos(List<String> userIds) async {
try {
Map<String, UserInfo> map =
await ChatUIKit.instance.fetchUserInfoByIds(userIds);
List<ChatUIKitProfile> list = map.values
.map((e) => ChatUIKitProfile.contact(
id: e.userId, nickname: e.nickName, avatarUrl: e.avatarUrl))
.toList();
if (list.isNotEmpty) {
UserDataStore().saveUserDatas(list);
ChatUIKitProvider.instance.addProfiles(list);
}
} catch (e) {
debugPrint('获取用户信息错误: $e');
}
}
}
使用
在使用 ChatUIKitProvider
之前,需要设置 profilesHandler
。之后,当需要显示相关信息时,UIKit 会通过处理器返回一个默认的 ChatUIKitProfile
对象,你需要返回一个 ChatUIKitProfile
对象。建议首先返回一个占位符的 ChatUIKitProfile
对象。当你从服务器或数据库获取到正确的 ChatUIKitProfile
对象后,通过 ChatUIKitProvider.instance.addProfiles(list)
方法将其传递给 UIKit。接收该对象后,UIKit 会刷新 UI 并进行缓存以供后续显示。以下是使用 ChatUIKitProvider
的步骤:
- 在应用启动和登录时设置
profilesHandler
。
ChatUIKitProvider.instance.profilesHandler = onProfilesRequest;
- 通过
ChatUIKitProvider
将用户数据和群组数据设置到 UIKit。
List<ChatUIKitProfile> list = await UserDataStore().loadAllProfiles();
ChatUIKitProvider.instance.addProfiles(list);
- 当执行
profilesHandler
时,你可以首先返回占位符的ChatUIKitProfile
对象,从服务器获取数据,然后将其保存到数据库并传递给 UIKit。
List<ChatUIKitProfile>? onProfilesRequest(List<ChatUIKitProfile> profiles) {
List<String> userIds = profiles
.where((e) => e.type == ChatUIKitProfileType.contact)
.map((e) => e.id)
.toList();
if (userIds.isNotEmpty) {
fetchUserInfos(userIds);
}
List<String> groupIds = profiles
.where((e) => e.type == ChatUIKitProfileType.group)
.map((e) => e.id)
.toList();
updateGroupsProfile(groupIds);
return profiles;
}
配置项
ChatUIKit
允许通过 ChatUIKitSettings
进行样式自定义。
import 'chat_uikit.dart';
import 'package:flutter/material.dart';
enum CornerRadius { extraSmall, small, medium, large }
class ChatUIKitSettings {
/// 指定 UIKit 中头像的圆角半径。
static CornerRadius avatarRadius = CornerRadius.medium;
/// 指定搜索框的圆角半径。
static CornerRadius searchBarRadius = CornerRadius.small;
/// 指定输入框的圆角半径。
static CornerRadius inputBarRadius = CornerRadius.medium;
/// 默认头像占位符图像。
static ImageProvider? avatarPlaceholder;
/// 对话框的圆角类型。
static ChatUIKitDialogRectangleType dialogRectangleType =
ChatUIKitDialogRectangleType.filletCorner;
/// 消息气泡的默认显示样式。
static ChatUIKitMessageListViewBubbleStyle messageBubbleStyle =
ChatUIKitMessageListViewBubbleStyle.arrow;
/// 是否在会话列表中显示头像。
static bool showConversationListAvatar = true;
/// 是否在会话列表中显示未读消息数量。
static bool showConversationListUnreadCount = true;
// 会话列表中显示的静音图标。
static ImageProvider? conversationListMuteImage;
/// 消息长按菜单。
static List<ChatUIKitActionType> msgItemLongPressActions = [
ChatUIKitActionType.reaction,
ChatUIKitActionType.copy, // 仅文本消息。
ChatUIKitActionType.forward,
ChatUIKitActionType.thread, // 仅群消息。
ChatUIKitActionType.reply,
ChatUIKitActionType.recall,
ChatUIKitActionType.edit, // 仅文本消息。
ChatUIKitActionType.multiSelect,
ChatUIKitActionType.pinMessage,
ChatUIKitActionType.translate, // 仅文本消息。
ChatUIKitActionType.report,
ChatUIKitActionType.delete,
];
/// 是否启用一对一聊天消息的输入状态功能。
static bool enableTypingIndicator = true;
/// 是否启用线程功能。
static bool enableMessageThread = true;
/// 是否启用消息翻译功能。
static bool enableMessageTranslation = true;
/// 消息翻译的目标语言。
static String translateTargetLanguage = 'zh-Hans';
/// 是否启用消息反应功能。
static bool enableMessageReaction = true;
/// 消息反应表情在底部表单标题中。这些表情需要包含在表情列表 [ChatUIKitEmojiData.emojiList] 中。
static List<String> favoriteReaction = [
'\u{1F44D}',
'\u{2764}',
'\u{1F609}',
'\u{1F928}',
'\u{1F62D}',
'\u{1F389}',
];
/// 默认消息 URL 的正则表达式。
static RegExp defaultUrlRegExp = RegExp(
r'(?:(?:https?|ftp):\/\/)?[\w/\-?=%.]+\.[\w/\-?=%.]+',
caseSensitive: false,
);
/// 是否启用消息固定功能。
static bool enablePinMsg = true;
/// 是否启用消息引用功能。
static bool enableMessageReply = true;
/// 是否启用消息撤回功能。
static bool enableMessageRecall = true;
/// 消息撤回的时间限制,单位为秒。
static int recallExpandTime = 120;
/// 是否启用消息编辑功能。
static bool enableMessageEdit = true;
/// 是否启用消息举报功能。
static bool enableMessageReport = true;
/// 消息举报标签,可以自定义。举报原因应该写入本地化文件中,本地化文件中的原因键应与标签一致。例如,[ChatUIKitLocal.reportTarget1]
static List<String> reportMessageTags = [
'tag1',
'tag2',
'tag3',
'tag4',
'tag5',
'tag6',
'tag7',
'tag8',
'tag9',
];
/// 是否启用消息多选功能。
static bool enableMessageMultiSelect = true;
/// 是否启用消息转发功能。
static bool enableMessageForward = true;
/// 联系人 `showName` 的字母排序。如果有中文字符,可以使用 [ChatUIKitAlphabetSortHelper] 重新定义首字母。
static String sortAlphabetical = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ#';
}
国际化
UIKit 提供了国际化功能。在集成 UIKit 时,你需要在 MaterialApp
中设置国际化信息。
final ChatUIKitLocalizations _localization = ChatUIKitLocalizations();
...
@override
Widget build(BuildContext context) {
return MaterialApp(
supportedLocales: _localization.supportedLocales,
localizationsDelegates: _localization.localizationsDelegates,
localeResolutionCallback: _localization.localeResolutionCallback,
locale: _localization.currentLocale,
...
);
}
要添加支持的语言,你可以先使用 ChatUIKitLocalizations.addLocales
,然后调用 ChatUIKitLocalizations.resetLocales
。
以下是如何添加法语的例子。
_localization.addLocales(locales: const [
ChatLocal('fr', {
ChatUIKitLocal.conversationsViewSearchHint: 'Recherche',
})
]);
_localization.resetLocales();
主题
UIKit 自带两个主题:浅色和深色,默认为浅色主题。设置主题时,建议添加 ChatUIKitTheme
组件作为 UIKit 的根节点。
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
builder: (context, child) {
/// 添加主题支持
return ChatUIKitTheme(
font: ChatUIKitFont(),
color: ChatUIKitColor.light(), // ChatUIKitColor.dark()
child: child!,
);
},
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
ChatUIKitColor
可以通过调整 hue
来自定义。例如,在浅色模式下调整 hue
值。
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
builder: (context, child) {
return ChatUIKitTheme(
color: ChatUIKitColor.light(
primaryHue: 203,
secondaryHue: 155,
errorHue: 350,
neutralHue: 203,
neutralSpecialHue: 220,
),
child: child!,
);
},
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
ChatUIKitFont
允许你设置字体大小。例如,你可以通过 ChatUIKitFont.fontSize(fontSize: ChatUIKitFontSize.normal)
传递不同的 ChatUIKitFontSize
类型来改变 UIKit 的字体大小。
路由拦截和定制
UIKit 使用 pushNamed
实现重定向,通过目标重定向页面的 ChatUIKitViewArguments
对象传递。你可以拦截 onGenerateRoute(RouteSettings settings)
并解析 settings.name
来获取目标重定向页面。然后,你可以重置 ChatUIKitViewArguments
参数以实现重定向拦截和页面定制。目标重定向页面的名称在 chat_uikit_route_names.dart
中指定。
有关路由拦截的详细信息,可以参考 example/lib/custom/chat_route_filter.dart
。
事件拦截和错误处理
当 UIKit 开始调用聊天 SDK 时,ChatSDKEventsObserver.onChatSDKEventBegin
会被触发。当调用结束时,ChatSDKEventsObserver.onChatSDKEventEnd
会被触发。如果发生错误,会报告 ChatError
。
class SDKEventHandlerPage extends StatefulWidget {
const SDKEventHandlerPage({super.key});
@override
State<SDKEventHandlerPage> createState() => _SDKEventHandlerPageState();
}
class _SDKEventHandlerPageState extends State<SDKEventHandlerPage> with ChatSDKEventsObserver {
@override
void initState() {
ChatUIKit.instance.addObserver(this);
super.initState();
}
@override
void dispose() {
ChatUIKit.instance.removeObserver(this);
super.dispose();
}
/// 当调用 SDK 方法开始时,可以根据不同事件显示不同的提示窗口。
@override
void onChatSDKEventBegin(ChatSDKEvent event) {}
/// 当调用 SDK 方法结束时,此时可以结束提示窗口的显示。如果发生错误,可以显示相应的提示消息。
@override
void onChatSDKEventEnd(ChatSDKEvent event, ChatError? error) {}
...
}
更多详细信息,可以参考 example/lib/tool/toast_page.dart
。
对于其他非聊天 SDK 的事件,ChatUIKitEventsObservers.onChatUIKitEventsReceived
会被触发。
class UIKitEventHandlePage extends StatefulWidget {
const UIKitEventHandlePage({super.key});
@override
State<UIKitEventHandlePage> createState() => _UIKitEventHandlePageState();
}
class _UIKitEventHandlePageState extends State<UIKitEventHandlePage> with ChatUIKitEventsObservers {
@override
void initState() {
ChatUIKit.instance.addObserver(this);
super.initState();
}
@override
void dispose() {
ChatUIKit.instance.removeObserver(this);
super.dispose();
}
/// 此方法用于将事件从 ChatUIKit 传递给开发者。
@override
void onChatUIKitEventsReceived(ChatUIKitEvent event) {}
...
}
更多详细信息,见 example/lib/tool/toast_page.dart
。
连接状态变化和登录令牌过期回调
当连接状态或登录状态发生变化时,ChatUIKit.instance.connectHandler
中的相应事件会被触发。
ChatUIKit.instance.connectHandler(
onUserAuthenticationFailed: () {},
onUserDidChangePassword: () {},
onUserDidForbidByServer: () {},
onUserDidLoginFromOtherDevice: (info) {},
onUserDidLoginTooManyDevice: () {},
onUserDidRemoveFromServer: () {},
onUserKickedByOtherDevice: () {},
onConnected: () {},
onDisconnected: () {},
onTokenWillExpire: () {},
onTokenDidExpire: () {},
onAppActiveNumberReachLimit: () {},
);
更多详细信息,可以参考 example/lib/tool/token_status_handler_widget.dart
。
消息时间格式化
UIKit 默认以某种格式显示时间。你可以调用 ChatUIKitTimeFormatter
来改变时间的显示方式。
ChatUIKitTimeFormatter.instance.formatterHandler = (context, type, time) {
return 'formatter time'; // 返回格式化的时间,如 12:00 PM
};
联系人字母顺序修正
例如,如果联系人的名字包含除英文字母以外的其他字符,你可以使用 ChatUIKitAlphabetSortHelper
来按字母顺序排序联系人。
ChatUIKitAlphabetSortHelper.instance.sortHandler = (String? groupId, String userId, String showName) {
// 返回 showName 的第一个字母用于排序,特别是对中文字符有用
return PinyinHelper.getFirstWordPinyin(showName);
};
更多关于Flutter即时通讯UI组件插件em_chat_uikit的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter即时通讯UI组件插件em_chat_uikit的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
em_chat_uikit
是一个用于 Flutter 的即时通讯 UI 组件插件,由环信(Easemob)提供。它基于环信的即时通讯 SDK,简化了开发者在 Flutter 应用中集成聊天功能的过程。以下是如何使用 em_chat_uikit
插件的步骤:
1. 添加依赖
首先,在你的 pubspec.yaml
文件中添加 em_chat_uikit
依赖:
dependencies:
flutter:
sdk: flutter
em_chat_uikit: ^1.0.0 # 请检查最新版本
然后运行 flutter pub get
来安装依赖。
2. 初始化环信 SDK
在使用 em_chat_uikit
之前,你需要初始化环信 SDK。通常在你的 main.dart
文件中进行初始化:
import 'package:em_chat_uikit/em_chat_uikit.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// 初始化环信 SDK
await EMChatUIKit.instance.init(
appKey: 'your_app_key', // 替换为你的环信 App Key
apnsCertName: 'your_apns_certificate_name', // iOS 推送证书名称,可选
);
runApp(MyApp());
}
3. 用户登录
在用户登录界面,使用 EMChatUIKit
提供的方法进行用户登录:
void login(String username, String password) async {
try {
await EMChatUIKit.instance.login(username, password);
// 登录成功后,导航到主界面
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => HomeScreen()));
} catch (e) {
// 处理登录失败
print('Login failed: $e');
}
}
4. 使用聊天 UI 组件
em_chat_uikit
提供了多个预构建的聊天 UI 组件,你可以直接在应用中使用。
聊天列表
显示用户的好友列表或群组列表:
import 'package:em_chat_uikit/em_chat_uikit.dart';
class ChatListScreen extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Chats'),
),
body: EMChatListView(),
);
}
}
聊天界面
显示与特定用户的聊天界面:
import 'package:em_chat_uikit/em_chat_uikit.dart';
class ChatScreen extends StatelessWidget {
final String userId;
ChatScreen(this.userId);
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(userId),
),
body: EMChatView(
conversationId: userId,
conversationType: EMConversationType.Chat,
),
);
}
}
5. 处理消息事件
你可以监听消息事件来处理新消息、消息发送状态等。
import 'package:em_chat_uikit/em_chat_uikit.dart';
class ChatScreen extends StatefulWidget {
final String userId;
ChatScreen(this.userId);
[@override](/user/override)
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
[@override](/user/override)
void initState() {
super.initState();
EMChatUIKit.instance.addMessageListener(onMessageReceived);
}
[@override](/user/override)
void dispose() {
EMChatUIKit.instance.removeMessageListener(onMessageReceived);
super.dispose();
}
void onMessageReceived(EMMessage message) {
// 处理新消息
print('New message received: ${message.body}');
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.userId),
),
body: EMChatView(
conversationId: widget.userId,
conversationType: EMConversationType.Chat,
),
);
}
}