fix:update docs

This commit is contained in:
SL 2024-10-18 15:55:34 +08:00
parent 431f565a44
commit 06031432a4
37 changed files with 3770 additions and 2 deletions

View File

@ -130,7 +130,24 @@ export const sidebar: DefaultTheme.Sidebar = {
"/sdk": [
{ text: "概述", link: "/sdk/" },
{ text: "iOS", link: "/sdk/ios" },
{ text: "Android", link: "/sdk/android" },
{
text: "Android",
collapsed: true,
items: [
{ text: "说明", link: "/sdk/android/intro" },
{ text: "集成", link: "/sdk/android/integration" },
{ text: "基础", link: "/sdk/android/base" },
{ text: "消息管理", link: "/sdk/android/message" },
{ text: "最近会话管理", link: "/sdk/android/conversation" },
{ text: "频道管理", link: "/sdk/android/channel" },
{ text: "频道成员管理", link: "/sdk/android/channel_member" },
{ text: "提醒项管理", link: "/sdk/android/reminder" },
{ text: "数据源管理", link: "/sdk/android/datasource" },
{ text: "命令管理", link: "/sdk/android/cmd" },
{ text: "高级功能", link: "/sdk/android/advance" },
{ text: "示例代码", link: "https://github.com/WuKongIM/WuKongIMAndroidSDK" },
]
},
{
text: "Javascript",
collapsed: true,
@ -146,7 +163,43 @@ export const sidebar: DefaultTheme.Sidebar = {
]
},
{ text: "Uniapp", link: "/sdk/uniapp" },
{ text: "Flutter", link: "/sdk/flutter" },
{
text: "Flutter",
collapsed: true,
items: [
{ text: "说明", link: "/sdk/flutter/intro" },
{ text: "集成", link: "/sdk/flutter/integration" },
{ text: "基础", link: "/sdk/flutter/base" },
{ text: "消息管理", link: "/sdk/flutter/message" },
{ text: "最近会话管理", link: "/sdk/flutter/conversation" },
{ text: "频道管理", link: "/sdk/flutter/channel" },
{ text: "频道成员管理", link: "/sdk/flutter/channel_member" },
{ text: "提醒项管理", link: "/sdk/flutter/reminder" },
{ text: "数据源管理", link: "/sdk/flutter/datasource" },
{ text: "命令管理", link: "/sdk/flutter/cmd" },
{ text: "高级功能", link: "/sdk/flutter/advance" },
{ text: "示例代码", link: "https://github.com/WuKongIM/WuKongIMFlutterSDK" },
]
},
{
text: "HarmonyOS",
collapsed: true,
items: [
{ text: "说明", link: "/sdk/harmonyos/intro" },
{ text: "集成", link: "/sdk/harmonyos/integration" },
{ text: "基础", link: "/sdk/harmonyos/base" },
{ text: "消息管理", link: "/sdk/harmonyos/message" },
{ text: "最近会话管理", link: "/sdk/harmonyos/conversation" },
{ text: "频道管理", link: "/sdk/harmonyos/channel" },
{ text: "频道成员管理", link: "/sdk/harmonyos/channel_member" },
{ text: "提醒项管理", link: "/sdk/harmonyos/reminder" },
{ text: "数据源管理", link: "/sdk/harmonyos/datasource" },
{ text: "命令管理", link: "/sdk/harmonyos/cmd" },
{ text: "高级功能", link: "/sdk/harmonyos/advance" },
{ text: "示例代码", link: "https://github.com/WuKongIM/WuKongIMHarmonyOSSDK/tree/main/entry" },
]
},
{ text: "c", link: "/sdk/c" },
]
};

540
src/sdk/android/advance.md Normal file
View File

@ -0,0 +1,540 @@
# 高级功能
### 自定义消息
在WuKongIM 中所有的消息类型都是自定义消息
#### 自定义普通消息
下面我们以名片消息举例
##### 第一步 定义消息
定义消息对象并继承 `WKMessageContent` 并在构造方法中指定消息类型
- <font color='#999' size=2>SDK 内置消息类型可通过 `WKMsgContentType` 查看</font>
`Java`
```java
public class WKCardContent extends WKMessageContent {
public WKCardContent() {
type = 3; //指定消息类型
}
// 定义需发送给对方的字段
public String uid; // 用户ID
public String name; // 名称
public String avatar; // 头像
}
```
`Kotlin`
```kotlin
class WKCardContent : WKMessageContent() {
var uid: String = ""
var name: String = ""
var avatar: String = ""
init {
type = 3; //指定消息类型
}
}
```
- <strong><font color='red'>注意:自定义消息对象必须提供无参数的构造方法</font></strong>
##### 第二步 编码和解码
我们需要将`uid`,`name`,`avatar`三个字段信息发送给对方,最终传递的消息内容为
```json
{
"type": 3,
"uid": "xxxx",
"name": "xxx",
"avatar": "xxx"
}
```
重写`WKMessageContent``encodeMsg`方法开始编码
`Java`
```java
@Override
public JSONObject encodeMsg() {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("uid", uid);
jsonObject.put("name", name);
jsonObject.put("avatar", avatar);
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObject;
}
```
`Kotlin`
```kotlin
override fun encodeMsg(): JSONObject {
val jsonObject = JSONObject()
jsonObject.put("uid", uid)
jsonObject.put("name", name)
jsonObject.put("avatar", avatar)
return jsonObject
}
```
重写`WKMessageContent``decodeMsg`方法开始解码
`Java`
```java
@Override
public WKMessageContent decodeMsg(JSONObject jsonObject) {
uid = jsonObject.optString("uid");
name = jsonObject.optString("name");
avatar = jsonObject.optString("avatar");
return this;
}
```
`Kotlin`
```kotlin
override fun decodeMsg(jsonObject: JSONObject): WKMessageContent {
this.uid = jsonObject.optString("uid")
this.name = jsonObject.optString("name")
this.avatar = jsonObject.optString("avatar")
return this
}
```
- <font color='#999' size=2>解码和编码消息时无需将 `type` 字段考虑其中sdk 内部会自动处理</font>
如果您想控制该自定义消息在获取时显示的内容可重写 `getDisplayContent` 方法
`Java`
```java
@Override
public String getDisplayContent() {
return "[名片消息]";
}
```
`Kotlin`
```kotlin
override fun getDisplayContent(): String {
return "[名片消息]"
}
```
如果你想在全局搜索时能搜索到该类型的消息,可重写`getSearchableWord` 方法
`Java`
```java
@Override
public String getSearchableWord() {
return "[名片]";
}
```
`Kotlin`
```
override fun getSearchableWord(): String {
return "[名片]"
}
```
##### 第三步 注册消息
`Java`
```java
WKIM.getInstance().getMsgManager().registerContentMsg(WKCardContent.class);
```
`Kotlin`
```kotlin
WKIM.getInstance().msgManager.registerContentMsg(WKCardContent::class.java)
```
对此通过这三步自定义普通消息就已完成。在收到消息时`WKMsg`中的type为3就表示该消息是名片消息其中`baseContentMsgModel`则为自定义的`WKCardContent`,这时可将`baseContentMsgModel`强转为`WKCardContent`并渲染到UI上
#### 自定义附件消息
我们在发送消息的时候有时需发送带附件的消息。WuKongIM 也提供自定义附件消息,自定义附件消息和普通消息区别不大。下面我们已地理位置消息举例
##### 第一步 定义消息
值得注意的是自定义附件消息需继承`WKMediaMessageContent`而不是`WKMessageContent`
`Java`
```java
public class WKLocationContent extends WKMediaMessageContent {
// 定义需发送给对方的字段
public double longitude; // 经度
public double latitude; // 纬度
public String address; // 地址详细信息
public WKLocationContent(double longitude, double latitude, String address) {
type = 6;
this.longitude = longitude;
this.latitude = latitude;
this.address = address;
}
// 这里必须提供无参数的构造方法
public WKLocationContent() {
type = 6;
}
}
```
`Kotlin`
```kotlin
class WKLocationContent(var longitude: Double, var latitude: Double, var address: String) :
WKMediaMessageContent() {
init {
type = 6 //指定消息类型
}
}
```
- <font color='#999' size=2>`WKMediaMessageContent`提供了`url``localPath`字段,自定义消息无需在定义网络地址和本地地址字段</font>
##### 第二步 编码和解码
我们需要将`longitude`,`latitude`,`address`,`url`信息发送给对方,最终传递的消息内容为
```json
{
"type": 6,
"longitude": 115.25,
"latitude": 39.26,
"url": "xxx",
"address": "xxx"
}
```
重写`WKMessageContent``encodeMsg`方法开始编码
`Java`
```java
@Override
public JSONObject encodeMsg() {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("address", address);
jsonObject.put("latitude", latitude);
jsonObject.put("longitude", longitude);
jsonObject.put("url", url); // 位置截图
jsonObject.put("localPath", localPath);
} catch (JSONException e) {
e.printStackTrace();
}
return jsonObject;
}
```
`Kotlin`
```kotlin
override fun encodeMsg(): JSONObject {
val jsonObject = JSONObject()
jsonObject.put("longitude", longitude)
jsonObject.put("latitude", latitude)
jsonObject.put("address", address)
jsonObject.put("url", url)
jsonObject.put("localPath", localPath)
return jsonObject
}
```
- <font color='#999' size=2>编码消息可以写入`localPath`本地字段sdk 在保存完消息时发送给对方的消息是不包含该字段的</font>
重写`WKMessageContent``decodeMsg`方法开始解码
`Java`
```java
@Override
public WKMessageContent decodeMsg(JSONObject jsonObject) {
latitude = jsonObject.optDouble("latitude");
longitude = jsonObject.optDouble("longitude");
address = jsonObject.optString("address");
url = jsonObject.optString("url");
if (jsonObject.has("localPath"))
localPath = jsonObject.optString("localPath");
return this;
}
```
`Kotlin`
```kotlin
override fun decodeMsg(jsonObject: JSONObject): WKMessageContent {
this.latitude = jsonObject.optDouble("latitude")
this.longitude = jsonObject.optDouble("longitude")
this.address = jsonObject.optString("address")
this.url = jsonObject.optString("url")
if (jsonObject.has("localPath"))
this.localPath = jsonObject.optString("localPath")
return this
}
```
- <font color='#999' size=2>在解码消息时如果是解码本地字段需判断该字段是否存在,因为收到的消息并没有本地字段。如`localPath`在收到消息时是没有的</font>
##### 第三步 注册消息
`Java`
```java
WKIM.getInstance().getMsgManager().registerContentMsg(WKLocationContent.class);
```
`Kotlin`
```kotlin
WKIM.getInstance().msgManager.registerContentMsg(WKLocationContent::class.java)
```
### 消息扩展
随着业务的发展应用在聊天中的功能也日益增多,为了满足绝大部分的需求 WuKongIM 中增加了消息扩展功能。消息扩展分`本地扩展``远程扩展`,本地扩展只针对 app 本地使用卸载 app 后将丢失,远程扩展是服务器保存卸载重装后数据将恢复
#### 本地扩展
本地扩展就是消息对象`WKMsg`中的`localExtraMap`字段
`Java`
```java
/**
* 修改消息本地扩展
*
* @param clientMsgNo 客户端ID
* @param hashExtra 扩展字段
*/
WKIM.getInstance().getMsgManager().updateLocalExtraWithClientMsgNo(String clientMsgNo, HashMap<String, Object> hashExtra);
```
`Kotlin`
```kotlin
WKIM.getInstance().msgManager.updateLocalExtraWithClientMsgNo( clientMsgNo,hashExtra)
```
- <font color='#999' size=2>更新成功后 sdk 会触发刷新消息回调</font>
#### 远程扩展
远程扩展就是消息对象`WKMsg`中的`remoteExtra`字段
`Java`
```java
/**
* 保存远程扩展
* @param channel 某个channel信息
* @param list 远程扩展数据
*/
WKIM.getInstance().getMsgManager().saveRemoteExtraMsg(WKChannel channel, List<WKSyncExtraMsg> list);
```
`Kotlin`
```kotlin
WKIM.getInstance().msgManager.saveRemoteExtraMsg(channel, list)
```
- <font color='#999' size=2>更新成功后 sdk 会触发刷新消息回调</font>
##### 数据结构说明
```java
public class WKMsgExtra {
public String messageID; // 消息ID
public String channelID; // 频道ID
public byte channelType; // 频道类型
public int readed; // 是否已读
public int readedCount; // 消息已读数量
public int unreadCount; // 消息未读数量
public int revoke; // 消息是否撤回
public int isMutualDeleted; // 是否删除
public String revoker; // 消息撤回者uid
public long extraVersion; // 版本号
public long editedAt; // 消息编辑时间
public String contentEdit; // 消息编辑内容
public int needUpload; // 是否需要上传(这里指业务服务器)
public int isPinned; // 是否置顶
public WKMessageContent contentEditMsgModel; // 消息编辑内容体
}
```
### 消息已读未读
消息的已读未读又称消息回执。消息回执功能可通过 setting 进行设置
`Java`
```java
WKMsgSetting setting = new WKMsgSetting();
setting.receipt = 1; // 开启回执
WKSendOptions options = new WKSendOptions();
options.setting = setting;
// 发送消息
WKIM.getInstance().getMsgManager().sendWithOptions(@NonNull WKMessageContent contentModel, @NonNull WKChannel channel, @NonNull WKSendOptions options);
```
`Kotlin`
```kotlin
val setting = WKMsgSetting()
setting.receipt = 1 // 开启回执
val options = WKSendOptions()
options.setting = setting
// 发送消息
WKIM.getInstance().msgManager.sendWithOptions(
wkBaseContentMsgModel,channel,options
)
```
当登录用户浏览过对方发送的消息时,如果对方开启了消息回执这时需将查看过的消息上传到服务器标记该消息已读。当对方或者自己上传过已读消息这时服务器会下发同步消息扩展的 cmd(命令)消息`syncMessageExtra`,此时需同步最新消息扩展保存到 sdk 中
### 消息编辑
当我们给对方发送消息发现发送内容有错误时,这时无需撤回重发只需要将消息编辑即可
<video controls height='30%' width='30%' src="/video/msgedit.mp4"></video>
#### 设置编辑内容
`Java`
```java
/**
* 修改编辑内容
* @param msgID 消息服务器ID
* @param channelID 频道ID
* @param channelType 频道类型
* @param content 编辑后的内容
*/
WKIM.getInstance().getMsgManager().updateMsgEdit(String msgID, String channelID, byte channelType, String content);
```
`Kotlin`
```kotlin
WKIM.getInstance().msgManager.updateMsgEdit(msgID,channelID,channelType,content)
```
更改 sdk 消息编辑内容后需将编辑后的内容上传到服务器,则需要监听上传消息扩展
#### 监听上传消息扩展
`Java`
```java
//监听上传消息扩展
WKIM.getInstance().getMsgManager().addOnUploadMsgExtraListener(new IUploadMsgExtraListener() {
@Override
public void onUpload(WKMsgExtra msgExtra) {
// 上传到自己的服务器
}
});
```
`Kotlin`
```kotlin
WKIM.getInstance().msgManager.addOnUploadMsgExtraListener(object :IUploadMsgExtraListener{
override fun onUpload(msgExtra: WKMsgExtra) {
// 上传到服务器
}
})
```
### 消息回复
在聊天中如果消息过多,发送消息回复就会显得消息很乱无章可循。这时就需要对某条消息进行特定的回复,即消息回复,如以下效果 <img src='./msg_reply.jpg' width=30%/>
在发送消息时,只需将消息正文`WKMessageContent`中的`WKReply`对象赋值就能对达到消息回复效果
`WKReply` 对象核心字段
```java
public class WKReply {
// 被回复的消息根ID多级回复时的第一次回复的消息ID
public String root_mid;
// 被回复的消息ID
public String message_id;
// 被回复的MessageSeq
public long message_seq;
// 被回复者uid
public String from_uid;
// 被回复者名称
public String from_name;
// 被回复的消息体
public WKMessageContent payload;
// 被回复消息编辑后的内容
public String contentEdit;
// 被回复消息编辑后的消息实体
public WKMessageContent contentEditMsgModel;
// 编辑时间
public long editAt;
}
```
### 消息回应(点赞)
#### 保存
`java`
```java
// 保存消息回应
WKIM.getInstance().getMsgManager().saveMessageReactions(List<WKSyncMsgReaction> list)
```
`kotlin`
```kotlin
// 保存消息回应
WKIM.getInstance().msgManager.saveMessageReactions(list)
```
- <font color='#999' size=2>同一个用户对同一条消息只能做出一条回应。重复进行消息不同 emoji 的回应会做为修改回应,重复进行相同 emoji 的回应则做为删除回应</font> sdk 更新消息回应后会触发消息刷新的事件。app 需监听此事件并对 UI 进行刷新
#### 获取
`java`
```java
// 获取某条消息的回应
WKIM.getInstance().getMsgManager().getMsgReactions(String messageID);
```
`kotlin`
```kotlin
// 获取某条消息的回应
WKIM.getInstance().msgManager.getMsgReactions(messageID)
```
#### 数据结构说明
```java
public class WKMsgReaction {
public String messageID; // 消息ID
public String channelID; // 频道ID
public byte channelType; // 频道类型
public String uid; // 用户ID
public long seq; // 消息序列号
public String emoji; // 表情
public int isDeleted; // 是否删除
public String createdAt; // 创建时间
}
```

