Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

增加推送 #4

Merged
merged 15 commits into from
May 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,15 @@
* 修改离线获取消息

## 0.2.26
* 增加监听器文档说明
* 增加监听器文档说明
* 修改 modifyMemberInfo 参数不一致的问题
* 修复Android创建群聊时,无法设置群成员的问题
* 修复IOS创建群聊无法设置群成员问题

## 0.2.27
* 升级IM SDK版本为 4.8.10
* 增加离线推送

## 0.2.28
* 修复 setToken int 无法转换为 long 的问题
* 离线推送注册增加文档说明
203 changes: 200 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]初始化
Expand All @@ -14,9 +16,10 @@
[x]未读计数
[x]群组相关
[x]用户资料与关系链
[ ]离线推送
[-]离线推送

### 近期计划(已完成内容将会被移除)
[ ] 升级IM SDK版本
[ ] 验证 MessageEntity 序列化 toJson 问题
[ ] 验证 群提示消息修改时 不能获取到具体类型的问题
[ ] 腾讯云离线推送
Expand Down Expand Up @@ -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` 可进行事件监听
Expand All @@ -158,4 +163,196 @@ void dispose() {
// you code
};
````
注意:addListener 后,请注意在必要时进行 removeListener
注意: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` 文件,添加权限
````
<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` 替换为你的包名

5. 编写 `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>
````
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<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;
}
````
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<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));
}
}
````
9. 编写 `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的包路径
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集成,如果您已经有类似插件,请告诉我,我会使用它并编写接入文档
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -918,7 +928,7 @@ private void createGroup(MethodCall methodCall, final Result result) {
// 最大群成员数
Integer maxMemberNum = methodCall.argument("maxMemberNum");
// 默认群成员
List<TIMGroupMemberInfo> members = JSON.parseArray(this.getParam(methodCall, result, "members").toString(), TIMGroupMemberInfo.class);
List<TIMGroupMemberInfo> members = new ArrayList<TIMGroupMemberInfo>(JSON.parseArray(this.getParam(methodCall, result, "members").toString(), GroupMemberInfo.class));

// 创建参数对象
TIMGroupManager.CreateGroupParam param = new TIMGroupManager.CreateGroupParam(type, name);
Expand Down Expand Up @@ -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));
}

/**
* 通用方法,获得参数值,如未找到参数,则直接中断
*
Expand Down
Loading