diff --git a/CHANGELOG.md b/CHANGELOG.md index 3447edf..c0025ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -161,4 +161,15 @@ * 修改离线获取消息 ## 0.2.26 -* 增加监听器文档说明 \ No newline at end of file +* 增加监听器文档说明 +* 修改 modifyMemberInfo 参数不一致的问题 +* 修复Android创建群聊时,无法设置群成员的问题 +* 修复IOS创建群聊无法设置群成员问题 + +## 0.2.27 +* 升级IM SDK版本为 4.8.10 +* 增加离线推送 + +## 0.2.28 +* 修复 setToken int 无法转换为 long 的问题 +* 离线推送注册增加文档说明 \ No newline at end of file diff --git a/README.md b/README.md index 3a153e5..a923f88 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,9 @@ ## Getting Started 集成腾讯云IM SDK,同时支持 Android 和 IOS -**注意:当前为测试版本,如果您要集成到正式项目,请保持关注新版本。稳定版本将大于等于 `v1.0.0`** +**🎉🎉🎉🎉🎉离线推送部分接口已实现,关注:`setOfflinePushSettings`和`setOfflinePushToken`🎉🎉🎉🎉🎉** +**注意:当前为测试版本,如果您要集成到正式项目,请保持关注新版本。稳定版本将大于等于 `v1.0.0`** +**注意:由于腾讯云IM升级了新版本,但是本插件基于上一个版本,所以浏览开发文档时请通过以下地址:[Android](https://cloud.tencent.com/document/product/269/36909) [IOS](https://cloud.tencent.com/document/product/269/36910) ,在完成基本工作后,插件将进行相应更新** ## 功能清单 [x]初始化 @@ -14,9 +16,10 @@ [x]未读计数 [x]群组相关 [x]用户资料与关系链 -[ ]离线推送 +[-]离线推送 ### 近期计划(已完成内容将会被移除) +[ ] 升级IM SDK版本 [ ] 验证 MessageEntity 序列化 toJson 问题 [ ] 验证 群提示消息修改时 不能获取到具体类型的问题 [ ] 腾讯云离线推送 @@ -139,6 +142,8 @@ Demo截图: | 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` 可进行事件监听 @@ -158,4 +163,196 @@ void dispose() { // you code }; ```` -注意:addListener 后,请注意在必要时进行 removeListener \ No newline at end of file +注意:addListener 后,请注意在必要时进行 removeListener + +### 离线推送 +注意: 本插件仅在腾讯云IM上进行封装,并未集成小米、华为等推送方的SDK,故集成离线推送时根据腾讯云文档进行集成。已封装离线推送配置方法。 + +#### 离线推送相关接口 +`setOfflinePushSettings`: 设置离线推送相关设置,包含:是否启用、C2C消息语音、群聊消息语音和视频邀请语音。请保证该方法在登录后调用! +`setOfflinePushToken`: 设置离线推送相关Token,token 是各个手机厂商的推送服务对客户端的唯一标识,需要集成各个厂商的推送服务获取; bussid 是推送证书 ID,是在 IM 控制台上生成的, 具体步骤请参考 https://cloud.tencent.com/document/product/269/9234 + +#### 根据腾讯云IM文档进行集成第三方SDK,并配置Token +[Android](https://cloud.tencent.com/document/product/269/44516) +[IOS](https://cloud.tencent.com/document/product/269/44517) +示例: 小米推送 +1. 根据腾讯云文档配置证书(bussid)并下载小米推送SDK +2. 在 `android/app` 目录创建 `libs` 文件夹,并将小米推送SDK拷贝 + `android/app/libs/MiPush_SDK_Client_3_7_6.jar` +3. 编写 `app/build.gradle` 文件,引入 libs 的jar包 + ```` + dependencies { + api fileTree(include: ['*.jar'], dir: 'libs') + } + ```` +4. 编写 `android/app/src/main/AndroidManifest.xml` 文件,添加权限 + ```` + + + + + + + + + + + ```` + 注意: 请将 `top.huic.tencent_im_plugin_example` 替换为你的包名 + +5. 编写 `android/app/src/main/AndroidManifest.xml`,在 `application` 标签中添加 + ```` + + + + + + + + + + + + + + + + ```` +6. 更改 `android/app/src/main/MainActivity.java` 文件,加入如下代码 + ````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 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; + } + ```` +7. 在`android/app/src/main/` 中创建包 `push`(非必须) +8. 在 `android/app/src/main/push` 创建类:`XiaomiMsgReceiver` + ````java + public class XiaomiMsgReceiver extends PushMessageReceiver { + @Override + public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) { + String command = message.getCommand(); + List 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)); + } + } + ```` +9. 编写 `android/app/src/main/AndroidManifest.xml`,在 `application` 标签中添加 + ```` + + + + + + + + + + + + + ```` + `top.huic.tencent_im_plugin_example.push.XiaomiMsgReceiver` 修改为 XiaomiMsgReceiver的包路径 +10. 在 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; + }); + } + } + ```` +11. 在程序启动后调用 + ```` + TencentImPluginExample.setListener(); + ```` +12. 最后,在登录之后调用 `setOfflinePushToken` 即可,可使用 腾讯云离线推送自查工具查看是否注册成功 + ```` + if(TencentImPluginExample.miPushToken != null){ + await TencentImPlugin.setOfflinePushToken(token: TencentImPluginExample.miPushToken,bussid: 10301); + } + ```` +13. example已经集成小米推送,可参考进行配置 + + +#### 缺陷 +如果您要集成多个平台,那么需要频繁修改 Android 配置和 Android 代码,这对Flutter新手是极其不友好的,故计划提供分支插件(不确定什么时候):小米、华为等推送SDK集成,如果您已经有类似插件,请告诉我,我会使用它并编写接入文档 \ No newline at end of file diff --git a/android/src/main/java/top/huic/tencent_im_plugin/TencentImPlugin.java b/android/src/main/java/top/huic/tencent_im_plugin/TencentImPlugin.java index c7171c7..d0b62fc 100644 --- a/android/src/main/java/top/huic/tencent_im_plugin/TencentImPlugin.java +++ b/android/src/main/java/top/huic/tencent_im_plugin/TencentImPlugin.java @@ -1,6 +1,7 @@ package top.huic.tencent_im_plugin; import android.content.Context; +import android.net.Uri; import android.text.TextUtils; import android.util.Log; @@ -17,6 +18,8 @@ import com.tencent.imsdk.TIMGroupReceiveMessageOpt; import com.tencent.imsdk.TIMManager; import com.tencent.imsdk.TIMMessage; +import com.tencent.imsdk.TIMOfflinePushSettings; +import com.tencent.imsdk.TIMOfflinePushToken; import com.tencent.imsdk.TIMSdkConfig; import com.tencent.imsdk.TIMSoundElem; import com.tencent.imsdk.TIMUserConfig; @@ -59,6 +62,7 @@ import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.PluginRegistry.Registrar; import top.huic.tencent_im_plugin.entity.GroupMemberEntity; +import top.huic.tencent_im_plugin.entity.GroupMemberInfo; import top.huic.tencent_im_plugin.entity.GroupPendencyEntity; import top.huic.tencent_im_plugin.entity.GroupPendencyPageEntiity; import top.huic.tencent_im_plugin.entity.MessageEntity; @@ -302,6 +306,12 @@ public void onMethodCall(MethodCall call, Result result) { case "findMessage": this.findMessage(call, result); break; + case "setOfflinePushSettings": + this.setOfflinePushSettings(call, result); + break; + case "setOfflinePushToken": + this.setOfflinePushToken(call, result); + break; default: result.notImplemented(); break; @@ -918,7 +928,7 @@ private void createGroup(MethodCall methodCall, final Result result) { // 最大群成员数 Integer maxMemberNum = methodCall.argument("maxMemberNum"); // 默认群成员 - List members = JSON.parseArray(this.getParam(methodCall, result, "members").toString(), TIMGroupMemberInfo.class); + List members = new ArrayList(JSON.parseArray(this.getParam(methodCall, result, "members").toString(), GroupMemberInfo.class)); // 创建参数对象 TIMGroupManager.CreateGroupParam param = new TIMGroupManager.CreateGroupParam(type, name); @@ -1790,6 +1800,47 @@ public void onSuccess(final TIMMessage message) { }); } + + /** + * 腾讯云 设置离线推送设置 + * + * @param methodCall 方法调用对象 + * @param result 返回结果对象 + */ + private void setOfflinePushSettings(MethodCall methodCall, final Result result) { + TIMOfflinePushSettings settings = new TIMOfflinePushSettings(); + Boolean enabled = methodCall.argument("enabled"); + if (enabled != null) { + settings.setEnabled(true); + } + String c2cSound = methodCall.argument("c2cSound"); + if (c2cSound != null) { + settings.setC2cMsgRemindSound(Uri.fromFile(new File(c2cSound))); + } + String groupSound = methodCall.argument("groupSound"); + if (groupSound != null) { + settings.setGroupMsgRemindSound(Uri.fromFile(new File(groupSound))); + } + String videoSound = methodCall.argument("videoSound"); + if (videoSound != null) { + settings.setVideoSound(Uri.fromFile(new File(videoSound))); + } + TIMManager.getInstance().setOfflinePushSettings(settings); + result.success(null); + } + + /** + * 腾讯云 设置离线推送Token + * + * @param methodCall 方法调用对象 + * @param result 返回结果对象 + */ + private void setOfflinePushToken(MethodCall methodCall, final Result result) { + String token = this.getParam(methodCall, result, "token"); + Long bussid = Long.parseLong(this.getParam(methodCall, result, "bussid").toString()); + TIMManager.getInstance().setOfflinePushToken(new TIMOfflinePushToken(bussid, token), new VoidCallBack(result)); + } + /** * 通用方法,获得参数值,如未找到参数,则直接中断 * diff --git a/android/src/main/java/top/huic/tencent_im_plugin/entity/GroupMemberInfo.java b/android/src/main/java/top/huic/tencent_im_plugin/entity/GroupMemberInfo.java new file mode 100644 index 0000000..9ac3300 --- /dev/null +++ b/android/src/main/java/top/huic/tencent_im_plugin/entity/GroupMemberInfo.java @@ -0,0 +1,56 @@ +package top.huic.tencent_im_plugin.entity; + +import com.tencent.imsdk.TIMGroupMemberInfo; + +import java.util.Map; + +/** + * 群成员信息实体,继承自{@link TIMGroupMemberInfo},解决 fastjson 无法序列化填充问题 + * @author 蒋具宏 + */ +public class GroupMemberInfo extends TIMGroupMemberInfo { + @Override + public void setJoinTime(long joinTime) { + super.setJoinTime(joinTime); + } + + @Override + public void setRole(int role) { + super.setRole(role); + } + + @Override + public void setUser(String identifier) { + super.setUser(identifier); + } + + @Override + public void setNameCard(String nameCard) { + super.setNameCard(nameCard); + } + + @Override + public void setCustomInfo(Map customInfo) { + super.setCustomInfo(customInfo); + } + + @Override + public void setSilenceSeconds(long seconds) { + super.setSilenceSeconds(seconds); + } + + @Override + public void setTinyId(long tinyId) { + super.setTinyId(tinyId); + } + + @Override + public void setMsgFlag(long msgFlag) { + super.setMsgFlag(msgFlag); + } + + @Override + public void setMsgSeq(long msgSeq) { + super.setMsgSeq(msgSeq); + } +} diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 70ccd42..47a8e56 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -86,7 +86,8 @@ flutter { } dependencies { + api fileTree(include: ['*.jar'], dir: 'libs') testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' -} +} \ No newline at end of file diff --git a/example/android/app/libs/MiPush_SDK_Client_3_7_6.jar b/example/android/app/libs/MiPush_SDK_Client_3_7_6.jar new file mode 100644 index 0000000..7a78056 Binary files /dev/null and b/example/android/app/libs/MiPush_SDK_Client_3_7_6.jar differ diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index c6efa45..7166ff9 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -8,22 +8,36 @@ FlutterApplication and put your custom class here. --> + + + + + + + + + + + + + tools:replace="android:label"> - - + + + + + + + + + + + + diff --git a/example/android/app/src/main/java/top/huic/tencent_im_plugin_example/MainActivity.java b/example/android/app/src/main/java/top/huic/tencent_im_plugin_example/MainActivity.java index 56def8b..1a5722b 100644 --- a/example/android/app/src/main/java/top/huic/tencent_im_plugin_example/MainActivity.java +++ b/example/android/app/src/main/java/top/huic/tencent_im_plugin_example/MainActivity.java @@ -1,13 +1,63 @@ package top.huic.tencent_im_plugin_example; +import android.app.ActivityManager; +import android.content.Context; +import android.os.Bundle; + +import com.xiaomi.mipush.sdk.MiPushClient; + +import java.util.List; + import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import io.flutter.embedding.android.FlutterActivity; import io.flutter.embedding.engine.FlutterEngine; +import io.flutter.plugin.common.MethodChannel; import io.flutter.plugins.GeneratedPluginRegistrant; public class MainActivity extends FlutterActivity { - @Override - public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { - GeneratedPluginRegistrant.registerWith(flutterEngine); - } + + /** + * Flutter 通知器 + */ + public static MethodChannel channel; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (shouldInit()) { + MiPushClient.registerPush(this, "2882303761518400514", "5241840023514"); + } + 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 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; + } + + @Override + public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { + GeneratedPluginRegistrant.registerWith(flutterEngine); + } } diff --git a/example/android/app/src/main/java/top/huic/tencent_im_plugin_example/push/XiaomiMsgReceiver.java b/example/android/app/src/main/java/top/huic/tencent_im_plugin_example/push/XiaomiMsgReceiver.java new file mode 100644 index 0000000..167ca9b --- /dev/null +++ b/example/android/app/src/main/java/top/huic/tencent_im_plugin_example/push/XiaomiMsgReceiver.java @@ -0,0 +1,36 @@ +package top.huic.tencent_im_plugin_example.push; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; + +import com.xiaomi.mipush.sdk.ErrorCode; +import com.xiaomi.mipush.sdk.MiPushClient; +import com.xiaomi.mipush.sdk.MiPushCommandMessage; +import com.xiaomi.mipush.sdk.PushMessageReceiver; + +import java.util.List; + +import top.huic.tencent_im_plugin_example.MainActivity; + +public class XiaomiMsgReceiver extends PushMessageReceiver { + + @Override + public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) { + String command = message.getCommand(); + List 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)); + } +} diff --git a/example/lib/main.dart b/example/lib/main.dart index 8ebd4f5..2437e62 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,12 +1,17 @@ import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:tencent_im_plugin/tencent_im_plugin.dart'; import 'package:tencent_im_plugin/enums/log_print_level.dart'; +import 'package:tencent_im_plugin_example/tencent_im_plugin_example.dart'; import 'page/home.dart'; -void main() => runApp(MyApp()); +void main() { + // 运行程序 + runApp(MyApp()); +} class MyApp extends StatefulWidget { @override @@ -17,16 +22,10 @@ class _MyAppState extends State { @override void initState() { super.initState(); - init(); - } - - init() async { - // 初始化SDK - await TencentImPlugin.init( - appid: "1400290273", logPrintLevel: LogPrintLevel.info); - // 初始化本地存储 - await TencentImPlugin.initStorage( - identifier: "98a6f9541f1b455480bf460aa5208497"); + // 设置监听器 + TencentImPluginExample.setListener(); + // 初始化SDK(每次仅调用一次) + TencentImPlugin.init(appid: "1400294314", logPrintLevel: LogPrintLevel.info); } @override @@ -45,15 +44,18 @@ class LoginPage extends StatefulWidget { class LoginPageState extends State { /// 登录 onLogin() async { - await TencentImPlugin.initStorage( - identifier: "98a6f9541f1b455480bf460aa5208497"); + await TencentImPlugin.initStorage(identifier: "dev"); await TencentImPlugin.login( - identifier: "98a6f9541f1b455480bf460aa5208497", - userSig: - "eJwtjcsOgjAURP*lWwy5Lb3QkrjxtTDEhRgS3ZXQSiHKQ0SN8d8lwHLO5Mx8ySmK3V63JCTMBbIYs830vbPGjlgK5RuJnBqackQuIDXcB6WQgeAymJ1HVqq6thkJKQdgEljgTY1*17bVA0ccFICJdvY2MuEFSBnj84q9DpfbrtoUptrnziXZlcn62GDhNLU8Q9HLuM0DWB2en0ggvJbk9wfJKDdD", + identifier: "dev", + userSig: "eJyrVgrxCdYrSy1SslIy0jNQ0gHzM1NS80oy0zLBwimpZVDh4pTsxIKCzBQlK0MTAwMjSxNjQxOITGpFQWZRKlDc1NTUyMDAACJakpkLFrOwNLcwtDA3hJqSmQ401aDKpDQw2NnHLSo4yTjR06XAy8XSNyLJsSgt0cjALSQpqNI-syDV2aWw0MJWqRYAm*EwVg__", ); + // 注册离线推送 + if(TencentImPluginExample.miPushToken != null){ + await TencentImPlugin.setOfflinePushToken(token: TencentImPluginExample.miPushToken,bussid: 10301); + } + Navigator.push( context, new MaterialPageRoute(builder: (context) => new HomePage()), diff --git a/example/lib/page/create_group.dart b/example/lib/page/create_group.dart index ca8dc04..1a60629 100644 --- a/example/lib/page/create_group.dart +++ b/example/lib/page/create_group.dart @@ -50,7 +50,7 @@ class CreateGroupPageState extends State { faceUrl: data['faceUrl'], addOption: data['addOption'], maxMemberNum: data['maxMemberNum'], - members: [GroupMemberEntity(user: self.identifier, role: 400)], + members: [GroupMemberEntity(user: self.identifier, role: 300)], ); if (data['type'] == 'Private') { diff --git a/example/lib/tencent_im_plugin_example.dart b/example/lib/tencent_im_plugin_example.dart new file mode 100644 index 0000000..dcf6ce4 --- /dev/null +++ b/example/lib/tencent_im_plugin_example.dart @@ -0,0 +1,18 @@ +import 'package:flutter/services.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; + }); + } +} diff --git a/example/pubspec.lock b/example/pubspec.lock index e8204e6..3b74c94 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -7,42 +7,42 @@ packages: name: archive url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.11" + version: "2.0.13" args: dependency: transitive description: name: args url: "https://pub.flutter-io.cn" source: hosted - version: "1.5.2" + version: "1.6.0" async: dependency: transitive description: name: async url: "https://pub.flutter-io.cn" source: hosted - version: "2.4.0" + version: "2.4.1" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.flutter-io.cn" source: hosted - version: "1.0.5" + version: "2.0.0" charcode: dependency: transitive description: name: charcode url: "https://pub.flutter-io.cn" source: hosted - version: "1.1.2" + version: "1.1.3" collection: dependency: transitive description: name: collection url: "https://pub.flutter-io.cn" source: hosted - version: "1.14.11" + version: "1.14.12" convert: dependency: transitive description: @@ -56,7 +56,7 @@ packages: name: crypto url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.3" + version: "2.1.4" cupertino_icons: dependency: "direct main" description: @@ -106,7 +106,7 @@ packages: name: image url: "https://pub.flutter-io.cn" source: hosted - version: "2.1.4" + version: "2.1.12" image_picker: dependency: "direct main" description: @@ -156,13 +156,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.0.1" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.8.0+1" permission_handler: dependency: "direct main" description: @@ -197,7 +190,7 @@ packages: name: quiver url: "https://pub.flutter-io.cn" source: hosted - version: "2.0.5" + version: "2.1.3" sky_engine: dependency: transitive description: flutter @@ -209,7 +202,7 @@ packages: name: source_span url: "https://pub.flutter-io.cn" source: hosted - version: "1.5.5" + version: "1.7.0" stack_trace: dependency: transitive description: @@ -237,7 +230,7 @@ packages: path: ".." relative: true source: path - version: "0.2.19" + version: "0.2.27" term_glyph: dependency: transitive description: @@ -251,7 +244,7 @@ packages: name: test_api url: "https://pub.flutter-io.cn" source: hosted - version: "0.2.11" + version: "0.2.15" typed_data: dependency: transitive description: @@ -293,7 +286,7 @@ packages: name: xml url: "https://pub.flutter-io.cn" source: hosted - version: "3.5.0" + version: "3.6.1" sdks: - dart: ">=2.4.0 <3.0.0" + dart: ">=2.6.0 <3.0.0" flutter: ">=1.12.13+hotfix.4 <2.0.0" diff --git a/ios/Classes/SwiftTencentImPlugin.swift b/ios/Classes/SwiftTencentImPlugin.swift index fa5d5bf..b93632f 100644 --- a/ios/Classes/SwiftTencentImPlugin.swift +++ b/ios/Classes/SwiftTencentImPlugin.swift @@ -198,6 +198,12 @@ public class SwiftTencentImPlugin: NSObject, FlutterPlugin, TIMUserStatusListene case "findMessage": self.findMessage(call: call, result: result); break; + case "setOfflinePushSettings": + self.setOfflinePushSettings(call: call, result: result); + break; + case "setOfflinePushToken": + self.setOfflinePushToken(call: call, result: result); + break; default: result(FlutterMethodNotImplemented); } @@ -768,9 +774,13 @@ public class SwiftTencentImPlugin: NSObject, FlutterPlugin, TIMUserStatusListene groupInfo.maxMemberNum = maxMemberNum!; } if members != nil { + var memberInfo: [TIMCreateGroupMemberInfo] = []; if let ms = [GroupMemberEntity].deserialize(from: members) { - print(ms); + for item in ms { + memberInfo.append(item!.toTIMCreateGroupMemberInfo()); + } } + groupInfo.membersInfo = memberInfo; } groupInfo.groupType = type; groupInfo.groupName = name; @@ -1687,6 +1697,51 @@ public class SwiftTencentImPlugin: NSObject, FlutterPlugin, TIMUserStatusListene }); } + /** + * 设置离线推送配置 + */ + private func setOfflinePushSettings(call: FlutterMethodCall, result: @escaping FlutterResult) { + let enabled = ((call.arguments as! [String: Any])["enabled"]) as? Bool; + let c2cSound = ((call.arguments as! [String: Any])["c2cSound"]) as? String; + let groupSound = ((call.arguments as! [String: Any])["groupSound"]) as? String; + let videoSound = ((call.arguments as! [String: Any])["videoSound"]) as? String; + + + let config = TIMAPNSConfig(); + if enabled != nil { + config.openPush = enabled! == true ? 1 : 2; + } + if c2cSound != nil { + config.c2cSound = c2cSound!; + } + if groupSound != nil { + config.groupSound = groupSound!; + } + if videoSound != nil { + config.videoSound = videoSound!; + } + + TIMManager.sharedInstance().setAPNS(config, succ: { + result(nil); + }, fail: TencentImUtils.returnErrorClosures(result: result)) + } + + /** + * 设置离线推送Token + */ + private func setOfflinePushToken(call: FlutterMethodCall, result: @escaping FlutterResult) { + if let token = CommonUtils.getParam(call: call, result: result, param: "token") as? String, + let bussid = CommonUtils.getParam(call: call, result: result, param: "bussid") as? UInt32 { + + let config = TIMTokenParam(); + config.token = token.data(using: String.Encoding.utf8); + config.busiId = bussid; + TIMManager.sharedInstance().setToken(config, succ: { + result(nil); + }, fail: TencentImUtils.returnErrorClosures(result: result)) + } + } + /** * 调用监听器 diff --git a/ios/Classes/entity/GroupMemberEntity.swift b/ios/Classes/entity/GroupMemberEntity.swift index c8fd37a..7e449d4 100644 --- a/ios/Classes/entity/GroupMemberEntity.swift +++ b/ios/Classes/entity/GroupMemberEntity.swift @@ -1,20 +1,21 @@ import ImSDK; + import HandyJSON // Created by 蒋具宏 on 2020/2/14. // 群成员实体 -public class GroupMemberEntity : NSObject,HandyJSON{ - var role : Int?; - var silenceSeconds : UInt32? - var joinTime : time_t?; - var nameCard : String?; - var user : String?; - var userProfile : UserInfoEntity?; - +public class GroupMemberEntity: NSObject, HandyJSON { + var role: Int?; + var silenceSeconds: UInt32? + var joinTime: time_t?; + var nameCard: String?; + var user: String?; + var userProfile: UserInfoEntity?; + required public override init() { - } - - init(info : TIMGroupMemberInfo) { + } + + init(info: TIMGroupMemberInfo) { super.init(); self.role = info.role.rawValue; self.silenceSeconds = info.silentUntil; @@ -22,4 +23,16 @@ public class GroupMemberEntity : NSObject,HandyJSON{ self.nameCard = info.nameCard; self.user = info.member; } + + /// 将 [GroupMemberEntity] 实体转换为腾讯云创建群成员信息实体 + func toTIMCreateGroupMemberInfo() -> TIMCreateGroupMemberInfo { + let tgm = TIMCreateGroupMemberInfo(); + if let role = self.role { + tgm.role = TIMGroupMemberRole.init(rawValue: role)!; + } + if let user = self.user { + tgm.member = user; + } + return tgm; + } } diff --git a/lib/tencent_im_plugin.dart b/lib/tencent_im_plugin.dart index fe49e9f..263e005 100644 --- a/lib/tencent_im_plugin.dart +++ b/lib/tencent_im_plugin.dart @@ -358,24 +358,24 @@ class TencentImPlugin { /// 修改群成员资料 static Future modifyMemberInfo({ - @required String name, // 群名称 + @required String groupId, // 群ID @required String identifier, // 成员ID String nameCard, // 成员名片 int silence, // 禁言时间 int role, // 角色 ReceiveMessageOptEnum receiveMessageOpt, // 接收消息选项 + Map customInfo, // 自定义信息 }) async { return await _channel.invokeMethod('modifyMemberInfo', { - "name": name, + "groupId": groupId, "identifier": identifier, "nameCard": nameCard, "silence": silence, "role": role, + "customInfo": customInfo == null ? null : jsonEncode(customInfo), "receiveMessageOpt": receiveMessageOpt == null ? null - : receiveMessageOpt - .toString() - .replaceAll("ReceiveMessageOptEnum.", ""), + : EnumUtil.getEnumName(receiveMessageOpt), }); } @@ -772,6 +772,32 @@ class TencentImPlugin { }); } + /// 设置离线推送配置 + static Future setOfflinePushSettings({ + bool enabled, // 是否启用 + String c2cSound, // C2C音频文件 + String groupSound, // Group音频文件 + String videoSound, // 视频邀请音频文件 + }) async { + return await _channel.invokeMethod('setOfflinePushSettings', { + "enabled": enabled, + "c2cSound": c2cSound, + "groupSound": groupSound, + "videoSound": videoSound, + }); + } + + /// 设置离线推送Token + static Future setOfflinePushToken({ + String token, // Token + int bussid, // 推送证书 ID,是在 IM 控制台上生成的 + }) async { + return await _channel.invokeMethod('setOfflinePushToken', { + "token": token, + "bussid": bussid, + }); + } + /// 添加消息监听 static void addListener(ListenerValue func) { if (listener == null) { diff --git a/pubspec.yaml b/pubspec.yaml index b1a2202..4c9d279 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: tencent_im_plugin description: This plug-in integrates Tencent cloud 'imsdk', realizes cross platform im access, and is compatible with Android and IOS devices. -version: 0.2.25 +version: 0.2.28 author: 690717394@qq.com homepage: https://github.com/JiangJuHong/FlutterTencentImPlugin