# im_plugin_tencent
**Repository Path**: nx6313/im_plugin_tencent
## Basic Information
- **Project Name**: im_plugin_tencent
- **Description**: flutter 版本 - 腾讯IM 会话 / 聊天 / 音视频通话 封装
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-10-13
- **Last Updated**: 2026-10-30
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# im_plugin_tencent
The Flutter plugin integrated with Tencent instant messaging supports chatting and audio/video calling. Provide two usage modes: API calling and using with UI. Real out of the box use.
---
### 先看手机上的效果
[](https://gitee.com/nx6313/im_plugin_tencent)
---
### ☕ 请我喝一杯咖啡 😘🥰🥺
[](https://github.com/ImGdong/preview/blob/main/wx_pay.png?raw=true)
---
### web平台
#### 聊天互动使用:[@tencentcloud/lite-chat](https://cloud.tencent.com/document/product/269/75285) (无UI)进行集成
#### 音视频通话使用:[TUICallEngine](https://web.sdk.qcloud.com/component/trtccalling/doc/TUICallEngine/web/zh-cn/tutorial-00-%E5%AE%9E%E7%8E%B0%E5%8F%8C%E4%BA%BA%E9%80%9A%E8%AF%9D.html) (无UI)进行集成
### flutter 各原生平台(android、ios、macos、windows)
#### 聊天互动使用:[tencent_cloud_chat_sdk](https://cloud.tencent.com/document/product/269/75286) (无UI)进行集成
#### 音视频通话使用:[atomic_x_core](https://cloud.tencent.com/document/product/269/130870) (无UI)进行集成
---
## 预览示例
如果您或您的公司有现成可用的 腾讯IM 即时通讯 服务,
那么您可以点击下面的示例去看看效果。
使用 腾讯IM 即时通讯 的相关参数 登录后就能看到效果啦 🤩🤩🤩🤪
放心登录,这只是示例项目,不会记录任何您的个人资料信息,我保证 😁
[👉 WEB 平台 - 点击查看示例效果](https://portal.yuanhuimiaozhen.com/tencent-im-web/)
---
## 使用前准备
### 第一步
引入插件包
```dart
dependencies:
im_plugin_tencent: 最新版本号
// 通过命令
flutter pub add im_plugin_tencent
```
### 第二步(仅针对web平台)
下载并复制以下文件到项目的 web 目录下
##### [im_plugin.bundle.js](https://gitee.com/nx6313/im_plugin_tencent/blob/master/web/im_plugin.bundle.js)
### 第三步(仅针对web平台)
在 web/index.html 的 head之间添加下面的代码
```javascript
```
---
> 请注意:android、ios 平台是一类用法;web 平台是一类用法。他们拥有各自的组件以及特有的方法
---
## 需要注意的平台特性
android平台
##### (可选)如果您需要在应用外使用 CallKit 的悬浮窗能力,需要开启系统画中画特性。
请在 App 主工程的 AndroidManifest.xml 里设置 MainActivity 的 android:supportsPictureInPicture 为 true
```dart
```
##### 开启后台采集音频/视频
参考官方文档:[拨打第一通电话](https://cloud.tencent.com/document/product/269/130870#38919b63-e58a-44d4-b03b-889585d27cf7)
> 更多功能 / 开启后台采集音频/视频
ios平台
##### 由于 tencent_rtc_sdk 通过 Flutter FFI 调用接口,iOS Release 构建时 Xcode 的符号裁剪优化可能误移除 TRTC 的 C 符号,引发 symbol not found 错误。解决方案如下
1、在项目的 Build Settings 中找到 Deployment Postprocessing,将其设置为 Yes 。

2、在项目的 Build Settings 中找到 Strip Style,将其中 Release 的值设置为 Non-Global Symbols 。
##### 开启后台采集音频/视频
参考官方文档:[拨打第一通电话](https://cloud.tencent.com/document/product/269/130870#38919b63-e58a-44d4-b03b-889585d27cf7)
> 更多功能 / 开启后台采集音频/视频
---
## 开始使用
共有两种使用方式(选择你需要的方式就可以)
- [带 UI 的使用方式](#-ui-)
- [仅 API 调用的方式](#-api-)
---
### 带 UI 的使用方式
#### 在使用UI之前, 你必须先进行IM的初始化与登录流程
### 初始化
android / ios 平台
在 程序入口 这样做
```dart
import 'package:im_plugin_tencent/im/init.dart';
import 'package:im_plugin_tencent/im/event_chat_listener_config.dart';
import 'package:im_plugin_tencent/im/event_call_listener_config.dart';
// 初始化 IM SDK
initTencentImSDK({
required int sdkAppId,
bool initCall = true, // 是否初始化音视频通话,默认 true
EventChatListenerConfig? eventChatListener, // 可不传。聊天事件监听
EventCallListenerConfig? eventCallListener, // 可不传。音视频通话事件监听
});
```
web 平台
在 浏览器每次刷新都会执行的地方 这样做
```dart
import 'package:im_plugin_tencent/im/init.dart';
import 'package:im_plugin_tencent/im/event_chat_listener_config.dart';
import 'package:im_plugin_tencent/im/event_call_listener_config.dart';
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
try {
// 下面方法其实可以不传入任何参数,不传参数时会从浏览器会话缓存中读取im相关参数,进行im初始化与im自动登录
//
// 内部执行逻辑:
//
// 1、先确认 sdkAppId
// sdkAppId = 传入的 sdkAppId ?? 浏览器会话缓存中的 sdkAppId;
// 如果最终确认的 sdkAppId 为空,则进入 catch,错误码:101
//
// 2、如果 sdkAppId 不为空,先执行 腾讯IM SDK 的初始化
// 再从浏览器会话缓存中读取 IM登录信息,执行 腾讯IM 的登录
// 读取不到浏览器会话缓存中的 IM登录信息,则进入 catch。如果仅需要实现初始化IM的步骤,那么该 catch 忽略即可
// 错误码表:
// 201 缓存中不存在 imLoginInfo
// 202 解析 imLoginInfo 缓存出错
// 203 执行腾讯IM官方登录接口报错
//
// 如果你还没有执行过 [doImTencentWebPluginLogin] - im的登录方法,就进入了第二步的异常,可不处理
// 如果你已经执行过 [doImTencentWebPluginLogin] - im的登录方法,就进入了第二步的异常,则需要处理,进行重新登录IM的逻辑
await setTencentImParamsAndLoginByCached(
sdkAppId: 0,
initCall: true, // 是否初始化音视频通话,默认 true
// 如果选择初始化音视频通话,那么该参数必须传入。这样才能正确的在接收到音视频通话邀请的时候显示出来邀请浮窗
navigatorKey: xxx,
eventChatListener: EventChatListenerConfig(), // 可不传。聊天事件监听
eventCallListener: EventCallListenerConfig(), // 可不传。音视频通话事件监听
);
} catch (err) {
// 收到 IM 初始化或登录异常的情况下,进行进一步处理
// 比如:再次调用 setTencentImParamsAndLoginByCached 传入需要的参数,别让它走缓存了
// 比如:重新进行IM的登录
}
});
}
```
### 登录
在可以允许进行登录 IM 的地方(比如:用户通过登录页面执行登录)
android / ios 平台
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
await ImPluginTencent.login(userID: userID, userSig: userSig);
// 如果有需要,可在登录完成后调用该方法,设置用户在腾讯IM中的个人资料信息
ImPluginTencent.updateMyProfile({
'nickName': '',
'faceUrl': '',
...
});
```
web 平台
```dart
import 'package:im_plugin_tencent/im/init.dart';
try {
await doImTencentWebPluginLogin(
userId, // 登录 userId
userSig, // 登录 userSig
);
// 如果有需要,可在登录完成后调用该方法,设置用户在腾讯IM中的个人资料信息
ImPluginTencent.updateMyProfile({
...
});
} catch (err) {
// 收到 IM 登录异常的情况下,进行进一步处理
// 比如:提示用户重试 或 提示登录im失败 或 提示登录im的账号信息有误
}
```
---

#### 经典组合UI的使用方式
android / ios 平台
##### 因为手机屏幕宽度有限,你可以在宽屏幕设备上采用这种组合方式。比如:平板、横屏手机、折叠手机
###### 屏幕适配逻辑你自己实现
```dart
import 'package:im_plugin_tencent/pages_native/conversation_list_page_widget.dart';
import 'package:im_plugin_tencent/pages_native/chat_page_widget.dart';
Row(
children: [
SizedBox(
width: 300,
// 组件内提供了丰富的参数以及样式配置,有注释说明,请自行探索
child: ConversationListPageWidget(),
),
Expanded(
// ChatPageWidget 是不带AppBar的组件,如果需要带AppBar的,可以使用 ChatPage()
child: ChatPageWidget(),
),
],
)
// 带AppBar的聊天页面
import 'package:im_plugin_tencent/pages_native/chat_page.dart';
ChatPage()
```
如果需要手动触发会话数据列表的刷新,可以调用以下方法
```dart
import 'package:im_plugin_tencent/pages_native/handlers/conversation_list.dart';
// 该方法调用就行,你可以不去接收该方法的返回值。因为方法内会自动将请求到的会话数据列表在你配置筛选配置的情况下(不配置则不走过滤)进行合并,自动更新到当前的会话列表中
ConversationListTool.getConversationList(
...
);
```
web 平台
```dart
import 'package:im_plugin_tencent/widget/conversation_list.dart';
import 'package:im_plugin_tencent/widget/chat.dart';
Row(
children: [
SizedBox(
width: 300,
child: ConversationListWidget(),
),
Expanded(
child: ChatWidget(),
),
],
)
```
---

#### 会话列表UI的使用方式(附:去到聊天页的方法、结束会话的方式说明)
android / ios 平台
```dart
import 'package:im_plugin_tencent/pages_native/conversation_list_page_widget.dart';
ConversationListPageWidget({
// 获取腾讯IM会话的分页每页数量,如果需要一次性获取全部,可以传入一个相对大的数字
int pageCount = 50,
// 是否允许加载更多。默认允许
bool allowLoadMore = true,
// EasyRefresh组件下拉刷新的头部
Header? easyRefreshHeader,
// EasyRefresh组件下拉刷新的底部
Footer? easyRefreshFooter,
// 会话列表组件样式参数配置。如果需要交由组件内接管展示会话列表,可选择是否传入该参数控制一些样式
ConversationItemWidgetConfig? conversationItemWidgetConfig,
// 会话列表组件构造器,如果需要完全自定义会话列表组件展示,可传入该参数。不传入则由组件内接管展示会话列表
ConversationItemWidgetBuilder? itemBuilder,
// 会话列表 padding,默认 EdgeInsets.zero
EdgeInsets? conversationListPadding,
// 会话列表为空时,展示的内容
Widget? conversationListEmptyWidget,
})
```
##### 正常情况下,内部已实现了跳转聊天页面的逻辑
##### 但如果你自己实现了 ConversationListPageWidget 的 itemBuilder 参数配置,内部的自动跳转就失效了,需要你自己调用方法去打开聊天页面
可调用以下方法
```dart
import 'package:im_plugin_tencent/utils/ui_tool.dart';
ImPluginTencentUiTool.toChatPage(
context,
conversationData: (会话列表中的会话数据项),
// 其他参数以及样式配置自行探索
// 可以做到:
// 1、是跳转过去还是替换当前页面再跳转过去
// 2、修改标题栏的样式以及显示内容,设置副标题。增加标题栏右侧操作区域
// 3、设置整个页面的背景色
// 4、给标题栏下方增加自定义内容
// 5、设置底部输入区域的样式以及显示配置
// 6、给底部消息输入框上方 / 下方增加自定义内容
// 7、自定义更多操作面板中的内容(点击聊天输入框后 + 号图标展开的面板)
// 8、设置用户头像加载失败时显示的默认头像(可根据用户信息判断显示不同的)
// 9、设置消息构建器
// ... 还有其他的配置,自行探索吧骚年
...
)
```
###### 跳转聊天之前,有一些情况你需要注意
- 情况1:如果你在跳转聊天页的时候,暂时没有im的会话数据,只有你的业务数据,可通过以下方法获取im的会话数据
```dart
import 'package:im_plugin_tencent/pages_native/handlers/conversation_list.dart';
ConversationListTool.findConversation(convId, { bool needRefreshConversationList = true, int? pageCount });
```
- 情况2:比如你需要在创建会话后就立刻跳到聊天页中。此时会话列表中,会话数据可能会缺少你的业务数据,或业务数据不是最新。你可以在调用 `ImPluginTencentUiTool.toChatPage` 方法之前,通过以下方法将跟会话有关的业务数据设置到会话数据缓存中,必备不时之需(可选)。
```dart
import 'package:im_plugin_tencent/pages_native/handlers/conversation_list.dart';
ConversationListTool.setUserDataToConversationItemData(convId, { required String key, dynamic data, bool force = false });
```
###### ✌️✌️✌️ 聊天组件内已帮你实现了以下功能,可以开箱即用,非常舒服
- 消息不满一屏时展示在上方,消息满一屏后正常显示
- 下滑到顶后自动触发拉取更多历史聊天记录
- 下次打开直接先展示缓存的聊天消息,感觉加载好快啊,用户很喜欢
- 如果最新消息紧靠列表底部时(有阈值可控制),则打开消息发送输入输入法或打开更多面板,聊天消息列表跟随滚动上去
- 如果不是紧靠列表底部(有阈值可控制),则打开消息发送输入输入法或打开更多面板后,聊天消息列表不会滚动,视觉上会停留,不会影响用户查看历史聊天消息
- 定格聊天消息滚动的情况下,出现新的消息,下方会出现有新消息的提示浮层,点击可直达最新消息
- 处理好了输入法弹出与更多面板的展示过渡,非常自然
- 处理好了消息时间的展示,并且已为你格式化好了时间,每个一段时间可再次显示时间信息(间隔时间可通过参数调整)
- 总之,非常牛逼 😁🤦♂️🤦♂️
##### 如果你要结束某一个会话,请调用以下方法
- 如果你有自己的业务,调用自己业务的结束咨询方法其实就行了,腾讯 IM 会话或群聊在就在吧,无所谓,因为后面再刷新请求会话列表的时候,会再次调用你的业务筛选方法,将这种结束咨询的会话筛掉就行了。
- 但如果你非要删除会话或解散群聊,可以调用下面的方法:
```dart
// 正在努力完善文档中
```
##### 如果你要发起音视频通话邀请,请调用以下方法
```dart
import 'package:im_plugin_tencent/pages_native/handlers/call.dart';
// 已实现了应用内小窗模式,牛逼就完了
CallTool.startCall(
context,
callType: CallType.,
// 给谁打,就写谁的 im userId 进去,可以多人
userIds: [],
// 其他参数,自行探索
...
)
```
###### 请注意:如果要使用应用内小窗口模式,需要调用以下的初始化代码
```dart
/// 需要在程序启动时,在 runApp 之前调用,传入 主入口 MaterialApp 中设置的全局路由 key
ImCallFloatingWindowManager.configure(navigatorKey: xxx)
// 你的入口或许是这样
MaterialApp(
navigatorKey: xxx,
...
)
```
web 平台
```dart
import 'package:im_plugin_tencent/widget/conversation_list.dart';
SizedBox(
width: 300,
child: ConversationListWidget(),
)
```
---

#### 聊天窗口UI的使用方式
android / ios 平台
```dart
// 不带AppBar的聊天页面
import 'package:im_plugin_tencent/pages_native/chat_page_widget.dart';
ChatPageWidget()
// 带AppBar的聊天页面
import 'package:im_plugin_tencent/pages_native/chat_page.dart';
ChatPage()
```
web 平台
```dart
import 'package:im_plugin_tencent/widget/chat.dart';
SizedBox(
width: 800,
child: ChatWidget(),
)
```
---
### 仅 API 调用的方式
#### 初始化IM
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
import 'package:im_plugin_tencent/im/event_chat_listener_config.dart';
import 'package:im_plugin_tencent/im/event_call_listener_config.dart';
ImPluginTencentWeb.initSdk(
sdkAppID: 0,
initCall: true, // 是否同时初始化 im Call,默认 true
eventChatListener: EventChatListenerConfig(),
eventCallListener: EventCallListenerConfig(), // initCall 为 false 时,可以忽略
);
```
[chat 可传入的事件列表](https://web.sdk.qcloud.com/im/doc/v3/zh-cn/module-EVENT.html)
[call 可传入的事件列表](https://web.sdk.qcloud.com/component/trtccalling/doc/TUICallEngine/web/zh-cn/module-TUICallEvent.html)
#### 登录IM
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
await ImPluginTencentWeb.login(
userID: '',
userSig: '',
);
} catch(err) {
print('登录出错:$err');
}
```
#### 登出IM
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
await ImPluginTencentWeb.logout();
} catch(err) {
print('登出出错:$err');
}
```
#### 销毁IM
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
await ImPluginTencentWeb.destroy();
} catch(err) {
print('销毁出错:$err');
}
```
#### 查询自己的资料
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
final res = await ImPluginTencentWeb.getMyProfile();
} catch(err) {
print('查询自己的资料出错:$err');
}
```
#### 查询其他用户资料
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
final res = await ImPluginTencentWeb.getUserProfile(List userIdList);
} catch(err) {
print('查询其他用户资料出错:$err');
}
```
#### 更新个人资料
[web 平台 官方文档](https://cloud.tencent.com/document/product/269/75417#.E6.9B.B4.E6.96.B0.E4.B8.AA.E4.BA.BA.E8.B5.84.E6.96.99)
[安卓/IOS 平台 官方文档](https://cloud.tencent.com/document/product/269/75418#.E6.9F.A5.E8.AF.A2.E5.92.8C.E4.BF.AE.E6.94.B9.E8.87.AA.E5.B7.B1.E7.9A.84.E8.B5.84.E6.96.99)
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
final res = await ImPluginTencentWeb.updateMyProfile(Map options);
} catch(err) {
print('更新个人资料出错:$err');
}
```
#### 获取会话列表
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
import 'package:im_plugin_tencent/model/conversation_item_entity.dart';
try {
final res = await ImPluginTencentWeb.getConversationList();
List list = res['conversationList'];
List getConversationList = list.map((item) => ConversationItemEntity.fromJson(item)).toList();
} catch(err) {
print('获取会话列表出错:$err');
}
```
#### 清空会话未读消息数
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
ImPluginTencentWeb.setMessageRead({
required String conversationID // 会话ID
});
```
#### 拉取消息列表
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
import 'package:im_plugin_tencent/model/message_item_entity.dart';
try {
final res = await ImPluginTencentWeb.getMessageList({
required String conversationID, // 会话ID
String? nextReqMessageID // 拉取下一页时传入。传入上一次请求拿到的 nextReqMessageID
});
List messageList = res['messageList'];
String nextReqMessageID = res['nextReqMessageID'];
List getMsgList = messageList.map((item) => MessageItemEntity.fromJson(item)).toList();
} catch(err) {
print('拉取消息列表出错:$err');
}
```
#### 发送消息
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
import 'package:im_plugin_tencent/im/create_msg_info.dart';
import 'package:im_plugin_tencent/model/message_item_entity.dart';
try {
final res = await ImPluginTencentWeb.sendMessage({
required CreateMsgType createMsgType, // 发送消息的类型
required CreateMsgInfo createMsgInfo, // 发送消息的数据构造
Map? options // 发送消息的配置参数
});
Map msg = Map.from(res['message']);
MessageItemEntity messageInfo = MessageItemEntity.fromJson(msg);
} catch(err) {
print('发送消息出错:$err');
}
```
[创建消息参考](https://cloud.tencent.com/document/product/269/75316#.E5.8F.91.E9.80.81.E6.B6.88.E6.81.AF)
#### 拨打音视频通话
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
final res = await ImPluginTencentWeb.call({
required CallType callType,
required List userIdList, // 邀请列表
String? chatGroupId, // IM 群组 / 会话 ID
String? roomId, // 房间号
String? userData, // 扩展字段: 用于在邀请信令中增加扩展信息
Map? offlinePushInfo
});
} catch(err) {
print('拨打音视频通话出错:$err');
}
```
#### 接听通话邀请
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
final res = await ImPluginTencentWeb.acceptCall();
} catch(err) {
print('接听通话邀请出错:$err');
}
```
#### 拒绝通话邀请
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
final res = await ImPluginTencentWeb.rejectCall();
} catch(err) {
print('拒绝通话邀请出错:$err');
}
```
#### 主动加入通话
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
final res = await ImPluginTencentWeb.joinCall(String callId);
} catch(err) {
print('主动加入通话出错:$err');
}
```
#### 挂断通话
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
final res = await ImPluginTencentWeb.hangup();
} catch(err) {
print('挂断通话出错:$err');
}
```
#### 打开麦克风
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
final res = await ImPluginTencentWeb.openMicrophone();
} catch(err) {
print('打开麦克风出错:$err');
}
```
#### 关闭麦克风
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
final res = await ImPluginTencentWeb.closeMicrophone();
} catch(err) {
print('关闭麦克风出错:$err');
}
```
#### 打开自己的摄像头
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
// 该方法使用方式仅限于web端
final res = await ImPluginTencentWeb.openSelfCamera(String renderCameraDomId);
} catch(err) {
print('打开自己的摄像头出错:$err');
}
```
#### 关闭自己的摄像头
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
final res = await ImPluginTencentWeb.closeSelfCamera();
} catch(err) {
print('关闭自己的摄像头出错:$err');
}
```
#### 渲染远端的摄像头
```dart
import 'package:im_plugin_tencent/im_plugin_tencent.dart';
try {
// 该方法使用方式仅限于web端
final res = await ImPluginTencentWeb.openRemoteCamera(String userId, String renderRemoteCameraDomId);
} catch(err) {
print('渲染远端的摄像头出错:$err');
}
```