腾讯云IM插件
集成腾讯云IM SDK,同时支持 Android 和 IOS.
🎉🎉🎉🎉🎉离线推送部分接口已实现,关注:setOfflinePushSettings
和setOfflinePushToken
🎉🎉🎉🎉🎉
错误码参考: 点我进入
IMSDK版本:
平台 | 版本 | 文档地址 |
---|---|---|
Android | v4.6.1 | Android |
IOS | v4.6.58 | IOS |
[x]初始化
[x]登录相关
[x]消息收发
[x]未读计数
[x]群组相关
[x]用户资料与关系链
[-]离线推送
[-] 腾讯云离线推送
[ ] 验证 群提示消息修改时 不能获取到具体类型的问题
[ ] 升级IM SDK版本
[ ] 优化使用文档
tencent_im_plugin: ^[最新版本号]
无需额外配置,已内部打入混淆配置
无需额外配置
节点 | 进度 | 说明 |
---|---|---|
TextMessageNode | √ | 文本消息 |
ImageMessageNode | √ | 图片消息 |
SoundMessageNode | √ | 语音消息 |
VideoMessageNode | √ | 视频消息 |
CustomMessageNode | √ | 自定义消息 |
LocationMessageNode | √ | 位置消息 |
节点 | 进度 | 说明 |
---|---|---|
TIMCustomElem | √ | 已完成 |
TIMFaceElem | - | 暂不考虑,建议使用 TIMCustomElem 代替 |
TIMFileElem | - | 暂不考虑,建议使用 TIMCustomElem 代替 |
TIMGroupSystemElem | √ | 已完成 |
TIMGroupTipsElem | √ | 已完成 |
TIMImageElem | √ | 已完成 |
TIMLocationElem | √ | 已完成 |
TIMProfileSystemElem | √ | 已完成 |
TIMSNSSystemElem | √ | 已完成 |
TIMSoundElem | √ | 已完成 |
TIMTextElem | √ | 已完成 |
TIMVideoElem | √ | 已完成 |
OtherMessageNode | √ | 已完成,仅Android(IOS能够解析,但是内容体没有数据) |
接口 | 说明 | 参数 | Android | IOS |
---|---|---|---|---|
init | 初始化 | {appid:"xxxxxx",enabledLogPrint:"是否启用日志打印",logPrintLevel:"日志打印级别"} | √ | √ |
login | 登录 | {identifier:'用户ID',userSig:'用户签名'} | √ | √ |
logout | 登出 | - | √ | √ |
getLoginUser | 获得当前登录用户ID | - | √ | √ |
initStorage | 初始化本地存储(如果这个方法在 login 后进行 await 调用,则会造成卡死) | {identifier: '用户ID'} | √ | √ |
getConversationList | 获得会话列表(如果是离线状态,则获取出来的会话列表不包含: Group、UserProfile 信息) | - | √ | √ |
getConversation | 获得单个会话(如果是离线状态,则获取出来的会话列表不包含: Group、UserProfile 信息) | {id:'会话ID',sessionType:'会话类型} | √ | √ |
getGroupInfo | 获得群信息(云端) | {id:'群ID'} | √ | √ |
getUserInfo | 获得用户信息 | {id:'用户ID',forceUpdate:"是否从云端拉取数据,默认为false"} | √ | √ |
setRead | 设置已读 | {sessionId:'会话ID',sessionType:'会话类型,枚举值:SessionType' } | √ | √ |
getMessages | 获得消息列表(如果是离线状态,则获取出来的消息不包含 UserProfile 信息) | {sessionId:'会话ID',sessionType:'会话类型,枚举值:SessionType',number:"会话数量",lastMessage:'最后一条消息'} | √ | √ |
getLocalMessages | 获得本地消息列表(如果是离线状态,则获取出来的消息不包含 UserProfile 信息) | {sessionId:'会话ID',sessionType:'会话类型,枚举值:SessionType',number:"会话数量",lastMessage:'最后一条消息'} | √ | √ |
sendMessage | 发送消息 | {sessionId:'会话ID',sessionType:'会话类型,枚举值:SessionType',ol:"是否是在线消息(无痕)",node:消息节点对象} | √ | √ |
saveMessage | 向本地消息列表中添加一条消息,但并不将其发送出去。 | {sessionId:'会话ID',sessionType:'会话类型,枚举值:SessionType',node:消息节点对象,sender:"发送人",isReaded:'是否已读'} | √ | √ |
getFriendList | 获得好友列表 | - | √ | √ |
getGroupList | 获得群组列表 | - | √ | √ |
addFriend | 添加好友 | {id:'用户ID',addType:'添加类型',remark:'备注',addWording:'请求说明',addSource:'添加来源',friendGroup:'分组名'} | √ | √ |
checkSingleFriends | 检测单个好友关系 | {id:'用户ID',type:'检测类型'} | √ | √ |
getPendencyList | 获得未决好友列表(申请中) | {type:'类型',seq:'未决列表序列号',timestamp:'翻页时间戳',numPerPage:'每页数量'} | √ | √ |
pendencyReport | 未决已读上报 | {timestamp:"时间戳"} | √ | √ |
deletePendency | 未决删除 | {id:'用户Id',type:'类型'} | √ | √ |
examinePendency | 未决审核 | {id:'用户ID',type:'类型',remark:'备注'} | √ | √ |
deleteConversation | 删除会话 | {sessionId:'会话ID',sessionType:'会话类型,枚举值:SessionType',removeCache:'是否删除本地消息缓存'} | √ | √ |
deleteLocalMessage | 删除会话内的本地聊天记录 | {sessionId:'会话ID',sessionType:'会话类型,枚举值:SessionType'} | √ | √ |
createGroup | 创建群组 | {groupId:'指定群ID',notification:'群公告',introduction:'描述',faceUrl:'头像',addOption:'入群类型',maxMemberNum:'最大成员数量',members:'成员集合',type:'类型',name:'群名',customInfo:'自定义数据'} | √ | √ |
inviteGroupMember | 邀请加入群组 | {groupId:'群ID',ids:'群成员ID'} | √ | √ |
applyJoinGroup | 申请加入群组 | {groupId:'群ID',reason:'申请说明'} | √ | √ |
quitGroup | 退出群组 | {groupId:'群ID'} | √ | √ |
deleteGroupMember | 删除群组成员 | {groupId:'群ID',ids:'用户ID集合',reason:"删除说明"} | √ | √ |
getGroupMembers | 获得群成员列表 | {groupId:'群ID'} | √ | √ |
deleteGroup | 解散群组 | {groupId:'群ID'} | √ | √ |
modifyGroupOwner | 转让群组 | {groupId:'群ID',identifier:'新群主ID'} | √ | √ |
modifyGroupInfo | 修改群组资料 | {groupId:'指定群ID',notification:'群公告',introduction:'描述',faceUrl:'头像',addOption:'入群类型',maxMemberNum:'最大成员数量(IOS不支持)',type:'类型',groupName:'群名',visable:'是否对外可见',silenceAll:'全员禁言',customInfo:'自定义信息'} | √ | √ |
modifyMemberInfo | 修改群成员资料 | {groupId:'群ID',identifier:'群成员ID',nameCard:'名片',receiveMessageOpt:'接收消息选项,注:IOS不支持',silence:'禁言时间',role:'角色',customInfo:'自定义数据'} | √ | √ |
getGroupPendencyList | 获得未决群列表 | {timestamp:'翻页时间戳',numPerPage:'每页的数量'} | √ | √ |
reportGroupPendency | 上报群未决已读 | {timestamp:'已读时间戳'} | √ | √ |
groupPendencyAccept | 群未决审核(同意)会遍历所有未决列表来获得未审核的列表,存在性能隐患 | {msg:'审核意见',groupId:'群ID',identifier:'申请人ID',addTime:'申请时间'} | √ | √ |
groupPendencyRefuse | 群未决审核(拒绝)会遍历所有未决列表来获得未审核的列表,存在性能隐患 | {msg:'审核意见',groupId:'群ID',identifier:'申请人ID',addTime:'申请时间'} | √ | √ |
getSelfProfile | 获取登录用户资料 | {forceUpdate:"是否强制走后台拉取"} | √ | √ |
modifySelfProfile | 修改登录用户资料 字段参考文档 | {params:'修改参数'} | √ | √ |
modifyFriend | 修改好友资料 字段参考文档 | {identifier:'好友ID',params:'修改参数'} | √ | √ |
deleteFriends | 删除好友 | {ids:"用户ID列表",delFriendType:'删除类型'} | √ | √ |
addBlackList | 添加到黑名单 | {ids:"用户ID列表"} | √ | √ |
deleteBlackList | 从黑名单删除 | {ids:"用户ID列表"} | √ | √ |
getBlackList | 获得黑名单列表 | - | √ | √ |
createFriendGroup | 创建好友分组 | {groupNames:'组名列表',ids:'用户列表'} | √ | √ |
deleteFriendGroup | 删除好友分组 | {groupNames:'组名列表'} | √ | √ |
addFriendsToFriendGroup | 添加好友到某个分组 | {groupName:'组名',ids:'ID列表'} | √ | √ |
deleteFriendsFromFriendGroup | 从分组删除好友 | {groupName:'组名',ids:'ID列表'} | √ | √ |
renameFriendGroup | 重命名分组 | {oldGroupName:'旧名称',newGroupName:'新名称'} | √ | √ |
getFriendGroups | 获得好友分组 | {groupNames:'组名'} | √ | √ |
revokeMessage | 撤回一条发送成功的消息 | {message:'消息对象'} | √ | √ |
removeMessage | 删除一条消息(本地) | {message:'消息对象'} | √ | √ |
setMessageCustomInt | 设置自定义整数 | {message:'消息对象',value:'自定义值'} | √ | √ |
setMessageCustomStr | 设置自定义整数 | {message:'消息对象',value:'自定义值'} | √ | √ |
downloadVideoImage | 获得视频图片(缩略图) | {message:'消息对象',path:'保存截图的路径'} | √ | √ |
downloadVideo | 获得视频 | {message:'消息对象',path:'保存视频的路径'} | √ | √ |
downloadSound | 获得语音 | {message:'消息对象',path:'保存语音的路径'} | √ | √ |
findMessage | 查找一条消息 | {sessionId:'会话ID',sessionType:'会话类型',rand:'随机码',seq:'消息系列号',timestamp:'消息时间戳',self:'是否是自己发送的消息'} | √ | √ |
setOfflinePushSettings | 设置离线推送相关设置(请保证该方法在登录后调用) | {enabled:'是否启用',c2cSound:'C2C音频文件',groupSound:'Group音频文件',videoSound:'视频邀请语音'} | √ | √ |
setOfflinePushToken | 设置离线推送相关Token(登录之后调用) | {token:'各个手机厂商的推送服务对客户端的唯一标识,需要集成各个厂商的推送服务获取',bussid:'推送证书 ID,是在 IM 控制台上生成的'} | √ | √ |
通过 TencentImPlugin.addListener
和 TencentImPlugin.removeListener
可进行事件监听
@override
vodi initState(){
super.initState();
TencentImPlugin.addListener(_messageListener);
}
@override
void dispose() {
super.dispose();
TencentImPlugin.removeListener(_messageListener);
}
_messageListener(ListenerTypeEnum type, params) {
// you code
};
注意:addListener 后,请注意在必要时进行 removeListener
注意: 本插件仅在腾讯云IM上进行封装,并未集成小米、华为等推送方的SDK,故集成离线推送时根据腾讯云文档进行集成。已封装离线推送配置方法。
如果你要集成
setOfflinePushSettings
: 设置离线推送相关设置,包含:是否启用、C2C消息语音、群聊消息语音和视频邀请语音。请保证该方法在登录后调用!
setOfflinePushToken
: 设置离线推送相关Token,token 是各个手机厂商的推送服务对客户端的唯一标识,需要集成各个厂商的推送服务获取; bussid 是推送证书 ID,是在 IM 控制台上生成的, 具体步骤请参考 https://cloud.tencent.com/document/product/269/9234
- 引入插件
xiao_mi_push_plugin: 1.0.0
-
根据 xiao_mi_push_plugin 插件文档进行配置
-
初始化以及绑定监听器
void bindXiaoMiPush(){
XiaoMiPushPlugin.addListener((type,params){
if(type == XiaoMiPushListenerTypeEnum.ReceiveRegisterResult){
TencentImPlugin.setOfflinePushToken(token: params.commandArguments[0],bussid: BUSSID);
}
});
XiaoMiPushPlugin.init(appId: APP_ID, appKey: APP_KEY);
}
- 消息接收等使用方法请参考 xiao_mi_push_plugin 插件
- 引入插件
hua_wei_push_plugin: 1.0.0
-
根据 hua_wei_push_plugin 插件文档进行配置
-
获得Token并上传到腾讯云IM
void bindHuaWeiPush() {
HuaWeiPushPlugin.getToken().then((token) {
TencentImPlugin.setOfflinePushToken(token: token, bussid: BUSSID);
}).catchError((e) {
print("华为离线推送绑定失败!");
});
}
暂无符合要求的插件
暂无符合要求的插件
暂无符合要求的插件
暂无符合要求的插件
推荐 flutter-apns
或apns_flutter
(暂未集成测试)
-
根据腾讯云文档配置证书(bussid)并下载小米推送SDK
-
在
android/app
目录创建libs
文件夹,并将小米推送SDK拷贝android/app/libs/MiPush_SDK_Client_3_7_6.jar
-
编写
app/build.gradle
文件,引入 libs 的jar包dependencies { api fileTree(include: ['*.jar'], dir: 'libs') }
-
编写
android/app/src/main/AndroidManifest.xml
文件,添加权限<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.GET_TASKS" /> <uses-permission android:name="android.permission.VIBRATE" /> <permission android:name="top.huic.tencent_im_plugin_example.permission.MIPUSH_RECEIVE" android:protectionLevel="signature" /> <uses-permission android:name="top.huic.tencent_im_plugin_example.permission.MIPUSH_RECEIVE" />
注意: 请将
top.huic.tencent_im_plugin_example
替换为你的包名 -
编写
android/app/src/main/AndroidManifest.xml
,在application
标签中添加<service android:name="com.xiaomi.push.service.XMPushService" android:enabled="true" android:process=":pushservice" /> <service android:name="com.xiaomi.push.service.XMJobService" android:enabled="true" android:exported="false" android:permission="android.permission.BIND_JOB_SERVICE" android:process=":pushservice" /> <service android:name="com.xiaomi.mipush.sdk.PushMessageHandler" android:enabled="true" android:exported="true" /> <service android:name="com.xiaomi.mipush.sdk.MessageHandleService" android:enabled="true" /> <receiver android:name="com.xiaomi.push.service.receivers.NetworkStatusReceiver" android:exported="true"> <intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver> <receiver android:name="com.xiaomi.push.service.receivers.PingReceiver" android:exported="false" android:process=":pushservice"> <intent-filter> <action android:name="com.xiaomi.push.PING_TIMER" /> </intent-filter> </receiver>
-
更改
android/app/src/main/MainActivity.java
文件,加入如下代码/** * Flutter 通知器 */ public static MethodChannel channel; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (shouldInit()) { MiPushClient.registerPush(this, APP_ID, APP_KEY); } channel = new MethodChannel(this.getFlutterEngine().getDartExecutor(), "tencent_im_plugin_example"); } /** * 通过判断手机里的所有进程是否有这个App的进程 * 从而判断该App是否有打开 * * @return 是否需要初始化 -true 需要 */ private boolean shouldInit() { // 通过ActivityManager我们可以获得系统里正在运行的activities // 包括进程(Process)等、应用程序/包、服务(Service)、任务(Task)信息。 ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE)); List<ActivityManager.RunningAppProcessInfo> processInfos = am.getRunningAppProcesses(); String mainProcessName = getPackageName(); // 获取本App的唯一标识 int myPid = android.os.Process.myPid(); // 利用一个增强for循环取出手机里的所有进程 for (ActivityManager.RunningAppProcessInfo info : processInfos) { // 通过比较进程的唯一标识和包名判断进程里是否存在该App if (info.pid == myPid && mainProcessName.equals(info.processName)) { return true; } } return false; }
-
在
android/app/src/main/
中创建包push
(非必须) -
在
android/app/src/main/push
创建类:XiaomiMsgReceiver
public class XiaomiMsgReceiver extends PushMessageReceiver { @Override public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) { String command = message.getCommand(); List<String> arguments = message.getCommandArguments(); String cmdArg1 = ((arguments != null && arguments.size() > 0) ? arguments.get(0) : null); String token = null; if (MiPushClient.COMMAND_REGISTER.equals(command)) { if (message.getResultCode() == ErrorCode.SUCCESS) { token = cmdArg1; } } // 调用通知监听器传递到Flutter层 Handler mainHandler = new Handler(Looper.getMainLooper()); String finalToken = token; mainHandler.post(() -> MainActivity.channel.invokeMethod("miPushTokenListener", finalToken)); } }
-
编写
android/app/src/main/AndroidManifest.xml
,在application
标签中添加<receiver android:exported="true" android:name="top.huic.tencent_im_plugin_example.push.XiaomiMsgReceiver"> <!--这里com.xiaomi.mipushdemo.DemoMessageRreceiver改成app中定义的完整类名--> <intent-filter> <action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE" /> </intent-filter> <intent-filter> <action android:name="com.xiaomi.mipush.MESSAGE_ARRIVED" /> </intent-filter> <intent-filter> <action android:name="com.xiaomi.mipush.ERROR" /> </intent-filter> </receiver>
top.huic.tencent_im_plugin_example.push.XiaomiMsgReceiver
修改为 XiaomiMsgReceiver的包路径 -
在 lib 目录创建
tencent_im_plugin_example.dart
class TencentImPluginExample {
static const MethodChannel _channel = const MethodChannel('tencent_im_plugin_example');
/// 小米推送TOken
static String miPushToken;
/// 设置监听器
static setListener(){
_channel.setMethodCallHandler((call) {
if (call.method == 'miPushTokenListener') {
miPushToken = call.arguments as String;
}
return null;
});
}
}
- 在程序启动后调用
TencentImPluginExample.setListener();
- 最后,在登录之后调用
setOfflinePushToken
即可,可使用 腾讯云离线推送自查工具查看是否注册成功
if(TencentImPluginExample.miPushToken != null){
await TencentImPlugin.setOfflinePushToken(token: TencentImPluginExample.miPushToken,bussid: 10301);
}
如果您要集成多个平台,那么需要频繁修改 Android 配置和 Android 代码,这对Flutter新手是极其不友好的,故计划提供分支插件(不确定什么时候):小米(已完成)、华为等推送SDK集成,如果您已经有类似插件,请告诉我,我会使用它并编写接入文档
我同时维护的还有以下插件,如果您感兴趣与我一起进行维护,请通过Github联系我,欢迎 issues 和 PR。
平台 | 插件 | 描述 | 版本 |
---|---|---|---|
Flutter | FlutterTencentImPlugin | 腾讯云IM插件 | |
Flutter | FlutterTencentRtcPlugin | 腾讯云Rtc插件 | |
Flutter | FlutterXiaoMiPushPlugin | 小米推送SDK插件 | |
Flutter | FlutterHuaWeiPushPlugin | 华为推送(HMS Push)插件 | |
Flutter | FlutterTextSpanField | 自定义文本样式输入框 | |
Flutter | FlutterClipboardListener | 粘贴板监听器 | |
Flutter | FlutterQiniucloudLivePlugin | Flutter 七牛云直播云插件 | 暂未发布,通过 git 集成 |