113
src/sdk/android/base.md Normal file
View File

@ -0,0 +1,113 @@
# 基础
### 初始化
在 Application 的 onCreate 方法中初始化 SDK
`Java`
```java
/**
* 初始化IM
* @param context Application Context
* @param uid 登录用户ID业务服务端在IM通讯端登记了的uid
* @param token 登录用户token业务服务端在IM通讯端登记了的token
*/
WKIM.getInstance().init(context, uid, token);
```
`Kotlin`
```kotlin
WKIM.getInstance().init(context,uid,token)
```
监听获取连接服务器 IP 和 Port 的事件
`Java`
```java
WKIM.getInstance().getConnectionManager().addOnGetIpAndPortListener(new IGetIpAndPort() {
@Override
public void getIP(IGetSocketIpAndPortListener iGetSocketIpAndPortListener) {
// 返回连接IP和端口
iGetSocketIpAndPortListener.onGetSocketIpAndPort("xxx",xxx);
}
});
```
`Kotlin`
```kotlin
WKIM.getInstance().connectionManager.addOnGetIpAndPortListener { p0 ->
p0!!.onGetSocketIpAndPort(
"172.0.0.0",
6666
)
}
```
- <font color="#999" font-size=2>返回 IM 通信端的 IP 和 IM 通信端的 TCP 端口。<font color="#FF0000">分布式可调用接口获取 IP 和 Port 后返回</font></font>
### 连接与断开
#### 连接与断开 IM
`Java`
```java
// 连接IM
WKIM.getInstance().getConnectionManager().connection();
// 断开IM
WKIM.getInstance().getConnectionManager().disconnect(isLogout);
```
`Kotlin`
```kotlin
// 连接IM
WKIM.getInstance().connectionManager.connection()
// 断开IM
WKIM.getInstance().connectionManager.disconnect(isLogout)
```
- <font color='#999'>isLogout: trueSDK 将不再进行重连 falseSDK 保持重连机制</font>
#### 连接状态监听
`Java`
```java
WKIM.getInstance().getConnectionManager().addOnConnectionStatusListener("key", new IConnectionStatus() {
@Override
public void onStatus(int status, String reason) {
if(status == WKConnectStatus.success){
// 连接成功
}else if(status == WKConnectStatus.failed){
// 连接失败
}else if(status == WKConnectStatus.connecting){
// 连接中
} else if(status == WKConnectStatus.syncMsg){
// 同步消息中
}else if(status == WKConnectStatus.noNetwork){
// 无网络
}else if(status == WKConnectStatus.kicked){
// 被踢下线 需退出应用回到登录页面
}
}
});
```
`Kotlin`
```kotlin
WKIM.getInstance().connectionManager.addOnConnectionStatusListener(
"key"
) { code, reason ->
if (code == WKConnectStatus.success){
// 连接成功
}
}
```

188
src/sdk/android/channel.md Normal file
View File

@ -0,0 +1,188 @@
# 频道管理
频道(Channel)WuKongIM 中是一个比较抽象的概念。发送消息都是先发送给频道,频道根据自己的配置规则进行投递消息,频道分频道和频道详情。 更多介绍请移步[什么是频道](/guide/initialize#频道)
### 数据源
`需要实现获取频道资料的数据源` [获取频道资料数据源](/sdk/android/datasource.html#频道资料数据源)
### 频道资料
#### 获取频道资料
`Java`
```java
// 获取channel信息 先获取内存 如果没有再从数据库获取
WKIM.getInstance().getChannelManager().getChannel(String channelID, byte channelType)
// 从远程服务器获取channel信息
WKIM.getInstance().getChannelManager().fetchChannelInfo(String channelID, byte channelType)
// 批量导入频道信息 该方法会触发channel刷新事件
WKIM.getInstance().getChannelManager().addOrUpdateChannels(List<WKChannel> list);
```
`Kotlin`
```kotlin
// 获取channel信息 先获取内存 如果没有再从数据库获取
WKIM.getInstance().channelManager.getChannel(channelID,channelType)
// 从远程服务器获取channel信息
WKIM.getInstance().channelManager.fetchChannelInfo(channelID,channelType)
// 批量导入频道信息 该方法会触发channel刷新事件
WKIM.getInstance().channelManager.addOrUpdateChannels(list)
```
#### 强制刷新频道资料
`Java`
```java
// 从远程服务器获取channel信息
WKIM.getInstance().getChannelManager().fetchChannelInfo(String channelID, byte channelType)
```
`Kotlin`
```kotlin
// 从远程服务器获取channel信息
WKIM.getInstance().channelManager.fetchChannelInfo(channelID,channelType)
```
### 事件
#### 刷新频道资料
`Java`
```java
// 监听channel刷新事件
WKIM.getInstance().getChannelManager().addOnRefreshChannelInfo("key", new IRefreshChannel() {
@Override
public void onRefreshChannel(WKChannel channel, boolean isEnd) {
//
}
});
// 移除监听
WKIM.getInstance().getChannelManager().removeRefreshChannelInfo("key");
```
`Kotlin`
```kotlin
// 监听channel刷新事件
WKIM.getInstance().channelManager.addOnRefreshChannelInfo("key", object : IRefreshChannel {
override fun onRefreshChannel(channel: WKChannel, isEnd: Boolean) {
//
}
})
// 移除监听
WKIM.getInstance().channelManager.removeRefreshChannelInfo("key");
```
- <font color='#999' size=2>key为监听的唯一标识可以为任意字符串添加监听和移出监听时需要传入相同的key</font>
#### 频道头像更新
`java`
```java
// 监听频道头像更新事件
WKIM.getInstance().getChannelManager().addOnRefreshChannelAvatar( new IRefreshChannelAvatar() {
@Override
public void onRefreshChannelAvatar(String channelID, byte channelType) {
// 头像需要本地修改
String key = UUID.randomUUID().toString().replace("-", "");
WKIM.getInstance().getChannelManager().updateAvatarCacheKey(s, b, key);
}
});
```
`kotlin`
```kotlin
// 监听频道头像更新事件
WKIM.getInstance().channelManager.addOnUpdateChannelAvatar("key", object : IRefreshChannelAvatar {
override fun onRefreshChannelAvatar(channelID: String, channelType: Int) {
//
}
})
// 移除监听
WKIM.getInstance().channelManager.removeUpdateChannelAvatar("key");
```
### 常用方法
#### 修改备注
`Java`
```java
// 修改频道备注
WKIM.getInstance().getChannelManager().updateRemark(String channelID, byte channelType, String remark)
```
`Kotlin`
```kotlin
// 修改频道备注
WKIM.getInstance().channelManager.updateRemark(channelID, channelType, remark)
```
#### 置顶/取消置顶
`Java`
```java
// 置顶频道 1.置顶 0.取消置顶
WKIM.getInstance().getChannelManager().updateTop(String channelID, byte channelType, int isTop)
```
`Kotlin`
```kotlin
// 置顶频道
WKIM.getInstance().channelManager.setTopChannel(channelID, channelType, isTop)
```
#### 保存频道资料
`java`
```java
// 保存频道资料
WKIM.getInstance().getChannelManager().saveOrUpdateChannel(WKChannel channel)
// 批量保存频道资料
WKIM.getInstance().getChannelManager().saveOrUpdateChannels(List<WKChannel> list)
```
`kotlin`
```kotlin
// 保存频道资料
WKIM.getInstance().channelManager.saveOrUpdateChannel(channel)
// 批量保存频道资料
WKIM.getInstance().channelManager.saveOrUpdateChannels( list)
```
### 数据结构说明
#### 频道属性
```java
public class WKChannel {
// 频道ID
public String channelID;
// 频道类型 1.为单聊 2.为群聊
public byte channelType;
// 频道名称
public String channelName;
// 频道备注(频道的备注名称,个人的话就是个人备注,群的话就是群别名)
public String channelRemark;
// 频道头像
public String avatar;
// 是否置顶
public int top;
// 免打扰
public int mute;
// 是否禁言
public int forbidden;
// 远程扩展
public HashMap remoteExtraMap;
// 本地扩展字段
public HashMap extraMap;
}
```

View File

@ -0,0 +1,108 @@
# 频道成员管理
### 获取频道成员列表
#### 获取成员
`java`
```java
// 获取频道内所有成员
WKIM.getInstance().getChannelMembersManager().getMembers(channelId,channelType);
// 单个频道成员
WKIM.getInstance().getChannelMembersManager().getMembers(channelId,channelType,uid);
```
`kotlin`
```kotlin
// 获取频道内所有成员
WKIM.getInstance().channelMembersManager().getMembers(channelId,channelType);
// 单个频道成员
WKIM.getInstance().channelMembersManager().getMembers(channelId,channelType,uid);
```
#### 搜索成员
`需要实现频道成员数据源` [频道成员数据源](/sdk/android/datasource.html#频道成员数据源)
`java`
```java
// 搜索频道成员列表
WKIM.getInstance().getChannelMembersManager().getWithPageOrSearch(channelId, channelType, "keyword", 1, 20, (list, isRemote) -> {
// list 成员列表
// isRemote 是否为远端数据
});
```
`kotlin`
```kotlin
// 搜索频道成员列表
WKIM.getInstance().channelMembersManager().getWithPageOrSearch(channelId, channelType, "keyword", 1, 20, (list, isRemote) -> {
// list 成员列表
// isRemote 是否为远端数据
});
```
### 常用方法
#### 保存频道成员
`java`
```java
// 批量保存成员
WKIM.getInstance().getChannelMembersManager().save(List<WKChannelMember> list);
```
`kotlin`
```kotlin
// 批量保存成员
WKIM.getInstance().channelMembersManager().save(list)
```
#### 修改备注
`java`
```java
// 修改备注
WKIM.getInstance().getChannelMembersManager().updateRemarkName(channelId, channelType, uid, remark);
```
`kotlin`
```kotlin
// 修改备注
WKIM.getInstance().channelMembersManager().updateRemarkName(channelId, channelType, uid, remark)
```
### 数据结构说明
```java
public class WKChannelMember{
//自增ID
public long id;
//频道id
public String channelID;
//频道类型
public byte channelType;
//成员id
public String memberUID;
//成员名称
public String memberName;
//成员备注
public String memberRemark;
//成员头像
public String memberAvatar;
//成员角色
public int role;
//成员状态黑名单等1正常2黑名单
public int status;
//是否删除
public int isDeleted;
//创建时间
public String createdAt;
//修改时间
public String updatedAt;
//版本
public long version;
// 机器人0否1是
public int robot;
//扩展字段
public HashMap extraMap;
// 用户备注
public String remark;
// 邀请者uid
public String memberInviteUID;
// 被禁言到期时间
public long forbiddenExpirationTime;
public String memberAvatarCacheKey;
}
```

36
src/sdk/android/cmd.md Normal file
View File

@ -0,0 +1,36 @@
# 命令管理
CMD(命令)消息只能是服务器下发客户端进行解析 cmd消息格式
### 监听cmd消息
```java
WKIM.getInstance().getCMDManager().addCmdListener("key", cmd -> {
//处理cmd消息
});
// 移出监听
WKIM.getInstance().getCMDManager().removeCmdListener("key");
```
```kotlin
WKIM.getInstance().cmdManager.addCmdListener("key", { cmd ->
//处理cmd消息
})
// 移出监听
WKIM.getInstance().cmdManager.removeCmdListener("key")
```
### 数据结构说明
```java
public class WKCMD {
// 命令ID
public String cmdKey;
// 命令参数
public JSONObject paramJsonObject;
}
```

View File

@ -0,0 +1,143 @@
# 最近会话管理
`需要实现最近会话数据源` [最近会话数据源](/sdk/android/datasource.html#最近会话数据源)
### 获取最近会话列表
#### 所有最近会话
`Java`
```java
// 查询所有最近会话
WKIM.getInstance().getConversationManager().getAll();
```
`Kotlin`
```kotlin
// 查询所有最近会话
WKIM.getInstance().conversationManager.getAll()
```
#### 新消息
只有第一次打开应用时,需要同步最近会话列表, 后续最近会话列表的变化,通过监听来获取
`Java`
```java
WKIM.getInstance().getConversationManager().addOnRefreshMsgListener("key", new IRefreshConversationMsg() {
@Override
public void onRefreshConversationMsg(WKUIConversationMsg wkUIConversationMsg, boolean isEnd) {
// wkUIConversationMsg 最近会话消息内容 UI上已有该会话需进行更新反之添加到UI上
// isEnd 为了防止频繁刷新UI当isEnd为true可刷新UI
}
});
```
`Kotlin`
```kotlin
WKIM.getInstance().conversationManager.addOnRefreshMsgListener(
"key"
) { wkUIConversationMsg, isEnd ->
// wkUIConversationMsg 最近会话消息内容 UI上已有该会话需进行更新反之添加到UI上
// isEnd 为了防止频繁刷新UI当isEnd为true可刷新UI
}
```
### 移除最近会话
#### 删除
`Java`
```java
// 删除某个最近会话
WKIM.getInstance().getConversationManager().deleteWitchChannel(String channelId, byte channelType);
```
`Kotlin`
```kotlin
// 删除某个最近会话
WKIM.getInstance().conversationManager.deleteWitchChannel(channelId, channelType)
```
#### 监听删除
在删除某个最近会话时会回调此方法
`Java`
```java
WKIM.getInstance().getConversationManager().addOnDeleteMsgListener("key", new IDeleteConversationMsg() {
@Override
public void onDelete(String channelID, byte channelType) {
// channelID 聊天频道ID
// channelType 聊天频道类型
}
});
```
`Kotlin`
```kotlin
WKIM.getInstance().conversationManager.addOnDeleteMsgListener(
"key"
) { channelID, channelType ->
// channelID 聊天频道ID
// channelType 聊天频道类型
}
```
### 常用方法
`Java`
```java
// 查询所有最近会话
WKIM.getInstance().getConversationManager().getAll();
// 修改消息红点
WKIM.getInstance().getConversationManager().updateRedDot(String channelID, byte channelType, int redDot);
// 删除某个会话
WKIM.getInstance().getConversationManager().deleteMsg(String channelId, byte channelType);
```
`Kotlin`
```kotlin
// 查询所有最近会话
WKIM.getInstance().conversationManager.getAll()
// 修改消息红点
WKIM.getInstance().conversationManager.updateRedDot( channelID, channelType, redDot)
// 删除某个会话
WKIM.getInstance().conversationManager.deleteMsg( channelId, channelType)
```
### 数据结构说明
WKUIConversationMsg 类核心数据
```java
public class WKUIConversationMsg {
// 最后一条消息时间
public long lastMsgTimestamp;
// 消息频道 频道资料,可能为空,如果为空可以调用 WKChannelManager 的 fetchChannelInfo(channelID, channelType); 触发频道信息变更
private WKChannel wkChannel;
// 消息正文
private WKMsg wkMsg;
// 未读消息数量
public int unreadCount;
// 远程扩展
private WKConversationMsgExtra remoteMsgExtra()
// 本地扩展字段
public HashMap<String, Object> localExtraMap;
// 最近会话提醒项 如[有人@你][群内审核]等
public List<WKReminder> getReminderList(){
// ...
}
// 获取远程扩展
public WKConversationMsgExtra getRemoteMsgExtra(){
// ...
}
// 会话channel信息
public WKChannel getWkChannel(){
// ...
}
}
```

View File

@ -0,0 +1,188 @@
# 数据源管理
### 文件
在自定义附件消息的时候发送给对方的消息是将网络地址发送给对方,并不是实际的文件。这个时候我们就需监听附件的上传
#### 监听上传附件
`Java`
```java
WKIM.getInstance().getMsgManager().addOnUploadAttachListener(new IUploadAttachmentListener() {
@Override
public void onUploadAttachmentListener(WKMsg wkMsg, IUploadAttacResultListener listener) {
// 在这里将未上传的文件上传到服务器并返回给sdk
if(wkMsg.type == WKMsgContentType.WK_IMAGE){
WKMediaMessageContent mediaMessageContent = (WKMediaMessageContent) wkMsg.baseContentMsgModel;
if (TextUtils.isEmpty(mediaMessageContent.url)) {
// todo 上传文件
// ...
mediaMessageContent.url = "xxxxxx"; // 设置网络地址并返回给sdk
listener.onUploadResult(true, mediaMessageContent);
}
}
}
});
```
`Kotlin`
```kotlin
WKIM.getInstance().msgManager.addOnUploadAttachListener { wkMsg, listener ->
// 在这里将未上传的文件上传到服务器并返回给sdk
if (wkMsg.type == WKMsgContentType.WK_IMAGE) {
val mediaMessageContent = wkMsg.baseContentMsgModel as WKMediaMessageContent
if (TextUtils.isEmpty(mediaMessageContent.url)) {
// todo 上传文件
// ...
mediaMessageContent.url = "xxxxxx" // 设置网络地址并返回给sdk
listener.onUploadResult(true, mediaMessageContent)
}
}
}
```
#### 监听下载附件
sdk 中不会主动下载消息的附件。在收到带有附件的消息时需要 app 自己按需下载。在 app 下载完成后可改文件本地地址,避免重复下载
`Java`
```java
/**
* 修改消息内容体
*
* @param clientMsgNo 客户端消息ID
* @param messageContent 消息module 将本地地址保存在 messageContent 中
* @param isRefreshUI 是否通知UI刷新对应消息
*/
WKIM.getInstance().getMsgManager().updateContent(String clientMsgNo, WKMessageContent messageContent, boolean isRefreshUI);
```
`Kotlin`
```kotlin
WKIMWKIM.getInstance().msgManager.updateContent(clientMsgNo, messageContent)
```
### 最近会话
#### 最近会话数据源
`Java`
```java
WKIM.getInstance().getConversationManager().addOnSyncConversationListener(new ISyncConversationChat() {
@Override
public void syncConversationChat(String last_msg_seqs, int msg_count, long version, ISyncConversationChatBack iSyncConversationChatBack) {
/**
* 同步会话
*
* @param last_msg_seqs 最近会话列表msg_seq集合
* @param msg_count 会话里面消息同步数量
* @param version 最大版本号
* @param iSyncConvChatBack 回调
*/
// 需要请求业务接口将数据返回给sdk
}
});
```
`Kotlin`
```kotlin
WKIM.getInstance().conversationManager.addOnSyncConversationListener { last_msg_seqs, msg_count, version, iSyncConversationChatBack ->
// todo 同步最近会话数据
}
```
### 频道
#### 频道资料数据源
`Java`
```java
// 监听获取channel信息
WKIM.getInstance().getChannelManager().addOnGetChannelInfoListener(new IGetChannelInfo() {
@Override
public WKChannel onGetChannelInfo(String channelID, byte channelType, IChannelInfoListener iChannelInfoListener) {
// 获取个人资料还是群资料可通过 channelType 区分
// 如果app本地有该channel信息可直接返回数据反之可获取网络数据后通过 iChannelInfoListener 返回
return null;
}
});
```
`Kotlin`
```kotlin
// 监听获取channel信息
WKIM.getInstance().channelManager.addOnGetChannelInfoListener { channelID, channelType, iChannelInfoListener ->
// 获取个人资料还是群资料可通过 channelType 区分
// 如果app本地有该channel信息可直接返回数据反之可获取网络数据后通过 iChannelInfoListener 返回
null
}
```
- <font color='#999' size=2>SDK 内置频道类型 可通过 `WKChannelType` 查看</font>
也可以批量保存频道资料信息
```java
// 批量保存频道资料信息
WKIM.getInstance().getChannelManager().saveOrUpdateChannels(channels);
```
```kotlin
// 批量保存频道资料信息
WKIM.getInstance().channelManager.saveOrUpdateChannels(channels)
```
### 频道成员
#### 频道成员数据源
`Java`
```java
// 监听获取频道成员信息
WKIM.getInstance().getChannelMembersManager().addOnGetChannelMembersListener((channelID, b, keyword, page, limit, iChannelMemberListResult) ->{
// 获取频道成员后通过 iChannelMembersListener 返回给sdk
});
```
`Kotlin`
```kotlin
// 监听获取频道成员信息
WKIM.getInstance().channelMembersManager.addOnGetChannelMembersListener { channelID, channelType, keyword, page, limit, back ->
// 获取频道成员后通过 iChannelMembersListener 返回给sdk
}
```
### 消息
#### 频道消息数据源
`Java`
```java
WKIM.getInstance().getMsgManager().addOnSyncChannelMsgListener(new ISyncChannelMsgListener() {
@Override
public void syncChannelMsgs(String channelID, byte channelType,long startMessageSeq, long endMessageSeq, int limit, int pullMode, ISyncChannelMsgBack iSyncChannelMsgBack) {
/**
* 同步某个频道的消息
*
* @param channelID 频道ID
* @param channelType 频道类型
* @param startMessageSeq 开始消息列号结果包含start_message_seq的消息
* @param endMessageSeq 结束消息列号结果不包含end_message_seq的消息
* @param limit 消息数量限制
* @param pullMode 拉取模式 0:向下拉取 1:向上拉取
* @param iSyncChannelMsgBack 请求返回
*/
}
});
```
`Kotlin`
```kotlin
WKIM.getInstance().msgManager.addOnSyncChannelMsgListener { channelID, channelType, startMessageSeq, endMessageSeq, limit, pullMode, iSyncChannelMsgBack ->
// 调用接口获取channel历史消息
// do ...
}
```

View File

@ -0,0 +1,47 @@
# 集成
## 快速入门
**Gradle**
[![](https://jitpack.io/v/WuKongIM/WuKongIMAndroidSDK.svg)](https://jitpack.io/#WuKongIM/WuKongIMAndroidSDK)
```
implementation implementation 'com.github.WuKongIM:WuKongIMAndroidSDK:version' // 版本号请看上面
```
jitpack 还需在主程序的`build.gradle`文件中添加:
```
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
```
由于 sdk 内使用了 sqlcipher 加密数据库和 curve25519 加密算法,需将库添加到项目中
```
implementation "net.zetetic:android-database-sqlcipher:4.5.3"
implementation "androidx.sqlite:sqlite-ktx:2.3.1"
implementation 'org.whispersystems:curve25519-android:0.5.0'
implementation 'org.whispersystems:signal-protocol-android:2.8.1'
```
**混淆**
```
-dontwarn com.xinbida.wukongim.**
-keep class com.xinbida.wukongim.**{*;}
#数据库加密
-keep,includedescriptorclasses class net.sqlcipher.** { *; }
-keep,includedescriptorclasses interface net.sqlcipher.** { *; }
#--------- 混淆dh curve25519-------
-keep class org.whispersystems.curve25519.**{*;}
-keep class org.whispersystems.** { *; }
-keep class org.thoughtcrime.securesms.** { *; }
```

47
src/sdk/android/intro.md Normal file
View File

@ -0,0 +1,47 @@
# 说明
## 设计理念
为了让开发者更快更方便的使用 SDK悟空 SDK 提供了一个唯一的入口来访问 SDK 中的所有功能。就像书籍的目录一样可以通过目录查找对应的内容。如连接 IM `WKIM.getInstance().getConnectionManager().connection()`
## 结构说明
![sdk结构图](./sdk.png) SDK 常用功能介绍
```java
// 消息管理器
// 负责消息的增删改查、新消息监听、刷新消息监听、消息入库、发送消息回执监听、监听同步某个聊天数据等
WKIM.getInstance().getMsgManager()
// 连接管理
// 负责IM的连接、断开、退出登录、监听连接状态、监听获取连接IP等
WKIM.getInstance().getConnectionManager()
// 频道管理
// 可获取Channel的信息刷新Channel缓存监听Channel更改[置顶、免打扰、禁言]、搜索Channel等
WKIM.getInstance().getChannelManager()
// 最近会话管理
// 获取最近聊天记录、刷新最近会话[新增聊天、红点改变]、监听移除某个会话、监听同步最近会话等
WKIM.getInstance().getConversationManager()
// 频道成员管理
// 获取Channel成员列表、设置成员备注、保存修改成员数据、监听刷新成员和移除成员等
WKIM.getInstance().getChannelMembersManager()
// 提醒管理
// 获取某个会话的提醒如:[有人@我] [入群申请] 等。还可自定义提醒项,如像 语音未读 等
WKIM.getInstance().getReminderManager()
// 命令管理
// 负责监听服务器下发的命令消息
WKIM.getInstance().getCMDManager()
// 机器人管理
// 可以获取机器人菜单、同步机器人菜单,查询菜单等
WKIM.getInstance().getRobotManager()
```
### SDK 与 APP 交互原则
![SDK与已有APP交互原则](./../sdk_app.png) sdk 与 app 交互流程就是 app 调用 sdk 提供的方法sdk 处理完数据后通过事件将数据回调给 app。如发送消息流程app 调用发送消息方法sdk 将入库后的消息 push 给 app

276
src/sdk/android/message.md Normal file
View File

@ -0,0 +1,276 @@
# 消息管理
### 发送消息
`Java`
```java
/**
*
* @param textContent 消息正文
* @param channelID 投递的频道ID
* @param channelType 投递的频道类型(个人频道,群频道,客服频道等等)
*/
WKIM.getInstance().getMsgManager().sendMessage(textContent,channelID, channelType);
```
`Kotlin`
```kotlin
WKIM.getInstance().msgManager.sendMessage(textContent,channelID, channelType)
```
- <font size=2 color="#999">sdk 内置频道类型可通过`WKChannelType`查看</font>
如给用户`A`发送一条文本消息。构建文本消息正文
`Java`
```java
WKTextContent textContent = new WKTextContent("你好,悟空");
```
`Kotlin`
```kotlin
val textContent = WKTextContent("你好,悟空")
```
将消息发送给用户`A`
`Java`
```java
WKIM.getInstance().getMsgManager().sendMessage(textContent,"A",WKChannelType.PERSONAL);
```
`Kotlin`
```kotlin
WKIM.getInstance().msgManager.sendMessage(textContent,"A",WKChannelType.PERSONAL)
```
#### 文本消息
`Java`
```java
public class WKTextContent extends WKMessageContent {
public WKTextContent(String content) {
this.content = content;
this.type = WKMsgContentType.WK_TEXT;
}
}
```
#### 图片消息
```java
public class WKImageContent extends WKMediaMessageContent {
public int width; // 宽度
public int height; // 高度
public WKImageContent(String localPath) {
this.localPath = localPath;
this.type = WKMsgContentType.WK_IMAGE;
}
}
```
- <font color="#999" size=2>在构建图片消息正文时无需传递图片的高宽。sdk 会自动获取图片高宽</font>
#### 语音消息
```java
public class WKVoiceContent extends WKMediaMessageContent {
public int timeTrad; // 语音时长
public String waveform; // 音频波浪数据 (可选参数)
public WKVoiceContent(String localPath, int timeTrad) {
this.type = WKMsgContentType.WK_VOICE;
this.timeTrad = timeTrad;
this.localPath = localPath;
}
}
```
### 消息入库返回(并不是消息发送状态)
在发送消息时sdk 将消息保存在本地数据库后就会触发入库回调。此时消息并未进行发送,可在此监听中将消息展示在 UI 上
`Java`
```java
WKIM.getInstance().getMsgManager().addOnSendMsgCallback("key", new ISendMsgCallBackListener() {
@Override
public void onInsertMsg(WKMsg wkMsg) {
// 可以在这里将保存在数据库的消息`wkMsg`展示在UI上
// ...
}
});
```
`Kotlin`
```kotlin
WKIM.getInstance().msgManager.addOnSendMsgCallback("key") { wkMsg ->
// 将消息wkMsg展示在UI上
}
```
- <font color='#999' size=2>关于事件是否传入唯一 key 说明请查看[事件监听](/sdk/android#说明)</font>
### 收到新消息监听
`Java`
```java
WKIM.getInstance().getMsgManager().addOnNewMsgListener("key", new INewMsgListener() {
@Override
public void newMsg(List<WKMsg> list) {
// list:接收到的消息
}
});
```
`Kotlin`
```kotlin
WKIM.getInstance().msgManager.addOnNewMsgListener("key") { list ->
// list:接收到的消息
}
```
- <font color='#999' size=2>如果在聊天页面内收到新消息时需判断该消息是否属于当前会话,可通过消息对象`WKMsg``channelID``channelType`判断</font>
### 刷新消息监听
在 sdk 更新过消息时消息发送状态有人点赞消息消息已读回执消息撤回消息被编辑等等sdk 都将回调以下事件。UI 可通过消息对象`WKMsg``clientMsgNO`来判断具体是哪条消息发生了更改。
`Java`
```java
WKIM.getInstance().getMsgManager().addOnRefreshMsgListener("key", new IRefreshMsg() {
@Override
public void onRefresh(WKMsg wkMsg, boolean isEnd) {
// wkMsg刷新的消息对象
// isEnd为了避免频繁刷新UI导致卡顿当isEnd为true时在刷新UI
}
});
```
`Kotlin`
```kotlin
WKIM.getInstance().msgManager.addOnRefreshMsgListener("") { wkMsg, isEnd ->
// wkMsg刷新的消息对象
// isEnd为了避免频繁刷新UI导致卡顿当isEnd为true时在刷新UI
}
```
### 查看某个频道的聊天信息
`Java`
```java
/**
* 查询或同步某个频道消息
*
* @param channelId 频道ID
* @param channelType 频道类型
* @param oldestOrderSeq 最后一次消息大orderSeq 第一次进入聊天传入0
* @param contain 是否包含 oldestOrderSeq 这条消息
* @param dropDown 是否下拉
* @param aroundMsgOrderSeq 查询此消息附近消息 如 aroundMsgOrderSeq=20 返回数据则是 [16,17,19,20,21,22,23,24,25]
* @param limit 每次获取数量
* @param iGetOrSyncHistoryMsgBack 请求返还
*/
WKIM.getInstance().getMsgManager().getOrSyncHistoryMessages(String channelId, byte channelType, long oldestOrderSeq, boolean contain, boolean dropDown, int limit, long aroundMsgOrderSeq, final IGetOrSyncHistoryMsgBack iGetOrSyncHistoryMsgBack) {
}
```
`Kotlin`
```kotlin
WKIM.getInstance().msgManager.getOrSyncHistoryMessages(channelId,channelType,oldestOrderSeq,contain,dropDown,limit,aroundMsgOrderSeq,object :IGetOrSyncHistoryMsgBack{
override fun onResult(list: MutableList<WKMsg>?) {
// list 获取到的消息 展示到UI
}
})
```
- <font color='#999' size=2>获取历史消息并不是同步方法,因为有可能存在非连续性时会往服务器同步数据</font>
代码
```java
WKIM.getInstance().getMsgManager().getOrSyncHistoryMessages(channelId, channelType, oldestOrderSeq, contain, pullMode, limit, aroundMsgOrderSeq, new IGetOrSyncHistoryMsgBack() {
@Override
public void onSyncing() {
// 正在同步中 按需显示loading
}
@Override
public void onResult(List<WKMsg> list) {
// 展示消息
}
});
```
### 离线消息接收
`需要实现同步频道消息数据源` [频道消息数据源](/sdk/android/datasource.html#频道消息数据源)
因为WuKongIM 是支持消息永久存储,所以会产生海量的离线消息。对此我们采用了按需拉取的机制,如 10 个会话一个会话 10 万条消息WuKongIM 不会把这个 10\*10 万=100 万条消息都拉取到本地。 而是采用拉取这 10 个会话的信息和对应的最新 20 条消息,也就是实际只拉取了 200 条消息 相对 100 万条消息来说大大提高了离线拉取速度。用户点进对应的会话才会去按需拉取这个会话的消息。 这些机制 SDK 内部都已做好了封装,使用者其实不需要关心。使用者只需要关心最近会话的变化和监听获取数据的回调即可。
### 数据结构说明
#### 消息类核心属性
```java
public class WKMsg {
// 服务器消息ID(全局唯一,无序)
public String messageID;
// 本地唯一ID
public String clientMsgNO;
// 服务器时间 (10位时间戳)
public long timestamp;
// 消息来源发送者
public String fromUID;
// 聊天频道ID
public String channelID;
// 聊天频道类型
public byte channelType;
// 消息正文
public WKMessageContent baseContentMsgModel;
// 消息头
public WKMsgHeader header;
// 本地扩展字段
public HashMap localExtraMap;
// 远程扩展
public WKMsgExtra remoteExtra;
...
}
```
#### 消息正文核心属性
```java
public class WKMessageContent {
// 消息内容类型
public int type;
// 消息中的@提醒信息
public WKMentionInfo mentionInfo;
// 消息回复对象
public WKReply reply;
// 编码消息 上层需实现该方法并编码
public JSONObject encodeMsg() {
return new JSONObject();
}
// 解码消息 上层需实现该方法并解码
public WKMessageContent decodeMsg(JSONObject jsonObject) {
return this;
}
...
}
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 KiB

View File

@ -0,0 +1,82 @@
# 提醒项管理
会话提醒目前只支持服务器下发指令。客户端只需监听同步会话提醒和监听刷新会话消息即可
### 获取提醒项
`java`
```java
// 获取指定会话的提醒项
List<WKReminder> allReminder = WKIM.getInstance().getReminderManager().getReminders(channelId, channelType);
// 获取指定类型的提醒项
WKIM.getInstance().getReminderManager().getRemindersWithType(String channelID, byte channelType, int type);
```
`kotlin`
```kotlin
// 获取指定会话的提醒项
val allReminder = WKIM.getInstance().reminderManager.s(channelId, channelType)
// 获取指定类型的提醒项
WKIM.getInstance().reminderManager.getRemindersWithType( channelID, channelType, type);
```
### 保存提醒项
`java`
```java
// 保存提醒项
WKIM.getInstance().getReminderManager().saveOrUpdateReminders(List<WKReminder> reminderList);
```
`kotlin`
```kotlin
// 保存提醒项
WKIM.getInstance().reminderManager.saveOrUpdateReminders(list)
```
### 事件
#### 新增提醒项
`java`
```java
// 监听新增提醒项
WKIM.getInstance().getReminderManager().addOnNewReminderListener("key", new INewReminderListener() {
@Override
public void newReminder(List<WKReminder> list) {
}
});
// 移出监听
WKIM.getInstance().getReminderManager().removeNewReminderListener("key");
```
`kotlin`
```kotlin
// 监听新增提醒项
WKIM.getInstance().reminderManager.addOnNewReminderListener("key", object : INewReminderListener {
override fun newReminder(list: List<WKReminder>) {
}
})
// 移出监听
WKIM.getInstance().reminderManager.removeNewReminderListener("key");
```
- <font color='#999' size=2>key为监听的唯一标识可以为任意字符串添加监听和移出监听时需要传入相同的key</font>
### 数据结构说明
```java
public class WKReminder {
public long reminderID; // 提醒项ID
public String messageID; // 消息ID
public String channelID; // 频道ID
public byte channelType; // 频道类型
public long messageSeq; // 消息序列号
public int type; // 提醒类型[1、有人@你][2、群内审核] 等
public String uid;
public String text; // 提醒内容
public Map data; // 提醒包含的自定义数据
public long version; // 版本号 增量同步需要用到
public int done; // 0.未完成 1.已完成
public int needUpload; // 0.不需要上传 1.需要上传
public String publisher; // 发布者
}
```

BIN
src/sdk/android/sdk.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 335 KiB

208
src/sdk/flutter/advance.md Normal file
View File

@ -0,0 +1,208 @@
# 高级功能
### 自定义消息类型
在WuKongIM 中所有的消息类型都是自定义消息。下面我们以`gif`消息举例
#### 第一步 定义消息
定义消息对象并继承 `WKMessageContent` 并在构造方法中指定消息类型
- <font color='#999' size=2>SDK 内置消息类型可通过 `WkMessageContentType` 查看</font>
**继承 `WKMessageContent` 和定义 gif 消息的正文结构**
```dart
class GifContent extends WKMessageContent{
int width=0; // 宽度
int height=0; // 高度
String url; // 远程地址
GifContent(this.url){
// 指定消息类型
contentType = WkMessageContentType.gif;
}
}
```
#### 第二步 编码解码
```dart
class GifContent extends WKMessageContent{
int c=0; // 宽度
int height=0; // 高度
String url; // 远程地址
GifContent(this.url){
// 指定消息类型
contentType = WkMessageContentType.gif;
}
@override
WKMessageContent decodeJson(Map<String, dynamic> json) {
url = readString(json, 'url');
width = readInt(json, 'width');
height = readInt(json, 'height');
return this;
}
@override
Map<String, dynamic> encodeJson() {
return {'url': url, 'width': width, 'height': height};
}
// 如果需要获取可显示内容可重写
@override
String displayText() {
return "[动态图片]";
}
}
```
- <font color='#999' size=2>解码和编码消息时无需将 `type` 字段考虑其中sdk 内部会自动处理</font>
#### 第三步 注册消息
```dart
WKIM.shared.messageManager.registerMsgContent(WkMessageContentType.gif,
(dynamic data) {
return GifContent('').decodeJson(data);
});
```
对此通过这三步自定义普通消息就已完成。在收到消息时`WKMsg`中的type为3就表示该消息是名片消息其中`messageContent`则为自定义的`GifContent`,这时可将`messageContent`强转为`GifContent`并渲染到UI上
### 自定义附件消息
我们在发送消息的时候有时需发送带附件的消息。WuKongIM 也提供自定义附件消息,自定义附件消息和普通消息区别不大。下面我们图片消息举例
#### 第一步 定义消息
值得注意的是自定义附件消息需继承`WKMediaMessageContent`而不是`WKMessageContent`
```dart
class WKImageContent extends WKMediaMessageContent {
int width; // 图片宽度
int height; // 图片高度
WKImageContent(this.width, this.height) {
contentType = WkMessageContentType.image;
}
}
```
#### 第二步 编码解码
```dart
class WKImageContent extends WKMediaMessageContent {
int width; // 图片宽度
int height; // 图片高度
WKImageContent(this.width, this.height) {
contentType = WkMessageContentType.image;
}
@override
Map<String, dynamic> encodeJson() {
return {'width': width, 'height': height, 'url': url};
}
@override
WKMessageContent decodeJson(Map<String, dynamic> json) {
width = readInt(json, 'width');
height = readInt(json, 'height');
url = readString(json, 'url');
localPath = readString(json, 'localPath');
return this;
}
}
```
#### 第三步 注册消息
```dart
WKIM.shared.messageManager.registerMsgContent(WkMessageContentType.image,
(dynamic data) {
return WKImageContent(
0,
0,
).decodeJson(data);
});
```
### 消息扩展
随着业务的发展应用在聊天中的功能也日益增多,为了满足绝大部分的需求 WuKongIM 中增加了消息扩展功能。消息扩展分`本地扩展``远程扩展`,本地扩展只针对 app 本地使用卸载 app 后将丢失,远程扩展是服务器保存卸载重装后数据将恢复
#### 本地扩展
本地扩展就是消息对象`WKMsg`中的`localExtraMap`字段
```dart
// 修改消息本地扩展
WKIM.shared.messageManager.updateLocalExtraWithClientMsgNo(String clientMsgNo,dynamic data);
```
- <font color='#999' size=2>更新成功后 sdk 会触发刷新消息回调</font>
#### 远程扩展
远程扩展就是消息对象`WKMsg`中的`wkMsgExtra`字段
```dart
// 修改消息远程扩展
WKIM.shared.messageManager.saveRemoteExtraMsg(List<WKSyncExtraMsg> list);
```
### 消息已读未读
消息的已读未读又称消息回执。消息回执功能可通过 setting 进行设置
#### 发送回执消息
```dart
Setting setting = Setting();
setting.receipt = 1; //开启回执
var option = WKSendOptions();
option.setting = setting;
// 发送消息
WKIM.shared.messageManager.sendWithOption(
text, WKChannel(channelID, channelType), option);
```
当用户浏览过对方发送的消息时,如果对方开启了消息回执这时需将查看过的消息上传到服务器标记该消息已读。当对方或者自己上传过已读消息这时服务器会下发同步消息扩展的 cmd(命令)消息,此时需同步最新消息扩展通过`WKIM.shared.messageManager.saveRemoteExtraMsg(List<WKSyncExtraMsg> list)`方法保存到 sdk 中
### 消息回复
在聊天中如果消息过多,发送消息回复就会显得消息很乱无章可循。这时就需要对某条消息进行特定的回复,即消息回复。 如以下效果
<img src='./../msg_reply.jpg' width=30%/>
在发送消息时,只需将消息正文`WKMessageContent`中的`WKReply`对象赋值就能对达到消息回复效果
#### 发送回复消息
```dart
// 回复
WKTextContent text = WKTextContent(content);
WKReply reply = WKReply();
reply.messageId = "11";
reply.rootMid = "111";
reply.fromUID = "11";
reply.fromName = "12";
WKTextContent payloadText = WKTextContent("dds");
reply.payload = payloadText;
text.reply = reply;
// 发送消息
WKIM.shared.messageManager.sendMessage( text, WKChannel(channelID, channelType));
```
### 消息回应(点赞)
当自己或者别人对消息回应(点赞)时,都会触发 cmd(命令)消息通知到应用。应用在收到同步消息回应的cmd时获取可调用服务器同步接口将获取的回应数据更新到sdk
```dart
// 保存消息回应
WKIM.shared.messageManager.saveMessageReactions(List<WKSyncMsgReaction> list);
```
- <font color='#999' size=2>同一个用户对同一条消息只能做出一条回应。重复进行消息不同 emoji 的回应会做为修改回应,重复进行相同 emoji 的回应则做为删除回应</font> sdk 更新消息回应后会触发消息刷新的事件。app 需监听此事件并对 UI 进行刷新
### 消息编辑
当我们给对方发送消息发现发送内容有错误时,这时无需撤回重发只需要将消息编辑即可
#### 设置编辑内容
```dart
WKIM.shared.messageManager.updateMsgEdit(String messageID, String channelID, int channelType,
String content);
```
更改 sdk 消息编辑内容后需将编辑后的内容上传到服务器,则需要监听上传消息扩展
#### 监听上传消息扩展
```dart
WKIM.shared.messageManager.addOnUploadMsgExtra((wkMsgExtra) => {
// 上传到自己的服务器
});
```
如果自己或者别人编辑了消息,都会触发 cmd(命令)消息app根据cmd类型判断后去同步消息扩展即可 app 需监听消息更新的事件完成对 UI 的刷新

55
src/sdk/flutter/base.md Normal file
View File

@ -0,0 +1,55 @@
# 基础
### 初始化
#### 连接IP
```dart
WKIM.shared.options.getAddr = (Function(String address) complete) async {
// 可通过接口获取后返回
complete('xxxxx:5100');
};
```
- <font color="#999" font-size=2>返回 IM 通信端的 IP 和 IM 通信端的 TCP 端口。<font color="#FF0000">分布式可调用接口获取 IP 和 Port 后返回</font></font>
#### 初始化sdk
```dart
// uid 登录用户ID业务服务端在IM通讯端登记了的uid
// token 登录用户token业务服务端在IM通讯端登记了的token
WKIM.shared.setup(Options.newDefault('uid', 'token'));
```
### 连接/断开
#### 连接
```dart
WKIM.shared.connectionManager.connect();
```
#### 断开
```dart
// isLogout true退出并不再重连 false退出保持重连
WKIM.shared.connectionManager.disconnect(isLogout)
```
### 连接状态监听
```dart
WKIM.shared.connectionManager.addOnConnectionStatus('home',
(status, reason, connInfo) {
if (status == WKConnectStatus.connecting) {
// 连接中
} else if (status == WKConnectStatus.success) {
// 连接成功
// connInfo.nodeId 节点ID
} else if (status == WKConnectStatus.noNetwork) {
// 没有网络连接
} else if (status == WKConnectStatus.syncMsg) {
// 同步消息
} else if (status == WKConnectStatus.kicked) {
// 被踢下线 需退出应用回到登录界面
} else if (status == WKConnectStatus.fail) {
// 连接失败
} else if (status == WKConnectStatus.syncCompleted) {
// 同步完成
}
});
```

View File

@ -0,0 +1,96 @@
# 频道管理
频道(Channel)WuKongIM 中是一个比较抽象的概念。发送消息都是先发送给频道,频道根据自己的配置规则进行投递消息,频道分频道和频道详情。 更多介绍请移步[什么是频道](/guide/initialize#频道)
### 数据源
`需要实现获取频道资料的数据源` [获取频道资料数据源](/sdk/flutter/datasource.html#频道资料数据源)
### 频道资料
#### 获取频道资料
```dart
// 获取某个channel资料
WKIM.shared.channelManager.getChannel(String channelID,int channelType);
```
#### 强制刷新频道资料
```dart
// 强制刷新某个channel资料
WKIM.shared.channelManager.fetchChannelInfo(String channelID, int channelType)
```
### 事件
#### 监听频道更新事件
```dart
// 监听channel刷新事件
WKIM.shared.channelManager.addOnRefreshListener('key',(wkChannel){
// 刷新对应channel 信息
});
// 移除监听
WKIM.shared.channelManager.removeOnRefreshListener('key');
```
- <font color='#999' size=2>key为监听的唯一标识可以为任意字符串添加监听和移出监听时需要传入相同的key</font>
### 常用方法
```dart
// 批量保存频道资料
WKIM.shared.channelManager.addOrUpdateChannels(List<WKChannel> channelList);
// 搜索
WKIM.shared.channelManager.search(String keyword);
```
### 数据结构说明
```dart
class WKChannel {
String channelID = "";
int channelType = WKChannelType.personal;
String channelName = "";
//频道备注(频道的备注名称,个人的话就是个人备注,群的话就是群别名)
String channelRemark = "";
int showNick = 0;
//是否置顶
int top = 0;
//是否保存在通讯录
int save = 0;
//免打扰
int mute = 0;
//禁言
int forbidden = 0;
//邀请确认
int invite = 0;
//频道状态[1正常2黑名单]
int status = 1;
//是否已关注 0.未关注(陌生人) 1.已关注(好友)
int follow = 0;
//是否删除
int isDeleted = 0;
//创建时间
String createdAt = "";
//修改时间
String updatedAt = "";
//频道头像
String avatar = "";
//版本
int version = 0;
//扩展字段
dynamic localExtra;
//是否在线
int online = 0;
//最后一次离线时间
int lastOffline = 0;
// 最后一次离线设备标识
int deviceFlag = 0;
//是否回执消息
int receipt = 0;
// 机器人
int robot = 0;
//分类[service:客服]
String category = "";
String username = "";
String avatarCacheKey = "";
dynamic remoteExtraMap;
String parentChannelID = "";
int parentChannelType = 0;
}
```

View File

@ -0,0 +1,67 @@
# 频道成员管理
### 获取频道成员
#### 频道内所有成员
```dart
// 获取频道内所有成员
WKIM.shared.channelMemberManager.getMembers(channelId: channelId);
```
#### 频道内指定用户的成员信息
```dart
// 获取频道内指定用户的成员信息
WKIM.shared.channelMemberManager.getMember(channelId: channelId,uid;
```
### 事件
#### 刷新频道成员
```dart
// 刷新频道成员
WKIM.shared.channelMemberManager.addOnRefreshMemberListener('key', (WKChannelMember member,bool isEnd){
// todo 刷新会话列表
});
// 移除刷新频道成员监听
WKIM.shared.channelMemberManager.removeRefreshMemberListener('key');
```
- <font color='#999' size=2>key为监听的唯一标识可以为任意字符串添加监听和移出监听时需要传入相同的key</font>
### 数据结构说明
```dart
class WKChannelMember {
String channelID = "";
//频道类型
int channelType = 0;
//成员id
String memberUID = "";
//成员名称
String memberName = "";
//成员备注
String memberRemark = "";
//成员头像
String memberAvatar = "";
//成员角色
int role = 0;
//成员状态黑名单等1正常2黑名单
int status = 0;
//是否删除
int isDeleted = 0;
//创建时间
String createdAt = "";
//修改时间
String updatedAt = "";
//版本
int version = 0;
// 机器人0否1是
int robot = 0;
//扩展字段
dynamic extraMap;
// 用户备注
String remark = "";
// 邀请者uid
String memberInviteUID = "";
// 被禁言到期时间
int forbiddenExpirationTime = 0;
String memberAvatarCacheKey = "";
}
```

21
src/sdk/flutter/cmd.md Normal file
View File

@ -0,0 +1,21 @@
# 命令管理
CMD(命令)消息只能是服务器下发客户端进行解析 cmd消息格式
### 监听命令消息
```dart
// 监听命令消息
WKIM.shared.cmdManager.addOnCmdListener('chat', (cmdMsg) {
// todo 按需处理cmd消息
});
// 移除监听
WKIM.shared.cmdManager.removeCmdListener('chat');
```
### 数据结构说明
```dart
class WKCMD {
String cmd = ''; // 命令ID
dynamic param; // 对应命令参数
}
```

View File

@ -0,0 +1,68 @@
# 最近会话管理
### 获取最近会话
#### 所有最近会话
```dart
// 查询所有最近会话
WKIM.shared.conversationManager.getAll();
```
#### 新消息
只有第一次打开应用时,需要同步最近会话列表, 后续最近会话列表的变化,通过监听来获取
```dart
WKIM.getInstance().getConversationManager().addOnRefreshMsgListener("key", new IRefreshConversationMsg() {
@Override
public void onRefreshConversationMsg(WKUIConversationMsg wkUIConversationMsg, boolean isEnd) {
// wkUIConversationMsg 最近会话消息内容 UI上已有该会话需进行更新反之添加到UI上
// isEnd 为了防止频繁刷新UI当isEnd为true可刷新UI
}
});
```
### 删除最近会话
```dart
// 删除最近会话
WKIM.shared.conversationManager.deleteMsg(channelId,channelType);
```
### 常用方法
```dart
// 设置红点
WKIM.shared.conversationManager.updateRedDot(channelId,channelType,count);
// 删除所有最近会话
WKIM.shared.conversationManager.clearAll();
```
### 数据结构说明
```dart
class WKConversationMsg {
//频道id
String channelID = '';
//频道类型
int channelType = WKChannelType.personal;
//最后一条消息本地ID
String lastClientMsgNO = '';
//是否删除
int isDeleted = 0;
//服务器同步版本号
int version = 0;
//最后一条消息时间
int lastMsgTimestamp = 0;
//未读消息数量
int unreadCount = 0;
//最后一条消息序号
int lastMsgSeq = 0;
//扩展字段
dynamic localExtraMap;
WKConversationMsgExtra? msgExtra;
String parentChannelID = '';
int parentChannelType = 0;
}
```

View File

@ -0,0 +1,101 @@
# 数据源管理
### 文件
在自定义附件消息的时候发送给对方的消息是将网络地址发送给对方,并不是实际的文件。这个时候我们就需监听附件的上传
#### 监听上传附件
```dart
// 监听上传消息附件
WKIM.shared.messageManager.addOnUploadAttachmentListener((wkMsg, back) {
if (wkMsg.contentType == WkMessageContentType.image) {
// todo 上传附件
WKImageContent imageContent = wkMsg.messageContent! as WKImageContent;
imageContent.url = 'xxxxxx';
wkMsg.messageContent = imageContent;
back(wkMsg);
}
if (wkMsg.contentType == WkMessageContentType.voice) {
// todo 上传语音
WKVoiceContent voiceContent = wkMsg.messageContent! as WKVoiceContent;
voiceContent.url = 'xxxxxx';
wkMsg.messageContent = voiceContent;
back(wkMsg);
} else if (wkMsg.contentType == WkMessageContentType.video) {
WKVideoContent videoContent = wkMsg.messageContent! as WKVideoContent;
// todo 上传封面及视频
videoContent.cover = 'xxxxxx';
videoContent.url = 'ssssss';
wkMsg.messageContent = videoContent;
back(wkMsg);
}
});
```
#### 附件下载
sdk 中不会主动下载消息的附件。在收到带有附件的消息时需要 应用 自己按需下载。在 应用 下载完成后可改文件本地地址,避免重复下载
```dart
/**
* 修改消息内容体
*
* @param clientMsgNo 客户端消息ID
* @param messageContent 消息module 将本地地址保存在 messageContent 中
* @param isRefreshUI 是否通知UI刷新对应消息
*/
WKIM.shared.messageManager.updateContent(String clientMsgNo, WKMessageContent messageContent, boolean isRefreshUI);
```
### 最近会话
#### 监听同步会话
```dart
WKIM.shared.conversationManager
.addOnSyncConversationListener((lastSsgSeqs, msgCount, version, back) {
/**
* 同步会话
*
* @param lastSsgSeqs 最近会话列表msg_seq集合
* @param msgCount 会话里面消息同步数量
* @param version 最大版本号
* @param back 回调
*/
// 需要请求业务接口将数据返回给sdk
back(conversation);
});
```
### 频道
#### 频道资料数据源
```dart
// 监听获取channel信息
WKIM.shared.channelManager.addOnGetChannelListener((channelId, channelType, back) {
// 获取到资料后 通过back返回
// 或调用 WKIM.shared.channelManager.addOrUpdateChannel()方法更新sdk中channel资料
});
```
也可以批量保存频道资料信息
```dart
// 批量保存频道资料信息
WKIM.shared.channelManager.addOrUpdateChannels(channels);
```
### 消息
#### 频道消息数据源
```dart
WKIM.shared.messageManager.addOnSyncChannelMsgListener((channelID,
channelType, startMessageSeq, endMessageSeq, limit, pullMode, back) {
/*
* 同步某个频道的消息
*
* @param channelID 频道ID
* @param channelType 频道类型
* @param startMessageSeq 开始消息列号结果包含start_message_seq的消息
* @param endMessageSeq 结束消息列号结果不包含end_message_seq的消息
* @param limit 消息数量限制
* @param pullMode 拉取模式 0:向下拉取 1:向上拉取
* @param iSyncChannelMsgBack 请求返回
*/
// todo 请求接口后需返回给sdk
});
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

View File

@ -0,0 +1,14 @@
# 集成
## 快速入门
#### 安装
[![pub package](https://img.shields.io/pub/v/wukongimfluttersdk.svg)](https://pub.dartlang.org/packages/wukongimfluttersdk)
```
dependencies:
wukongimfluttersdk: ^version // 版本号看上面
```
#### 引入
```dart
import 'package:wukongimfluttersdk/wkim.dart';
```

45
src/sdk/flutter/intro.md Normal file
View File

@ -0,0 +1,45 @@
# 说明
## 设计理念
为了让开发者更快更方便的使用 SDK悟空 SDK 提供了一个唯一的入口来访问 SDK 中的所有功能。就像书籍的目录一样可以通过目录查找对应的内容。如连接 IM `WKIM.shared.connectionManager.connect();`
## 结构说明
![sdk结构图](./fluttersdk.png)
SDK 常用功能介绍
```dart
// 消息管理器
// 负责消息的增删改查、新消息监听、刷新消息监听、消息入库、监听同步某个聊天数据等
WKIM.shared.messageManager
// 最近会话管理
// 获取最近聊天记录、刷新最近会话[新增聊天、红点改变]、监听移除某个会话、监听同步最近会话等
WKIM.shared.conversationManager
// 连接管理
// 负责IM的连接、断开、退出登录、监听连接状态、监听获取连接IP等
WKIM.shared.connectionManager
// 频道管理
// 可获取Channel的信息刷新Channel缓存监听Channel更改[置顶、免打扰、禁言]等
WKIM.shared.channelManager
// 频道成员管理
// 获取Channel成员列表、设置成员备注、保存修改成员数据、监听刷新成员和移除成员等
WKIM.shared.channelMemberManager
// 提醒项管理
// 获取某个会话的提醒如:[有人@我] [入群申请] 等。还可自定义提醒项,如像 语音未读 等
WKIM.shared.reminderManager
// 命令管理
// 负责监听服务器下发的命令消息
WKIM.shared.cmdManager
```
### SDK 与 APP 交互原则
![SDK与已有APP交互原则](./../sdk_app.png) sdk 与 app 交互流程就是 app 调用 sdk 提供的方法sdk 处理完数据后通过事件将数据回调给 app。如发送消息流程app 调用发送消息方法sdk 将入库后的消息 push 给 app

180
src/sdk/flutter/message.md Normal file
View File

@ -0,0 +1,180 @@
# 消息管理
### 发送消息
```dart
WKIM.shared.messageManager.sendMessage(WKTextContent('我是文本消息'), WKChannel('uid_1', WKChannelType.personal));
```
如给用户`A`发送一条文本消息。构建文本消息正文
```dart
WKTextContent textContent = new WKTextContent("你好,悟空");
```
将消息发送给用户`A`
```dart
WKIM.shared.messageManager.sendMessage(textContent,WKChannel('A', WKChannelType.personal));
```
#### 文本消息
```dart
class WKTextContent extends WKMessageContent {
WKTextContent(content) {
contentType = WkMessageContentType.text;
this.content = content;
}
}
```
#### 图片消息
```dart
class WKImageContent extends WKMediaMessageContent {
int width;
int height;
WKImageContent(this.width, this.height) {
contentType = WkMessageContentType.image;
}
}
```
#### 语音消息
```dart
class WKVoiceContent extends WKMediaMessageContent {
int timeTrad; // 语音秒长
String? waveform; // 语音波纹 base64编码
WKVoiceContent(this.timeTrad) {
contentType = WkMessageContentType.voice;
}
}
```
### 消息入库返回(并不是消息发送状态)
在发送消息时sdk 将消息保存在本地数据库后就会触发入库回调。此时消息并未进行发送,可在此监听中将消息展示在 UI 上
监听消息入库事件
```dart
WKIM.shared.messageManager.addOnMsgInsertedListener((wkMsg) {
// 展示在UI
});
```
### 新消息
监听新消息事件
```dart
WKIM.shared.messageManager.addOnNewMsgListener('chat', (msgs) {
// 展示在UI上
});
```
- <font color='#999' size=2>如果在聊天页面内收到新消息时需判断该消息是否属于当前会话,可通过消息对象`WKMsg``channelID``channelType`判断</font>
### 刷新消息监听
在 sdk 更新过消息时消息发送状态有人点赞消息消息已读回执消息撤回消息被编辑等等sdk 都将回调以下事件。UI 可通过消息对象`WKMsg``clientMsgNO`来判断具体是哪条消息发生了更改。
监听刷新消息事件
```dart
WKIM.shared.messageManager.addOnRefreshMsgListener('chat', (wkMsg) {
// todo 刷新消息
});
```
### 查看某个频道的聊天信息
```dart
/*
* 查询或同步某个频道消息
*
* @param channelId 频道ID
* @param channelType 频道类型
* @param oldestOrderSeq 最后一次消息大orderSeq 第一次进入聊天传入0
* @param contain 是否包含 oldestOrderSeq 这条消息
* @param pullMode 拉取模式 0:向下拉取 1:向上拉取
* @param aroundMsgOrderSeq 查询此消息附近消息 如 aroundMsgOrderSeq=20 返回数据则是 [16,17,19,20,21,22,23,24,25]
* @param limit 每次获取数量
* @param iGetOrSyncHistoryMsgBack 请求返还
* @param syncBack 同步消息时回掉,可通过此回掉显示加载中
*/
WKIM.shared.messageManager.getOrSyncHistoryMessages(
channelID, channelType, oldestOrderSeq, contain, pullMode, limit, aroundMsgOrderSeq, Function(List<WKMsg>)){
},Function() syncBack);
```
- <font color='#999' size=2>获取历史消息并不是同步方法,因为有可能存在非连续性时会往服务器同步数据</font>
### 离线消息
`需要实现同步频道消息数据源` [频道消息数据源](/sdk/flutter/datasource.html#频道消息数据源)
因为WuKongIM 是支持消息永久存储,所以会产生海量的离线消息。对此我们采用了按需拉取的机制,如 10 个会话一个会话 10 万条消息WuKongIM 不会把这个 10\*10 万=100 万条消息都拉取到本地。 而是采用拉取这 10 个会话的信息和对应的最新 20 条消息,也就是实际只拉取了 200 条消息 相对 100 万条消息来说大大提高了离线拉取速度。用户点进对应的会话才会去按需拉取这个会话的消息。 这些机制 SDK 内部都已做好了封装,使用者其实不需要关心。使用者只需要关心最近会话的变化和监听获取数据的回调即可。
### 数据结构说明
#### 消息类核心属性
```dart
class WKMsg {
// 消息头 redDot是否显示红点 noPersist是否不存储 syncOnce是否只同步一次
MessageHeader header = MessageHeader();
// 消息设置 receipt是否回执topic是否话题聊天stream是否流消息;
Setting setting = Setting();
// 服务器消息ID(全局唯一,无序)
String messageID = "";
// 服务器消息ID(有序)
int messageSeq = 0;
// 本地消息有序ID
int clientSeq = 0;
// 10位时间戳
int timestamp = 0;
// 本地唯一ID
String clientMsgNO = "";
// 发送者
String fromUID = "";
// 所属频道ID
String channelID = "";
// 所属频道类型
int channelType = WKChannelType.personal;
// 消息正文类型 如 1:【文本】2:【图片】...
int contentType = 0;
// 消息负载
String content = "";
// 消息状态 0.发送中 1.成功
int status = 0;
// 是否被删除 1.是
int isDeleted = 0;
// 发送者的资料
WKChannel? _from;
// 所属频道资料
WKChannel? _channelInfo;
// 发送者在频道内类型资料(群消息才有值)
WKChannelMember? _memberOfFrom;
// 排序号
int orderSeq = 0;
// 本地扩展字段
dynamic localExtraMap;
// 远程扩展字段,服务器维护
WKMsgExtra? wkMsgExtra;
// 本条消息回应数据
List<WKMsgReaction>? reactionList;
// 消息正文体 contentType==1.WKTextContent contentType==2.WKImageConent
WKMessageContent? messageContent;
}
```
#### 消息正文体
```dart
class WKMessageContent {
// 消息类型 1.文本 2.图片
var contentType = 0;
// 消息内容
String content = "";
// 回复消息
WKReply? reply;
// 消息内容渲染数据
List<WKMsgEntity>? entities;
// 提醒信息
WKMentionInfo? mentionInfo;
}
```

View File

@ -0,0 +1,45 @@
# 提醒项管理
会话提醒目前只支持服务器下发指令。客户端只需监听同步会话提醒和监听刷新会话消息即可
### 获取提醒项
```dart
// 获取指定频道的提醒项列表
WKIM.shared.reminderManager.getWithChannel(channelId,channelType)
```
### 保存提醒项
```dart
// 保存提醒项
WKIM.shared.reminderManager.saveOrUpdateReminders(list)
```
### 事件
#### 新增提醒项
```dart
// 监听新增提醒项
WKIM.shared.reminderManager.addOnNewReminderListener(key, (reminder) {
// 处理新增提醒项
});
// 移除监听
WKIM.shared.reminderManager.removeOnNewReminderListener(key);
```
- <font color='#999' size=2>key为监听的唯一标识可以为任意字符串添加监听和移出监听时需要传入相同的key</font>
### 数据结构说明
```dart
class WKReminder {
int reminderID = 0; // 提醒项ID
String messageID = ''; // 消息ID
String channelID = ''; // 频道ID
int channelType = 0; // 频道类型
int messageSeq = 0; // 消息序列号
int type = 0; // 提醒类型
String text = ''; // 提醒内容
dynamic data; // 附加数据
int version = 0; // 版本号
int done = 0; // 完成状态
int needUpload = 0; // 是否需要上传(这里是指上传到业务服务器)
String publisher = ''; // 发布者
}
```

View File

@ -0,0 +1,352 @@
# 高级功能
### 自定义消息
在WuKongIM 中所有的消息类型都是自定义消息
#### 自定义普通消息
下面我们以名片消息举例
##### 第一步 定义消息
定义消息对象并继承 WKMessageContent 并在构造方法中指定消息类型
```typescripts
// 定义名片消息
export class CardMessageContent extends WKMessageContent {
uid: string = ''
name: string = ''
avatar: string = ''
constructor() {
super();
this.contentType = 16 // 指定类型
}
}
```
##### 第二步 编码和解码
我们需要将uid,name,avatar三个字段信息发送给对方最终传递的消息内容为
```typescripts
{
"type": 16,
"uid": "xxxx",
"name": "xxx",
"avatar": "xxx"
}
```
重写`WKMessageContent``encodeJson`方法开始编码
```typescripts
// 编码发送内容
encodeJson(): Record<string, Object> {
let json: Record<string, Object> = {}
json['uid'] = this.uid
json['name'] = this.name
json['avatar'] = this.avatar
return json
}
```
重写`WKMessageContent``decodeJson`方法开始解码
```typescripts
// 解码内容
decodeJson(jsonStr: string): WKMessageContent {
let json = CommonUtil.jsonToRecord(jsonStr)
if (json !== undefined) {
this.uid = CommonUtil.readString(json, 'uid')
this.name = CommonUtil.readString(json, 'name')
this.avatar = CommonUtil.readString(json, 'avatar')
}
return this
}
```
- <font color='#999' size=2>解码和编码消息时无需将 `type` 字段考虑其中sdk 内部会自动处理</font>
##### 第三步 注册消息
```typescripts
// 注册自定义消息
WKIM.shared.messageManager().registerMsgContent(16, (jsonStr: string) => {
return new CardMessageContent().decodeJson(jsonStr)
})
```
对此通过这三步自定义普通消息就已完成。在收到消息时`WKMsg`中的`type`为16就表示该消息是名片消息其中`messageContent`则为自定义的`CardMessageContent`,这时可将`messageContent`强转为`CardMessageContent`并渲染到UI上
完整代码
```typescripts
// 自定义普通消息
export class CardMessageContent extends WKMessageContent {
uid: string = ''
name: string = ''
avatar: string = ''
constructor() {
super();
this.contentType = 16 // 指定类型
}
// 编码发送内容
encodeJson(): Record<string, Object> {
let json: Record<string, Object> = {}
json['uid'] = this.uid
json['name'] = this.name
json['avatar'] = this.avatar
return json
}
// 解码内容
decodeJson(jsonStr: string): WKMessageContent {
let json = CommonUtil.jsonToRecord(jsonStr)
if (json !== undefined) {
this.uid = CommonUtil.readString(json, 'uid')
this.name = CommonUtil.readString(json, 'name')
this.avatar = CommonUtil.readString(json, 'avatar')
}
return this
}
// 最近会话显示内容
displayText(): string {
return '[名片]'
}
}
```
### 自定义附件消息
我们在发送消息的时候有时需发送带附件的消息。WuKongIM 也提供自定义附件消息,自定义附件消息和普通消息区别不大。下面我们已地理位置消息举例
##### 第一步 定义消息
值得注意的是自定义附件消息需继承`WKMediaMessageContent`而不是`WKMessageContent`
```typescripts
export class LocationMessageContent extends WKMediaMessageContent {
address: string = ''
longitude: number = 0.0
latitude: number = 0.0
constructor() {
super();
this.contentType = 17 // 指定类型
}
}
```
- <font color='#999' size=2>`WKMediaMessageContent`提供了`url``localPath`字段,自定义消息无需在定义网络地址和本地地址字段</font>
##### 第二步 编码和解码
我们需要将`longitude`,`latitude`,`address`,`url`信息发送给对方,最终传递的消息内容为
```typescripts
{
"type": 17,
"longitude": 115.25,
"latitude": 39.26,
"url": "xxx",
"address": "xxx"
}
```
重写`WKMessageContent`的encodeJson方法开始编码
```typescripts
// 编码
encodeJson(): Record<string, Object> {
let json: Record<string, Object> = {}
json['url'] = this.url
json['longitude'] = this.longitude
json['latitude'] = this.latitude
return json
}
```
重写`WKMessageContent``decodeJson`方法开始解码
```typescripts
// 解码
decodeJson(jsonStr: string): WKMessageContent {
let json = CommonUtil.jsonToRecord(jsonStr)
if (json !== undefined) {
this.address = CommonUtil.readString(json, 'address')
this.url = CommonUtil.readString(json, 'url')
this.longitude = CommonUtil.readNumber(json, 'longitude')
this.latitude = CommonUtil.readNumber(json, 'latitude')
}
return this
}
```
##### 第三步 注册消息
```typescripts
// 注册自定义消息
WKIM.shared.messageManager().registerMsgContent(17, (jsonStr: string) => {
return new LocationMessageContent().decodeJson(jsonStr)
})
```
### 消息扩展
随着业务的发展应用在聊天中的功能也日益增多,为了满足绝大部分的需求 WuKongIM 中增加了消息扩展功能。消息扩展分`本地扩展``远程扩展`,本地扩展只针对 app 本地使用卸载 app 后将丢失,远程扩展是服务器保存卸载重装后数据将恢复
#### 本地扩展
本地扩展就是消息对象`WKMsg`中的l`localExtraMap`字段
```typescripts
/**
* 修改消息本地扩展
*
* @param clientMsgNo 客户端ID
* @param extra 扩展字段
*/
WKIM.shared.messageManager().updateLocalExtra(clientMsgNo: string, extra: Record<string, Object>)
```
- <font color='#999' size=2>更新成功后 sdk 会触发刷新消息回调</font>
#### 远程扩展
远程扩展就是消息对象`WKMsg`中的`remoteExtra`字段
```typescripts
WKIM.shared.messageManager().saveRemoteExtras(list: WKMsgExtra[])
```
- <font color='#999' size=2>更新成功后 sdk 会触发刷新消息回调</font>
##### 数据结构说明
```typescripts
export class WKMsgExtra {
// 消息ID
messageId = ''
// 频道ID
channelId = ''
// 频道类型
channelType: number = WKChannelType.personal
// 是否已读 1.是
readed = 0
// 已读数量
readedCount = 0
// 未读数量
unreadCount = 0
// 是否撤回 1.是
revoke = 0
// 是否删除
isMutualDeleted = 0
// 撤回者uid
revoker = ''
// 版本号
extraVersion = 0
// 编辑时间
editedAt = 0
// 编辑内容
contentEdit = ''
// 是否需要上传 1.是
needUpload = 0
// 是否置顶
isPinned = 0
// 编辑后正文
contentEditMsgModel?: WKMessageContent
}
```
### 消息已读未读
消息的已读未读又称消息回执。消息回执功能可通过 setting 进行设置
```typescripts
let option = new WKSendOptions()
option.setting.receipt = 1 // 开启回执
// 发送消息
WKIM.shared.messageManager().sendWithOption(textModel, channel, option)
```
当登录用户浏览过对方发送的消息时,如果对方开启了消息回执这时需将查看过的消息上传到服务器标记该消息已读。当对方或者自己上传过已读消息这时业务服务器会下发同步消息扩展的 cmd(命令)消息`syncMessageExtra`,此时需同步最新消息扩展保存到 sdk 中
### 消息编辑
当我们给对方发送消息发现发送内容有错误时,这时无需撤回重发只需要将消息编辑即可
<video controls height='30%' width='30%' src="/video/msgedit.mp4"></video>
#### 设置编辑内容
```typescripts
/**
* 修改编辑内容
* @param messageId 消息服务器ID
* @param channelId 频道ID
* @param channelType 频道类型
* @param content 编辑后的内容
*/
WKIM.shared.messageManager().updateEdit(messageId: string, channelId: string, channelType: number, content: string)
```
更改 sdk 消息编辑内容后需将编辑后的内容上传到服务器,则需要监听上传消息扩展
```typescripts
WKIM.shared.config.provider.uploadMessageExtraCallback = (extra: WKMsgExtra) => {
//上传到业务服务器
}
```
### 消息回复
在聊天中如果消息过多,发送消息回复就会显得消息很乱无章可循。这时就需要对某条消息进行特定的回复,即消息回复,如以下效果 <img src='./../msg_reply.jpg' width=30%/>
在发送消息时,只需将消息正文`WKMessageContent`中的`WKReply`对象赋值就能对达到消息回复效果
```typescripts
let textModel: WKTextContent = new WKTextContent(this.sendContent)
textModel.reply = new WKReply()
textModel.reply.messageId = ''
// 设置其他字段信息
// 发送消息
WKIM.shared.messageManager().send(textModel, channel)
```
#### 回复消息结构说明
```typescripts
export class WKReply {
// 被回复的消息根ID多级回复时的第一次回复的消息ID
rootMid = ''
// 被回复的消息ID
messageId = ''
// 被回复的MessageSeq
messageSeq = 0
// 被回复者uid
fromUID = ''
// 被回复者名称
fromName = ''
// 被回复的消息字符串
contentEdit = ''
// 编辑时间
editAt = 0
// 回复消息被撤回标记 1.是
revoke = 0
// 被回复消息编辑后的内容
contentEditMsgModel?: WKMessageContent
// 被回复的消息体
payload?: WKMessageContent
}
```
### 消息回应(点赞)
#### 保存
```typescripts
WKIM.shared.messageManager().saveReactions(list: WKMsgReaction[])
```
- <font color='#999' size=2>同一个用户对同一条消息只能做出一条回应。重复进行消息不同 emoji 的回应会做为修改回应,重复进行相同 emoji 的回应则做为删除回应</font> sdk 更新消息回应后会触发消息刷新的事件。app 需监听此事件并对 UI 进行刷新
监听消息回应刷新
```typescripts
// 监听消息回应刷新
WKIM.shared.messageManager().addRefreshReactionListener((list)=>{
// 刷新 UI
})
```
#### 获取
```typescripts
WKIM.shared.messageManager().getMsgReactions(messageId:string)
```
#### 数据结构说明
```typescripts
export class WKMsgReaction {
// 消息ID
messageId = ""
// 频道ID
channelId = ""
// 频道类型
channelType = WKChannelType.personal
// 回应者uid
uid = ""
// 消息序号
seq = 0
// 回应表情
emoji = ""
// 是否删除 1.是
isDeleted = 0
// 创建时间
createdAt = ""
}
```

64
src/sdk/harmonyos/base.md Normal file
View File

@ -0,0 +1,64 @@
# 基础
### 初始化
```typescript
// uid 登录用户ID业务服务端在IM通讯端登记了的uid
// token 登录用户token业务服务端在IM通讯端登记了的token
await WKIM.shared.init(uid, token)
```
### 连接地址
```typescript
WKIM.shared.config.provider.connectAddrCallback = (): Promise<string> => {
// 通过网络获取连接地址后返回
let add = HttpUtil.getIP()
return add
}
```
- <font color="#999" font-size=2>返回 IM 通信端的 IP 和 IM 通信端的 TCP 端口。<font color="#FF0000">分布式可调用接口获取 IP 和 Port 后返回</font></font>
### 连接
```typescript
// 连接
WKIM.shared.connectionManager().connection()
```
### 断开
```typescript
// 断开 isLogout true退出并清空用户信息 false退出保持用户信息
WKIM.shared.connectionManager().disConnection(isLogout)
```
### 监听连接状态
```typescript
// 监听连接状态
WKIM.shared.connectionManager()
.addConnectStatusListener((status: number, reasonCode?: number, connInfo?: ConnectionInfo) => {
switch (status) {
case WKConnectStatus.success: {
// `悟空IM(连接成功-节点:${connInfo?.nodeId})`
break
}
case WKConnectStatus.fail:
// '连接失败'
break
case WKConnectStatus.connecting:
// '连接中...'
break
case WKConnectStatus.syncing:
// '同步中...'
break
case WKConnectStatus.syncCompleted:
// `悟空IM(连接成功-节点:${this.nodeId})`
break
case WKConnectStatus.noNetwork:
// '网络异常'
break
case WKConnectStatus.kicked:
// '其他账号登录'
break
}
})
```

View File

@ -0,0 +1,79 @@
# 频道管理
频道(Channel)WuKongIM 中是一个比较抽象的概念。发送消息都是先发送给频道,频道根据自己的配置规则进行投递消息,频道分频道和频道详情。 更多介绍请移步[什么是频道](/guide/initialize#频道)
### 数据源
`需要实现获取频道资料的数据源` [获取频道资料数据源](/sdk/harmonyos/datasource.html#频道资料数据源)
### 频道资料
#### 获取频道资料
```javascrip
// 获取频道资料
let channel = WKIM.shared.channelManager().getChannel(channelId, channelType)
```
#### 强制刷新频道资料
```javascrip
// 强制刷新频道资料
WKIM.shared.channelManager().fetchChannelInfo(channelId, channelType)
```
### 事件
#### 监听频道资料更新
```javascrip
refreshChannelListener = (channel: WKChannel) => {
// 刷新
}
// 添加刷新频道监听
WKIM.shared.channelManager().addRefreshListener(this.refreshChannelListener)
// 在退出页面时移除监听
WKIM.shared.channelManager().removeRefreshListener(this.refreshChannelListener)
```
### 常用方法
```typescript
// 保存频道资料
WKIM.shared.channelManager().addOrUpdate(channel: WKChannel)
// 批量保存
WKIM.shared.channelManager().addOrUpdates(list: WKChannel[])
// 修改频道头像缓存地址
WKIM.shared.channelManager().updateAvatarCacheKey(channelId: string, channelType: number, key: string)
```
### 数据结构说明
```typescript
export class WKChannel {
channelId: string // 频道ID
channelType: number // 频道类型
channelName: string = "" // 频道名称
channelRemark: string = "" // 频道备注
showNick: number = 0 // 显示昵称 0.不显示 1.显示
top: number = 0 // 置顶 0.不置顶 1.置顶
save: number = 0 // 是否保存到通讯录 0.不保存 1.保存
mute: number = 0 // 是否免打扰 0.不免打扰 1.免打扰
forbidden: number = 0 // 是否禁言 0.不禁言 1.禁言
invite: number = 0 // 是否允许邀请 0.不允许 1.允许
status: number = 0 // 频道状态 0.禁用 1.正常
follow: number = 0 // 关注状态 0.未关注 1.已关注
isDeleted: number = 0 // 是否删除 0.未删除 1.已删除
createdAt: string = '' // 创建时间
updatedAt: string = '' // 更新时间
avatar: string = '' // 头像
version: number = 0 // 频道版本
online: number = 0 // 在线状态 0.离线 1.在线
lastOffline: number = 0 // 最后离线时间
deviceFlag: number = 0 // 设备标识 0.APP 1.WEB 2.PC
receipt: number = 0 // 是否开启回执 0.未开启 1.开启
robot: number = 0 // 是否为机器人 0.不是 1.是
category: string = '' // 频道分类
username: string = '' // 用户名
avatarCacheKey: string = '' // 头像缓存key
localExtra?: Record<string, Object> // 本地扩展
remoteExtra?: Record<string, Object> // 远程扩展
parentChannelId: string = '' // 父频道ID
parentChannelType: number = 0 // 父频道类型
}
```

View File

@ -0,0 +1,58 @@
# 频道成员管理
### 获取频道成员
#### 获取某个频道下的所有成员
```typescript
// 获取某个channel下的所有成员
let members = WKIM.shared.channelMemberManager().getMembers(channelId, channelType)
```
#### 分页查询频道成员
`需要实现分页获取频道成员资料的数据源` [获取分页频道成员资料数据源](/sdk/harmonyos/datasource.html#频道成员分页数据源)
```typescript
// 分页获取频道成员
WKIM.shared.channelMemberManager().getWithPageOrSearch(channelId, channelType,option)
```
`option`说明
```typescript
export class SyncChannelMemberOptions {
searchKey: string = '' // 搜索关键字
page: number = 0 // 页码
limit: number = 20 // 每页数量
}
```
### 事件
#### 监听刷新频道成员
```typescript
refreshChannelMemberListener = (members: WKChannelMember[]) => {
// 刷新
}
// 添加刷新频道成员监听
WKIM.shared.channelMemberManager().addRefreshListener(this.refreshChannelMemberListener)
// 在退出页面时移除监听
WKIM.shared.channelMemberManager().removeRefreshListener(this.refreshChannelMemberListener)
```
### 数据结构说明
```typescript
export class WKChannelMember {
channelId: string = '' // 频道ID
channelType: number = WKChannelType.personal // 频道类型
memberUID: string = '' // 成员UID
memberName: string = '' // 成员名称
memberRemark: string = '' // 成员备注
memberAvatar: string = '' // 成员头像
role = 0 // 成员角色
status = 0 // 成员状态
isDeleted = 0 // 是否被删除
createdAt: string = '' // 创建时间
updatedAt: string = '' // 更新时间
version = 0 // 版本号
robot = 0 // 是否为机器人
extra?: Record<string, object> // 扩展字段
memberInviteUID: string = '' // 邀请人UID
forbiddenExpirationTime = 0 // 禁言截止时间
memberAvatarCacheKey: string = '' // 头像缓存key
}
```

23
src/sdk/harmonyos/cmd.md Normal file
View File

@ -0,0 +1,23 @@
# 命令管理
CMD(命令)消息只能是服务器下发客户端进行解析 cmd消息格式
### 监听命令消息
```typescript
cmdListener = (cmd: WKCMD) => {
// 处理CMD消息
}
// 添加CMD消息监听
WKIM.shared.cmdManager().addCmdListener(this.cmdListener)
// 在退出页面时移除监听
WKIM.shared.cmdManager().removeCmdListener(this.cmdListener)
```
### 数据结构说明
```typescript
export class WKCMD {
cmd: string = '' // 命令Id
paramJsonObject?: Record<string, Object> // 命令参数
}
```

View File

@ -0,0 +1,52 @@
# 最近会话管理
### 获取最近会话
#### 所有最近会话
```javascrip
// 查询所有最近会话
let msgs = WKIM.shared.conversationManager().all()
```
#### 新消息
只有第一次打开应用时,需要同步最近会话列表, 后续最近会话列表的变化,通过监听来获取
```typescript
WKIM.shared.conversationManager().addRefreshListener((list:WKConversation[]) => {
// 当UI列表没有list中的数据时需执行添加操作
})
```
### 删除最近会话
```typescript
// 删除最近会话
WKIM.shared.conversationManager().delete(channelId, channelType)
```
调用删除最近会话后会触发删除最近会话事件UI可以监听删除最近会话事件并将UI上的会话进行删除
```typescript
WKIM.shared.conversationManager().addDeletedListener((channelId: string, channelType: number) => {
// 删除UI上的会话
})
```
### 数据结构说明
```typescript
export class WKConversation {
channelId: string = '' // 频道ID
channelType: number = WKChannelType.personal // 频道类型
lastClientMsgNo: string = '' // 最后一条消息的序列号
isDeleted: number = 0 // 是否被删除
version: number = 0 // 会话版本号
unreadCount = 0 // 未读消息数
lastMsgTimestamp = 0 // 最后一条消息的时间戳
lastMsgSeq = 0 // 最后一条消息的序列号
parentChannelId = '' // 父会话ID
parentChannelType = WKChannelType.personal // 父会话类型
localExtra?: Record<string, Object> // 本地扩展字段
remoteExtra?: WKConversationExtra // 远程扩展字段
private reminders?: WKReminder[] // 提醒项
private msg?: WKMsg // 最后一条消息
private channel?: WKChannel // 频道信息
}
```

View File

@ -0,0 +1,118 @@
# 数据源管理
### 文件
在自定义附件消息的时候发送给对方的消息是将网络地址发送给对方,并不是实际的文件。这个时候我们就需监听附件的上传
#### 上传
```typescript
// 定义上传文件数据源
let uploadAttachmentCallback = async (msg: WKMsg): Promise<[boolean, WKMsg]> => {
if (msg.contentType === WKMsgContentType.Image) {
// 上传图片
let imageContent = msg.messageContent as WKImageContent
imageContent.url = 'xxxx'
msg.messageContent = imageContent
return [true, msg]
} else if (msg.contentType === WKMsgContentType.Voice) {
// 上传语音
let voiceContent = msg.messageContent as WKVoiceContent
voiceContent.url = 'xxxx'
msg.messageContent = voiceContent
return [true, msg]
} else if (msg.contentType === WKMsgContentType.Video) {
// 上传视频
let videoContent = msg.messageContent as WKVideoContent
videoContent.url = 'xxxx'
msg.messageContent = videoContent
return [true, msg]
} else if (msg.contentType === 17) {
// 上传自定义附件消息
let customerMsg = msg.messageContent as LocationMessageContent
customerMsg.url = 'https://img1.baidu.com/it/u=3362698628,1928330748&fm=253&fmt=auto&app=138&f=JPEG?w=390&h=308'
msg.messageContent = customerMsg
return [true, msg]
}
return [true, msg]
}
// 提供文件上传数据源
WKIM.shared.config.provider.uploadAttachmentCallback = uploadAttachmentCallback
```
#### 下载
sdk 中不会主动下载消息的附件。在收到带有附件的消息时需要 app 自己按需下载。在 app 下载完成后可改文件本地地址,避免重复下载
```typescript
WKIM.shared.messageManager().updateContent(clientMsgNo: string, messageContent: WKMessageContent)
```
### 最近会话
#### 同步最近会话数据源
```typescript
// 定义提供者
let syncConversationCallback = async (lastMsgSeqs: string, msgCount: number,
version: number): Promise<WKSyncConversation> => {
// do 请求接口后返回给sdk
}
// 设置同步最近会话提供者
WKIM.shared.config.provider.syncConversationCallback = syncConversationCallback
```
### 频道
#### 频道资料数据源
```typescript
// 设置频道资料提供者
WKIM.shared.config.provider.channelInfoCallback =
async (channelId: string, channelType: number): Promise<WKChannel> => {
// 测试数据,实际可通过接口返回
WKLogger.error('获取channel资料', channelId, channelType + "")
let channel = new WKChannel(channelId, channelType)
if (channel.channelType === WKChannelType.personal) {
channel.channelName = `单聊${channelId}`
channel.channelRemark = `备注${channel.channelName}`
} else if (channel.channelType === WKChannelType.group) {
channel.channelName = `群${channelId}`
}
channel.avatar = `https://api.multiavatar.com/${channel.channelId}.png`
return channel
}
```
### 频道成员
#### 频道成员分页数据源
```typescript
// 定义提供者
WKIM.shared.config.provider.channelMemberWithPageCallback = async (channel: WKChannel,
option: SyncChannelMemberOptions): Promise<WKChannelMember[]> => {
// todo 请求接口后返回给sdk
let list: WKChannelMember[] = []
return list
}
```
### 消息
#### 频道消息数据源
```typescript
// 定义提供者
let syncMessageCallback = async (channel: WKChannel, options: SyncOptions): Promise<WKSyncChannelMsg> => {
/*
* 同步某个频道的消息
*
* @param channel.channelId 频道ID
* @param channel.channelType 频道类型
* @param options.startMessageSeq 开始消息列号结果包含start_message_seq的消息
* @param options.endMessageSeq 结束消息列号结果不包含end_message_seq的消息
* @param options.limit 消息数量限制
* @param options.pullMode 拉取模式 0:向下拉取 1:向上拉取
*/
// todo 请求接口后需返回给sdk
}
// 同步channel消息
WKIM.shared.config.provider.syncMessageCallback = syncMessageCallback
```

View File

@ -0,0 +1,10 @@
# 集成
### 下载安装
```
ohpm install @wukong/wkim
```
### 引入
```
import { WKIM } from '@wukong/wkim';
```

View File

@ -0,0 +1,44 @@
# 说明
## 设计理念
为了让开发者更快更方便的使用 SDK悟空 SDK 提供了一个唯一的入口来访问 SDK 中的所有功能。就像书籍的目录一样可以通过目录查找对应的内容。如连接 IM `WKIM.shared.connectionManager().connection();`
## 结构说明
![sdk结构图](./../fluttersdk.png)
SDK 常用功能介绍
```typescript
// 连接管理
// 负责IM的连接、断开、退出登录、监听连接状态等
WKIM.shared.connectionManager()
// 消息管理
// 负责消息的增删改查、新消息监听、刷新消息监听、消息入库等
WKIM.shared.messageManager()
// 会话管理
// 负责会话的增删改查、会话列表监听、会话消息监听等
WKIM.shared.conversationManager()
// 频道管理
// 可获取Channel的信息刷新Channel缓存监听Channel更改[置顶、免打扰、禁言]等
WKIM.shared.channelManager()
// 频道成员管理
// 获取Channel成员列表、设置成员备注、保存修改成员数据、监听刷新成员和移除成员等
WKIM.shared.channelMemberManager()
// 提醒项管理
// 获取某个会话的提醒如:[有人@我] [入群申请] 等。还可自定义提醒项,如像 语音未读 等
WKIM.shared.reminderManager()
// 命令管理
// 负责监听服务器下发的命令消息
WKIM.shared.cmdManager()
```
### SDK 与 APP 交互原则
![SDK与已有APP交互原则](./../sdk_app.png) sdk 与 app 交互流程就是 app 调用 sdk 提供的方法sdk 处理完数据后通过事件将数据回调给 app。如发送消息流程app 调用发送消息方法sdk 将入库后的消息 push 给 app

View File

@ -0,0 +1,185 @@
# 消息管理
### 发送消息
#### 说明
发送消息的方法
```typescript
/**
* 发送消息
* @param model 消息内容
* @param channel 频道对象 个人频道,群频道
*/
WKIM.shared.messageManager().send(model: WKMessageContent, channel: WKChannel);
```
#### 文本消息
```typescript
// 文本消息
let textModel: WKTextContent = new WKTextContent('你好,悟空')
// 发送给用户A
WKIM.shared.messageManager().send(textModel, new WKChannel('A', WKChannelType.personal));
```
#### 图片消息
```typescript
// 图片消息
let imageModel: WKImageContent = new WKImageContent(localPath)
imageModel.width = 100
imageModel.height = 100
// 发送给用户A
WKIM.shared.messageManager().send(imageModel, new WKChannel('A', WKChannelType.personal));
```
#### 自定义消息
```typescript
// 自定义消息
let model: xxx = new xxx()
// 发送给群组g_100
WKIM.shared.messageManager().send(model, new WKChannel('g_100', WKChannelType.group));
```
### 消息入库返回(并不是消息发送状态)
在发送消息时sdk 将消息保存在本地数据库后就会触发入库回调。此时消息并未进行发送,可在此监听中将消息展示在 UI 上
```typescript
// 监听发送消息入库
WKIM.shared.messageManager().addInsertedListener((msg) => {
// 将消息展示在 UI 上
})
```
### 新消息
监听新消息事件
```typescript
// 新消息监听器
newMsgsListener = (msgs: WKMsg[]) => {
// 处理新消息
}
// 监听新消息
WKIM.shared.messageManager().addNewMsgListener(this.newMsgsListener)
// 移除新消息监听
WKIM.shared.messageManager().removeNewMsgListener(this.newMsgsListener)
```
### 刷新消息
在 sdk 更新过消息时消息发送状态有人点赞消息消息已读回执消息撤回消息被编辑等等sdk 都将回调以下事件。UI 可通过消息对象WKMsg的clientMsgNO来判断具体是哪条消息发生了更改。
```typescript
// 刷新消息监听器
refreshMsgListener = (msg: WKMsg) => {
// 处理刷新消息
}
// 监听刷新消息
WKIM.shared.messageManager().addRefreshListener(this.refreshMsgListener)
// 移除刷新消息监听
WKIM.shared.messageManager().removeRefreshListener(this.refreshMsgListener)
```
### 查看某个频道的聊天信息
```typescript
let option = new ChannelMsgOptions(() => {
// 同步中 按需显示loading
}, (list) => {
// 消息数据
})
option.oldestOrderSeq = 0 // 最后一次消息大orderSeq 第一次进入聊天传入0
option.contain = false // 是否包含 oldestOrderSeq 这条消息
option.pullMode = 1 // 拉取模式 拉取模式 0:向下拉取 1:向上拉取
option.limit = 20 // 一次拉取消息数量
option.aroundMsgOrderSeq = 0 // 查询此消息附近消息 如 aroundMsgOrderSeq=20 返回数据则是 [16,17,19,20,21,22,23,24,25]
// 查看某个频道的聊天信息
WKIM.shared.messageManager().getOrSyncHistoryMessages(channel, option)
```
- <font color='#999' size=2>获取历史消息并不是同步方法,因为有可能存在非连续性时会往服务器同步数据</font>
### 离线消息
`需要实现同步频道消息数据源` [频道消息数据源](/sdk/harmonyos/datasource.html#频道消息数据源)
因为WuKongIM 是支持消息永久存储,所以会产生海量的离线消息。对此我们采用了按需拉取的机制,如 10 个会话一个会话 10 万条消息WuKongIM 不会把这个 10\*10 万=100 万条消息都拉取到本地。 而是采用拉取这 10 个会话的信息和对应的最新 20 条消息,也就是实际只拉取了 200 条消息 相对 100 万条消息来说大大提高了离线拉取速度。用户点进对应的会话才会去按需拉取这个会话的消息。 这些机制 SDK 内部都已做好了封装,使用者其实不需要关心。使用者只需要关心最近会话的变化和监听获取数据的回调即可。
### 数据结构说明
#### 消息结构
```typescript
export class WKMsg {
// 服务端唯一消息ID
messageId = "";
// 服务端消息序号
messageSeq = 0;
// 客户端消息序号
clientSeq = 0;
// 消息时间戳
timestamp = 0;
// 过期时间
expireTime = 0;
// 过期时间戳
expireTimestamp = 0;
// 客户端唯一编号
clientMsgNo = "";
// 发送者uid
fromUID = "";
// 所属频道ID
channelId = "";
// 所属频道类型
channelType = WKChannelType.personal;
// 消息类型
contentType = 0;
// 消息内容字符串
content = "";
// 消息状态 1.发送成功 0.发送中
status = 0;
voiceStatus = 0;
// 是否删除 1.是
isDeleted = 0;
// 搜索关键字
searchableWord = "";
// 消息发送者资料
private from?: WKChannel
// 消息所属频道资料
private channelInfo?: WKChannel
// 消息发送者在频道内资料 群消息才有值
private memberOfFrom?: WKChannelMember
// 排序号
orderSeq = 0;
// 是否已读
viewed = 0;
// 已读时间
viewedAt = 0;
// 话题ID
topicId = "";
// 本地扩展
localExtraMap?: Record<string, object>
// 远程扩展
wkMsgExtra?: WKMsgExtra
// 消息回应点赞数据
reactionList?: WKMsgReaction[]
// 消息正文
messageContent?: WKMessageContent
}
```
#### 消息正文结构
```typescript
export class WKMessageContent {
// 消息类型
contentType: number = 0
// 消息内容
content: string = ""
// 渲染消息内容 如@某人时需要渲染@xxx这段文字
entities?: ArrayList<WKMsgEntity>
// 消息回复
reply?: WKReply
// 提醒信息
mentionInfo?: WKMentionInfo
}
```

View File

@ -0,0 +1,62 @@
# 提醒项管理
会话提醒目前只支持服务器下发指令。客户端只需监听同步会话提醒和监听刷新会话消息即可
### 获取提醒项
```typescript
// 获取指定频道的提醒项
// channelId: 频道ID
// channelType: 频道类型
// done: 1.已经完成的提醒项 0.未完成的提醒项
WKIM.shared.reminderManager().get(channelId,channelType,done)
```
### 保存提醒项
```typescript
// 保存提醒项
WKIM.shared.reminderManager().save(list: WKReminder[])
```
### 事件
#### 新增/更新事件
```typescript
refreshReminders = (reminders: WKReminder[]): void => {
// 新增提醒项 或 更新提醒项
}
// 监听提醒项
WKIM.shared.reminderManager().addRefreshListener(this.refreshReminders)
// 移除监听
WKIM.shared.reminderManager().removeRefreshListener(this.refreshReminders)
```
### 数据结构说明
```typescript
export class WKReminder {
// 提醒项ID
reminderId = 0
// 消息ID
messageId = ''
// 所属频道ID
channelId: string = ''
// 所属频道类型
channelType: number = WKChannelType.personal
// 消息序号
messageSeq = 0
// 提醒项类型 1.[@某人] 2.[入群申请] ...
type = 0
// 显示内容
text = ''
// 提醒项内容
data?: Record<string, Object>
// 版本号 增量同步需要
version = 0
// 是否完成 1.是
done = 0
// 是否需要上传到服务器
needUpload = 0
// 发布者
publisher = ''
}
```