消息发送(已不再维护)
更新时间: 2024/08/20 15:45:46
功能概述
SDK 提供一套完善的消息传输管理服务,包括收发消息,存储消息,上传下载附件等。支持发送文本,语音,图片,视频,文件,地理位置等类型消息,同时支持用户发送自定义类型的消息。
SDK 中用于表示消息的结构为 IMMessage
,不同消息类型以 MsgTypeEnum
作区分。IMMessage
不支持继承扩展。
消息接收、已读回执、广播消息接收等相关说明请查看消息接收。
消息发送
先通过 MessageBuilder
提供的接口创建对应的消息对象,然后调用 MsgService
的 sendMessage
接口发出。
java/**
* 发送消息。
* @param msg 待发送的消息体,由{@link MessageBuilder}构造
* @param resend 如果是发送失败后重发,标记为true,否则填false
* @return InvocationFuture 可以设置回调函数。消息发送完成后才会调用,如果出错,会有具体的错误代码。
*/
public InvocationFuture<Void> sendMessage(IMMessage msg, boolean resend);
一秒内默认最多调用 sendMessage
接口100次。如需上调上限,请在官网首页通过微信、在线消息或电话等方式咨询商务人员。
文本消息发送
文本消息创建原型
java/**
* 创建一条普通文本消息
*
* @param sessionId 聊天对象ID
* @param sessionType 会话类型
* @param text 文本消息内容
* @return IMMessage 生成的消息对象
*/
public static IMMessage createTextMessage(String sessionId, SessionTypeEnum sessionType, String text);
- 参数说明
参数 | 说明 |
---|---|
sessionId | 聊天对象的 ID,如果是单聊,为用户帐号,如果是群聊,为群组 ID |
sessionType | 聊天类型,SessionTypeEnum.P2P 为单聊类型,SessionTypeEnum.Team 为群聊类型 |
text | 文本消息内容 |
- 示例
java// 该帐号为示例
String account = "testAccount";
// 以单聊类型为例
SessionTypeEnum sessionType = SessionTypeEnum.P2P;
String text = "this is an example";
// 创建一个文本消息
IMMessage textMessage = MessageBuilder.createTextMessage(account, sessionType, text);
// 发送给对方
NIMClient.getService(MsgService.class).sendMessage(textMessage, false).setCallback(new RequestCallback<Void>() {
@Override
public void onSuccess(Void param) {
}
@Override
public void onFailed(int code) {
}
@Override
public void onException(Throwable exception) {
}
});
图片消息发送
图片消息创建原型
java/**
* 创建一条图片消息
*
* @param sessionId 聊天对象ID
* @param sessionType 会话类型
* @param file 图片文件
* @param displayName 图片文件的显示名,可不同于文件名
* @param nosTokenSceneKey 文件资源场景
* @return IMMessage 生成的消息对象
*/
public static IMMessage createImageMessage(String sessionId, SessionTypeEnum sessionType, File file, String displayName);
// 或者:创建一条图片消息并指定图片上传时使用的文件资源场景
public static IMMessage createImageMessage(String sessionId, SessionTypeEnum sessionType, File file, String displayName, String nosTokenSceneKey);
- 参数说明
参数 | 说明 |
---|---|
sessionId | 聊天对象的 ID,如果是单聊,为用户帐号,如果是群聊,为群组 ID |
sessionType | 聊天类型,SessionTypeEnum.P2P 为单聊类型,SessionTypeEnum.Team 为群聊类型 |
file | 图片文件对象 |
displayName | 图片文件的显示名,可不同于文件名,可设置为 null |
nosTokenSceneKey | 图片上传时使用的 nos scene ,默认为NimNosSceneKeyConstant.NIM_DEFAULT_IM,详见文件资源场景章节 |
- 示例
java// 该帐号为示例,请先注册
String account = "testAccount";
// 以单聊类型为例
SessionTypeEnum sessionType = SessionTypeEnum.P2P;
// 示例图片,需要开发者在相应目录下有图片
File file = new File("/sdcard/test.jpg");
// 创建一个图片消息
IMMessage message = MessageBuilder.createImageMessage(account, sessionType, file, file.getName());
// 或者:创建一个图片消息并指定图片上传时使用的文件资源场景,"nos_scene_key"请替换成开发者已经配置的
IMMessage message = MessageBuilder.createImageMessage(account, sessionType, file, file.getName(),"nos_scene_key");
// 发送给对方
NIMClient.getService(MsgService.class).sendMessage(message, false).setCallback(new RequestCallback<Void>() {
@Override
public void onSuccess(Void param) {
}
@Override
public void onFailed(int code) {
}
@Override
public void onException(Throwable exception) {
}
});
语音消息发送
音频消息创建原型:
java/**
* 创建一条音频消息
*
* @param sessionId 聊天对象ID
* @param sessionType 会话类型
* @param file 音频文件对象
* @param duration 音频文件持续时间,单位是ms
* @param nosTokenSceneKey 文件资源场景
* @return IMMessage 生成的消息对象
*/
public static IMMessage createAudioMessage(String sessionId, SessionTypeEnum sessionType, File file, long duration);
//或者:创建一条音频消息并指定音频上传时使用的文件资源场景
public static IMMessage createAudioMessage(String sessionId, SessionTypeEnum sessionType, File file, long duration, String nosTokenSceneKey);
- 参数说明
参数 | 说明 |
---|---|
sessionId | 聊天对象的 ID,如果是单聊,为用户帐号,如果是群聊,为群组 ID |
sessionType | 聊天类型,SessionTypeEnum.P2P 为单聊类型,SessionTypeEnum.Team 为群聊类型 |
file | 音频文件对象 |
duration | 音频文件持续时间,单位是 ms |
nosTokenSceneKey | 音频文件上传时使用的 nos scene ,默认为NimNosSceneKeyConstant.NIM_DEFAULT_IM ,详见文件资源场景章节 |
- 示例
java// 该帐号为示例,请先注册
String account = "testAccount";
// 以单聊类型为例
SessionTypeEnum sessionType = SessionTypeEnum.P2P;
// 示例音频,需要开发者在相应目录下有文件
File audioFile = new File("/sdcard/testAudio.mp3");
// 音频时长,时间为示例
long audiolength = 2000;
// 创建音频消息
IMMessage audioMessage = MessageBuilder.createAudioMessage(account, sessionType, audioFile, audioLength);
// 或者:创建一个音频消息并指定音频上传时使用的文件资源场景,"nos_scene_key"请替换成开发者已经配置的
IMMessage audioMessage = MessageBuilder.createAudioMessage(account, sessionType, audioFile, "nos_scene_key");
// 发送给对方
NIMClient.getService(MsgService.class).sendMessage(audioMessage, false).setCallback(new RequestCallback<Void>() {
@Override
public void onSuccess(Void param) {
}
@Override
public void onFailed(int code) {
}
@Override
public void onException(Throwable exception) {
}
});
视频消息发送
视频消息创建原型:
java/**
* 创建一条视频消息
*
* @param sessionId 聊天对象ID
* @param sessionType 会话类型
* @param file 视频文件对象
* @param duration 视频文件持续时间
* @param width 视频宽度
* @param height 视频高度
* @param displayName 视频文件显示名,可以为空
* @param nosTokenSceneKey 文件资源场景
* @return 视频消息
*/
public static IMMessage createVideoMessage(String sessionId, SessionTypeEnum sessionType, File file, long duration, int width, int height, String displayName);
//或者:创建一条视频消息并指定视频上传时使用的文件资源场景
public static IMMessage createVideoMessage(String sessionId, SessionTypeEnum sessionType, File file, long duration, int width, int height, String displayName, String nosTokenSceneKey)
- 参数说明
参数 | 说明 |
---|---|
sessionId | 聊天对象的 ID,如果是单聊,为用户帐号,如果是群聊,为群组 ID |
sessionType | 聊天类型,SessionTypeEnum.P2P 为单聊类型,SessionTypeEnum.Team 为群聊类型 |
file | 视频文件对象 |
duration | 视频文件持续时间,单位 ms |
width | 视频宽度 |
height | 视频高度 |
displayName | 视频文件显示名,可为 null |
nosTokenSceneKey | 视频文件上传时使用的 nos scene ,默认为NimNosSceneKeyConstant.NIM_DEFAULT_IM ,详见文件资源场景章节 |
- 示例
java// 该帐号为示例,请先注册
String account = "testAccount";
// 以单聊类型为例
SessionTypeEnum sessionType = SessionTypeEnum.P2P;
// 示例视频,需要开发者在相应目录下有文件
File file = new File("/sdcard/testVideo.mp4");
// 获取视频mediaPlayer
MediaPlayer mediaPlayer;
try {
mediaPlayer = MediaPlayer.create(context, Uri.fromFile(file));
} catch (Exception e) {
e.printStackTrace();
}
// 视频文件持续时间
long duration = mediaPlayer == null ? 0 : mediaPlayer.getDuration();
// 视频高度
int height = mediaPlayer == null ? 0 : mediaPlayer.getVideoHeight();
// 视频宽度
int width = mediaPlayer == null ? 0 : mediaPlayer.getVideoWidth();
// 创建视频消息
IMMessage message = MessageBuilder.createVideoMessage(account, sessionType, file, duration, width, height, null);
// 或者:创建一个视频消息并指定视频上传时使用的文件资源场景,"nos_scene_key"请替换成开发者已经配置的
IMMessage message = MessageBuilder.createVideoMessage(account, sessionType, file, duration, width, height, null,"nos_scene_key");
// 发送给对方
NIMClient.getService(MsgService.class).sendMessage(message, false).setCallback(new RequestCallback<Void>() {
@Override
public void onSuccess(Void param) {
}
@Override
public void onFailed(int code) {
}
@Override
public void onException(Throwable exception) {
}
});
文件消息发送
文件消息创建原型:
java/**
* 创建一条文件消息
*
* @param sessionId 聊天对象ID
* @param sessionType 会话类型
* @param file 文件
* @param displayName 文件的显示名,可不同于文件名
* @param nosTokenSceneKey 文件资源场景
* @return IMMessage 生成的消息对象
*/
public static IMMessage createFileMessage(String sessionId, SessionTypeEnum sessionType, File file, String displayName);
//或者:创建一条文件消息并指定文件上传时使用的文件资源场景
public static IMMessage createFileMessage(String sessionId, SessionTypeEnum sessionType, File file, String displayName, String nosTokenSceneKey)
- 参数说明
参数 | 说明 |
---|---|
sessionId | 聊天对象的 ID,如果是单聊,为用户帐号,如果是群聊,为群组 ID |
sessionType | 聊天类型,SessionTypeEnum.P2P 为单聊类型,SessionTypeEnum.Team 为群聊类型 |
file | 文件 |
displayName | 文件的显示名,可不同于文件名 |
nosTokenSceneKey | 文件上传时使用的 nos scene ,默认为NimNosSceneKeyConstant.NIM_DEFAULT_IM ,详见文件资源场景章节 |
- 示例
java// 该帐号为示例,请先注册
String account = "testAccount";
// 以单聊类型为例
SessionTypeEnum sessionType = SessionTypeEnum.P2P;
// 示例文件,需要开发者在相应目录下有文件
File file = new File("/sdcard/test.txt");
// 创建文件消息
IMMessage message = MessageBuilder.createFileMessage(account, sessionType, file, file.getName());
// 或者:创建一个文件消息并指定文件上传时使用的文件资源场景,"nos_scene_key"请替换成开发者已经配置的
IMMessage message = MessageBuilder.createFileMessage(account, sessionType, file, file.getName(),"nos_scene_key");
// 发送给对方
NIMClient.getService(MsgService.class).sendMessage(message, false).setCallback(new RequestCallback<Void>() {
@Override
public void onSuccess(Void param) {
}
@Override
public void onFailed(int code) {
}
@Override
public void onException(Throwable exception) {
}
});
位置消息发送
地理位置消息创建原型:
java/**
* 创建一条地理位置信息
*
* @param sessionId 聊天对象ID
* @param sessionType 会话类型
* @param lat 纬度
* @param lng 经度
* @param addr 地理位置描述信息
* @param nosTokenSceneKey 文件资源场景
* @return IMMessage 生成的消息对象
*/
public static IMMessage createLocationMessage(String sessionId, SessionTypeEnum sessionType, double lat, double lng, String addr);
- 参数说明
参数 | 说明 |
---|---|
sessionId | 聊天对象的 ID,如果是单聊,为用户帐号,如果是群聊,为群组 ID |
sessionType | 聊天类型,SessionTypeEnum.P2P 为单聊类型,SessionTypeEnum.Team 为群聊类型 |
lat | 纬度 |
lng | 经度 |
addr | 地理位置描述信息 |
- 示例
java// 该帐号为示例,请先注册
String account = "testAccount";
// 以单聊类型为例
SessionTypeEnum sessionType = SessionTypeEnum.P2P;
// 纬度
double lat = 30.3;
// 经度
double lng = 120.2;
// 地理位置描述信息
String addr = "杭州";
// 创建地理位置信息
IMMessage message = MessageBuilder.createLocationMessage(account, sessionType, lat, lng, addr);
// 发送给对方
NIMClient.getService(MsgService.class).sendMessage(message, false).setCallback(new RequestCallback<Void>() {
@Override
public void onSuccess(Void param) {
}
@Override
public void onFailed(int code) {
}
@Override
public void onException(Throwable exception) {
}
});
提示消息发送
提示消息(又叫做 Tip 消息)主要用于会话内的通知提醒,可以看做是自定义消息的简化,有独立的消息类型 MsgTypeEnum.tip 。 区别于自定义消息,Tip 消息暂不支持 setAttachment,如果要使用 Attachment 请使用自定义消息。 Tip 消息使用场景例如:进入会话时出现的欢迎消息,或是会话过程中命中敏感词后的提示消息等场景,当然也可以用自定义消息实现,只是相对复杂一些。
提示消息创建原型:
java/**
* 创建一条提示消息
*
* @param sessionId 聊天对象ID
* @param sessionType 会话类型
* @return IMMessage 生成的消息对象
*/
public static IMMessage createTipMessage(String sessionId, SessionTypeEnum sessionType);
- 示例
java// 向群里插入一条Tip消息,使得该群能立即出现在最近联系人列表(会话列表)中,满足部分开发者需求。
Map<String, Object> content = new HashMap<>(1);
content.put("content", "成功创建高级群");
// 创建tip消息,teamId需要开发者已经存在的team的teamId
IMMessage msg = MessageBuilder.createTipMessage(teamId, SessionTypeEnum.Team);
msg.setRemoteExtension(content);
// 自定义消息配置选项
CustomMessageConfig config = new CustomMessageConfig();
// 消息不计入未读
config.enableUnreadCount = false;
msg.setConfig(config);
// 消息发送状态设置为success
msg.setStatus(MsgStatusEnum.success);
// 保存消息到本地数据库,但不发送到服务器
NIMClient.getService(MsgService.class).saveMessageToLocal(msg, true).setCallback(new RequestCallback<Void>() {
@Override
public void onSuccess(Void param) {
}
@Override
public void onFailed(int code) {
}
@Override
public void onException(Throwable exception) {
}
});
自定义消息发送
除了内建消息类型以外,SDK 还支持收发自定义消息类型。SDK 不负责定义和解析自定义消息的具体内容,解释工作由开发者完成。SDK 会将自定义消息存入消息数据库,会和内建消息一并展现在消息记录中。
为了使用更加方便,自定义消息采用附件的方式展示给开发者。体现在 IMMessage
类中,自定义消息的内容会被解析为 MsgAttachment
对象,由于 SDK 并不知道自定义消息的格式,第三方 App 需要注册一个自定义消息解析器。当第三方 App 调用查询查询消息历史的接口,或者是 SDK 收到消息通知第三方 App 时,就能将自定义消息内容转换为一个 MsgAttachment
对象,然后就可以同操作图片消息等带附件消息一样,操作自定义消息了。
创建自定义消息原型
java/**
* 创建一条APP自定义类型消息, 同时提供描述字段,可用于推送以及状态栏消息提醒的展示。
*
* @param sessionId 聊天对象ID
* @param sessionType 会话类型
* @param content 消息简要描述,可通过IMMessage#getContent()获取,主要用于用户推送展示。
* @param attachment 消息附件对象
* @param config 自定义消息配置
* @param nosTokenSceneKey 文件资源场景
* @return 自定义消息
*/
public static IMMessage createCustomMessage(String sessionId, SessionTypeEnum sessionType, String content, MsgAttachment attachment, CustomMessageConfig config);
//或者:创建一条APP自定义类型消息并指定文件(图片、音视、视频...)上传(如果有)时使用的 nos scene
public static IMMessage createCustomMessage(String sessionId, SessionTypeEnum sessionType, String content, MsgAttachment attachment, CustomMessageConfig config, String nosTokenSceneKey)
示例:剪刀石头布
在 demo 中,我们提供了一个用自定义消息实现的“剪刀石头布”的游戏,下面以此为例,详细解析其实现步骤。
首先,我们先定义一个自定义消息附件的基类,负责解析你的自定义消息的公用字段,比如类型等。还可以定义一些公共接口,用于一些便利性的调用。
注意: 实现
MsgAttachment
接口的成员都要实现 Serializable。
java// 先定义一个自定义消息附件的基类,负责解析你的自定义消息的公用字段,比如类型等等。
public abstract class CustomAttachment implements MsgAttachment {
// 自定义消息附件的类型,根据该字段区分不同的自定义消息
protected int type;
CustomAttachment(int type) {
this.type = type;
}
// 解析附件内容。
public void fromJson(JSONObject data) {
if (data != null) {
parseData(data);
}
}
// 实现 MsgAttachment 的接口,封装公用字段,然后调用子类的封装函数。
@Override
public String toJson(boolean send) {
return CustomAttachParser.packData(type, packData());
}
// 子类的解析和封装接口。
protected abstract void parseData(JSONObject data);
protected abstract JSONObject packData();
}
然后,继承这个基类,实现“剪刀石头布”的附件类型。注意,成员变量都要实现 Serializable。
javapublic class GuessAttachment extends CustomAttachment {
// 猜拳类型枚举
public enum Guess {
Shitou(1),
Jiandao(2),
Bu(3),
;
}
private Guess value;
public GuessAttachment() {
super(CustomAttachmentType.Guess);
random();
}
// 解析猜拳类型具体数据
@Override
protected void parseData(JSONObject data) {
value = Guess.enumOfValue(data.getIntValue("value"));
}
// 数据打包
@Override
protected JSONObject packData() {
JSONObject data = new JSONObject();
data.put("value", value.getValue());
return data;
}
private void random() {
int value = new Random().nextInt(3) + 1;
this.value = Guess.enumOfValue(value);
}
}
第三步,实现自定义消息的附件解析器。
javapublic class CustomAttachParser implements MsgAttachmentParser {
// 根据解析到的消息类型,确定附件对象类型
@Override
public MsgAttachment parse(String json) {
CustomAttachment attachment = null;
try {
JSONObject object = JSON.parseObject(json);
int type = object.getInteger("type");
JSONObject data = object.getJSONObject(KEY_DATA);
switch (type) {
case CustomAttachmentType.Guess:
attachment = new GuessAttachment();
break;
default:
attachment = new DefaultCustomAttachment();
break;
}
if (attachment != null) {
attachment.fromJson(data);
}
} catch (Exception e) {
}
return attachment;
}
public static String packData(int type, JSONObject data) {
JSONObject object = new JSONObject();
object.put(KEY_TYPE, type);
if (data != null) {
object.put(KEY_DATA, data);
}
return object.toJSONString();
}
}
最后,将该附件解析器注册到 SDK 中。为了保证生成历史消息时能够正确解析自定义附件,注册一般应放在 Application 的 onCreate 中 的主进程判断语句内完成。
javaif (NIMUtil.isMainProcess(this)) {
// 监听的注册,必须在主进程中。
NIMClient.getService(MsgService.class).registerCustomAttachmentParser(new CustomAttachParser());
}
示例:阅后即焚
若需要发送文件类型消息,例如图片等,可以参考阅后即焚的实现。具体实现步骤如下:
第一步,定义一个自定义的附件类型,并继承 FileAttachment
。注意,成员变量都要实现 Serializable。
javapublic class SnapChatAttachment extends FileAttachment {
private static final String KEY_PATH = "path";
private static final String KEY_SIZE = "size";
private static final String KEY_MD5 = "md5";
private static final String KEY_URL = "url";
public SnapChatAttachment() {
super();
}
public SnapChatAttachment(JSONObject data) {
load(data);
}
@Override
public String toJson(boolean send) {
JSONObject data = new JSONObject();
try {
// 重发使用本地路径
if (!send && !TextUtils.isEmpty(path)) {
data.put(KEY_PATH, path);
}
if (!TextUtils.isEmpty(md5)) {
data.put(KEY_MD5, md5);
}
// 注意:这段代码一定要写。
// SDK在调toJson的时候 父类FileAttachemnt的url才有值。
// 这个值是sdk自动赋值的。
data.put(KEY_URL, url);
data.put(KEY_SIZE, size);
} catch (Exception e) {
e.printStackTrace();
}
return CustomAttachParser.packData(CustomAttachmentType.SnapChat, data);
}
private void load(JSONObject data) {
path = data.getString(KEY_PATH);
md5 = data.getString(KEY_MD5);
url = data.getString(KEY_URL);
size = data.containsKey(KEY_SIZE) ? data.getLong(KEY_SIZE) : 0;
}
}
第二步,实现自定义消息的附件解析器。
javapublic class CustomAttachParser implements MsgAttachmentParser {
// 根据解析到的消息类型,确定附件对象类型
@Override
public MsgAttachment parse(String json) {
CustomAttachment attachment = null;
try {
JSONObject object = JSON.parseObject(json);
int type = object.getInteger("type");
JSONObject data = object.getJSONObject(KEY_DATA);
switch (type) {
case CustomAttachmentType.SnapChat:
return new SnapChatAttachment(data);
default:
attachment = new DefaultCustomAttachment();
break;
}
if (attachment != null) {
attachment.fromJson(data);
}
} catch (Exception e) {
}
return attachment;
}
...
}
最后,将该附件解析器注册到 SDK 中。为了保证生成历史消息时能够正确解析自定义附件,注册一般应放在 Application 的 onCreate 中完成。
javaif (NIMUtil.isMainProcess(this)) {
// 监听的注册,必须在主进程中。
NIMClient.getService(MsgService.class).registerCustomAttachmentParser(new CustomAttachParser());
}
消息属性设置
发送消息时可以设置消息配置选项 CustomMessageConfig
,主要用于设定该消息是否存入云端、是否写入漫游等。
- 参数说明
自定义消息配置 CustomMessageConfig 属性
java/**
* 该消息是否要保存到服务器
* 默认为true。
*/
public boolean enableHistory = true;
/**
* 该消息是否需要漫游。
* 默认为true
*/
public boolean enableRoaming = true;
/**
* 当发送方在多个客户端同时登录时,其中一端发送一条消息后,客户端是否需要在收消息的回调抛出该条消息。
* 默认为true
*/
public boolean enableSelfSync = true;
/**
* 该消息是否要推送提醒
* 默认为true
*/
public boolean enablePush = true;
/**
* 该消息是否需要推送昵称
* 默认为true
*/
public boolean enablePushNick = true;
/**
* 该消息是否要计入未读数。
* 默认为true
*/
public boolean enableUnreadCount = true;
/**
* 该消息是否触发抄送。
* 默认为true
*/
public boolean enableRoute = true;
/**
*
* 该消息是否要存离线,若设置为false,将不会存入离线库与云端历史消息库。
* 默认为true
*/
public boolean enablePersist = true;
- 示例
java// 该帐号为示例,请先注册
String account = "testAccount";
// 以单聊类型为例
SessionTypeEnum sessionType = SessionTypeEnum.P2P;
String text = "this is an example";
// 创建一个文本消息
IMMessage textMessage = MessageBuilder.createTextMessage(account, sessionType, text);
// 消息的配置选项
CustomMessageConfig config = new CustomMessageConfig();
// 该消息不保存到服务器
config.enableHistory = false;
// 该消息不漫游
config.enableRoaming = false;
// 该消息不同步
config.enableSelfSync = false;
textMessage.setConfig(config);
// 发送给对方
NIMClient.getService(MsgService.class).sendMessage(textMessage, false).setCallback(new RequestCallback<Void>() {
@Override
public void onSuccess(Void param) {
}
@Override
public void onFailed(int code) {
}
@Override
public void onException(Throwable exception) {
}
});
文件资源场景
SDK支持对图片、语音、视频与文件等设置对应的存活时间。
- 预设文件资源场景
在初始化SDK时,可做相应的文件资源场景配置,参考代码:
java
static SDKOptions getSDKOptions(Context context) {
SDKOptions options = new SDKOptions();
//其他配置
options.mNosTokenSceneConfig = createNosTokenScene();
return options;
}
public static final String TEST_NOS_SCENE_KEY="test_nos_scene_key";
private static NosTokenSceneConfig createNosTokenScene() {
NosTokenSceneConfig nosTokenSceneConfig = new NosTokenSceneConfig();
//更新默认场景(NimNosSceneKeyConstant.NIM_DEFAULT_IM)对应的过期时间(天)
nosTokenSceneConfig.updateDefaultIMSceneExpireTime(1);
//更新默认场景 (NimNosSceneKeyConstant.NIM_DEFAULT_PROFILE) 对应的过期时间(天)
nosTokenSceneConfig.updateDefaultProfileSceneExpireTime(2);
//设置自定义场景及对应的过期时间(天),0代表永不过期。
//建议sceneKey常量化,这样使用的时候比较方便,目前支持自定义最多10种场景
nosTokenSceneConfig.appendCustomScene(TEST_NOS_SCENE_KEY, 4);
return nosTokenSceneConfig;
}
NimNosSceneKeyConstant主要参数一览:
NimNosSceneKeyConstant | 含义 |
---|---|
NIM_DEFAULT_IM | 私聊、群聊、聊天室发送图片、音频、视频、文件消息等。 |
NIM_DEFAULT_PROFILE | 对应使用云信上传服务上传的用户、群组..资料(eg:头像)等。 |
值得注意的是:
- 如果使用了不存在的场景,那么上传将失败(错误码:5)
- 如果文件过期了,再去下载文件,那么会下载失败(错误码:4)
本地消息插入
当有业务场景需要单纯插入一条消息至本地数据库内,而不发出时,可以使用插入本地消息的方法来实现。
java/**
* 插入消息到本地数据库,且通知更新UI界面,但不发送到服务器端。发送一条可设置他人为发送方的本地消息给自己。
* 该接口将消息保存到数据库后,会通知到UI,此时会触发{@link MsgServiceObserve#observeReceiveMessage(Observer, boolean)}通知。
*
* @param msg 待插入的消息对象
* @param fromAccount 发送者ID
* @return InvocationFuture 可以设置回调函数。在消息存入数据库后,就会回调。
*/
InvocationFuture<Void> insertLocalMessage(IMMessage msg, String fromAccount);
/**保存消息到本地数据库,但不发送到服务器端。可设置保存消息的时间 用于第三方APP保存本地提醒一类的消息。 该接口将消息保存到数据库后,如果需要通知到UI,可将notify设置为true,此时会触发{@link MsgServiceObserve.observeReceiveMessage(Observer, boolean)}通知。
* @param msg 待插入的消息对象
* @param notify 是否要通知
* @param time 设置该本地消息的时间
* @return InvocationFuture 可以设置回调函数。在消息存入数据库后,就会回调。
*/
InvocationFuture<java.lang.Void> saveMessageToLocalEx(IMMessage msg,boolean notify,long time);
消息更新
扩展字段更新
SDK支持更新客户端数据库内的消息的客户端扩展字段。
java/**
* 更新消息的LocalExtension
* @param message 待更新的消息
*/
void updateIMMessage(IMMessage message);
状态更新
java/**
* 更新消息状态
* @param message 待更新的消息
*/
void updateIMMessageStatus(IMMessage message);
示例:
javamsg.setStatus(MsgStatusEnum.success);
NIMClient.getService(MsgService.class).updateIMMessageStatus(msg);
注意:请不要对notification
类型消息进行更新。
消息重发
消息发送失败之后,可以重发消息。消息重发和消息发送是同一个接口,只是参数的设置不同而已,当 resend 参数为 true 时,表示重发消息。
消息转发
SDK 支持消息转发功能,但不支持通知消息和音视频通话事件消息的转发,其他消息类型均支持。
首先,通过 MessageBuilder
创建一个待转发的消息,然后通过 MsgService#sendMessage
接口,将消息发送出去。
java/**
* 创建一条待转发的消息
*
* @param message 要转发的消息
* @param sessionId 聊天对象ID
* @param sessionType 会话类型
* @return 待转发的消息
*/
public static IMMessage createForwardMessage(IMMessage message, String sessionId, SessionTypeEnum sessionType);
- 参数说明
参数 | 说明 |
---|---|
message | 要转发的消息 |
sessionId | 聊天对象的 ID,如果是单聊,为用户帐号,如果是群聊,为群组 ID |
sessionType | 聊天类型,SessionTypeEnum.P2P 为单聊类型,SessionTypeEnum.Team 为群聊类型 |
- 示例
java// 该帐号为示例,请先注册
String account = "testAccount";
// 以单聊类型为例
SessionTypeEnum sessionType = SessionTypeEnum.P2P;
// forwardMessage为待转发的消息, 一般由上下文获得
IMMessage message = MessageBuilder.createForwardMessage(forwardMessage, account, sessionType);
// 发送给对方
NIMClient.getService(MsgService.class).sendMessage(textMessage, false).setCallback(new RequestCallback<Void>() {
@Override
public void onSuccess(Void param) {
}
@Override
public void onFailed(int code) {
}
@Override
public void onException(Throwable exception) {
}
});
消息撤回
消息撤回
允许用户撤回一定时间内发送过的消息,客户端可允许撤回时长默认2分钟,可在网易云信控制台配置。
8.5.0起,支持撤回自己发送给自己的消息
- API 原型
java/**
* 消息撤回 , 并设置相应的第三方推送配置(包括IOS平台的推送)与未读数变化,如果想要关闭App内的返回消息提醒,参考{@link NIMClient#toggleRevokeMessageNotification(boolean on)}
*
* @param message 待撤回的消息
* @param customApnsText 第三方透传消息推送文本,不填则不推送
* @param pushPayload 第三方自定义的推送属性,限制json类型,长度2048
* @param shouldNotifyBeCount 撤回通知是否更新未读数
* @param postscript 附言
* @param attach 扩展字段
*
* @return InvocationFuture 可设置回调函数,监听发送结果。
*/
InvocationFuture<Void> revokeMessage(IMMessage message, String customApnsText,
Map<String, Object> pushPayload, boolean shouldNotifyBeCount,
String postscript, String attach);
- 参数说明
参数 | 说明 |
---|---|
message | 待撤回的消息 |
customApnsText | 第三方透传消息推送文本,不填则不推送 |
pushPayload | 第三方自定义的推送属性,限制json类型,长度2048 |
shouldNotifyBeCount | 撤回通知是否更新未读数 |
postscript | 附言 |
attach | 扩展字段 |
- 示例
javaNIMClient.getService(MsgService.class).revokeMessage(message, null, null, true, postscript, attachJson).setCallback(new RequestCallbackWrapper<Void>() {
@Override
public void onResult(int code, Void result, Throwable exception) {
}
});
在撤回消息请求调用成功后, SDK 会先回调给上层成功,再自动将本地的这条消息删除。如果需要在撤回后显示一条本方已撤回的提示,开发者可以自行构造一条提醒消息并调用插入本地消息的方法。
以下情况消息撤回会失败:
- 消息为空
- 消息没有发送成功
- 消息超过撤回时限
针对撤回场景的通知栏内容覆盖需求:如A发消息给B,产生APNs推送,文案内容为“你好“。然后A撤回了这条消息,此时通知栏中的“你好”变为预设的“对方撤回了一条消息”。
一种建议的实现方式是:
- 在发送消息时,需要通过 NIMMessage - setPushPayload(Map pushPayload)方法 插入key为apns-collapse-id的键值对,value的内容建议使用uuid等字符串,用以唯一标识该消息。
- 当要撤回这条消息时,在撤回接口传参 customApnsText 中设置覆盖文案,在 pushPayload 中插入与被撤回消息相同的apns-collapse-id键值对。
监听消息撤回
被撤回方会收到消息撤回通知。
- API 原型
java/**
* 注册/注销消息撤回的观察者
* @param observer 观察者,参数为被撤回的消息。
* @param register true为注册,false为注销
*/
public void observeRevokeMessage(Observer<RevokeMsgNotification> observer, boolean register);
- RevokeMsgNotification 说明
方法 | 说明 |
---|---|
getMessage() | 获取撤回消息 |
getAttach() | 获取撤回附件字段 |
getRevokeAccount() | 获取撤回者 |
getCustomInfo() | 获取消息撤回时设置的msg 字段(eg: 通过服务端API撤回)。 |
getNotificationType() | 获取通知类型: 1表示是离线通知,2表示是漫游通知 , 默认 0 |
getRevokeType() | 获取撤回类型:分为点对点双向撤回, 群双向撤回, 超大群双向撤回, 点对点单向撤回和未定义 |
getCallbackExt() | 获取第三方扩展字段 |
- 示例
javaObserver<RevokeMsgNotification> revokeMessageObserver = new Observer<RevokeMsgNotification>() {
@Override
public void onEvent(RevokeMsgNotification notification) {
// 监听到消息撤回的通知,可以在界面做相应的操作
// 获取撤回消息
notification.getMessage();
// 获取撤回者
notification.getRevokeAccount();
}
};
NIMClient.getService(MsgServiceObserve.class).observeRevokeMessage(revokeMessageObserver, true);
此外,若启用消息提醒功能,则收到撤回通知时,也会触发产生提醒通知栏。若不需要,可以通过
javaNIMClient.toggleRevokeMessageNotification(false);
来关闭,详见撤回通知消息提醒。
撤回是否展示通知的过滤器设置
设置一个过滤器,根据撤回通知对象判断是否应该展示通知栏。
如果其他逻辑判断为应该上通知栏,则由此过滤器决定是否上通知栏;如果其他逻辑判断为不应该上通知栏,则无论过滤器如何配置,都不会上通知栏
该过滤器可以用于减少上通知栏的撤回消息通知的数量
- API原型
java/**
* 注册是否在撤回消息时展示通知的过滤器
*/
void registerShouldShowNotificationWhenRevokeFilter(ShowNotificationWhenRevokeFilter filter);
- ShowNotificationWhenRevokeFilter原型
javapublic interface ShowNotificationWhenRevokeFilter {
boolean showNotification(RevokeMsgNotification notification);
}
- 示例
javaNIMClient.getService(MsgService.class).registerShouldShowNotificationWhenRevokeFilter(notification -> {
return notification == null || TextUtils.isEmpty(notification.getAttach());
});
文件传输过程管理
监听文件传输进度
SDK提供文件传输管理功能,开发可以通过注册消息附件上传/下载进度观察者来监控文件传输。
java/**
* 注册/注销消息附件上传/下载进度观察者
*
* @param observer 观察者, 参数为附件的传输进度
* @param register true为注册,false为注销
*/
void observeAttachmentProgress(Observer<AttachmentProgress> observer,
boolean register);
取消上传消息附件
MsgService 接口提供了取消上传消息附件的方法。
java/**
* 取消上传消息附件(图片、视频、文件类型的),如果附件已经上传成功,操作将会失败 。如果成功取消了附件的上传,那么相应的消息会发送失败,对应的消息状态是MsgStatusEnum.fail,附件状态是AttachStatusEnum.cancel。注意:此操作暂时不支持聊天室。
* @param imMessage 要取消上传附件的消息
*/
InvocationFuture<java.lang.Void> cancelUploadAttachment(IMMessage imMessage);
语音消息处理
云信 SDK 提供了高清语音的录制与播放的功能,用于处理语音消息。
播放
云信提供 AudioPlayer 类来支持语音播放的功能。
AudioPlayer 接口说明:
返回值 | AudioPlayer 接口 | 说明 |
---|---|---|
long | getCurrentPosition() | 获取当前音频播放进度 |
long | getDuration() | 获取音频持续时间长度 |
OnPlayListener | getOnPlayListener() | 获取 AudioPlayer 的播放进度监听 |
boolean | isPlaying() | 查询是否正在播放 |
void | seekTo(int msec) | 让播放器跳转到指定位置继续播放 |
void | setDataSource(String audioFile) | 设置音频来源 |
void | setOnPlayListener(OnPlayListener listener) | 设置播放监听 |
void | start(int audioStreamType) | 开始播放 |
void | stop() | 停止播放 |
构造播放实例
- API 原型
java/**
* 音频播放器构造函数
* @param context 上下文参数
* @param audioFile 待播放音频的文件路径
* @param listener 播放进度监听者
*/
public AudioPlayer(Context context, String audioFile, OnPlayListener listener);
- 参数说明
参数 | 说明 |
---|---|
context | 上下文参数 |
audioFile | 待播放音频的文件路径 |
listener | 播放进度监听者 |
OnPlayListener 接口说明:
OnPlayListener 接口 | 说明 |
---|---|
onCompletion() | 播放完成 |
onError(String error) | 播放过程中出错。参数为出错原因描述 |
onInterrupt() | 中断播放 |
onPlaying(long curPosition) | 播放进度报告,每隔 500ms 会回调一次,告诉当前进度。 参数为当前进度,单位为毫秒,可用于更新 UI |
onPrepared() | 文件解码完成,准备播放 |
- 示例
java// 定义一个播放进程回调类
OnPlayListener listener = new OnPlayListener() {
// 音频转码解码完成,会马上开始播放了
public void onPrepared() {}
// 播放结束
public void onCompletion() {}
// 播放被中断了
public void onInterrupt() {}
// 播放过程中出错。参数为出错原因描述
public void onError(String error){}
// 播放进度报告,每隔 500ms 会回调一次,告诉当前进度。 参数为当前进度,单位为毫秒,可用于更新 UI
public void onPlaying(long curPosition) {}
};
// 构造播放器对象
AudioPlayer player = new AudioPlayer(context, filePath, listener);
播放控制
- 播放音频
java// 开始播放。需要传入一个 audioStreamType 参数,表示是用听筒播放还是扬声器。
// AudioManager.STREAM_VOICE_CALL 表示使用听筒模式
// AudioManager.STREAM_MUSIC 表示使用扬声器模式
player.start(audioStreamType);
- 指定播放起点
java// 如果中途切换播放设备,重新调用 start,传入指定的 audioStreamType 即可。player 会自动停止播放,然后再以新的 streamType 重新开始播放。
// 如果需要从中断的地方继续播放,需要开发者记住已经播放到的位置,然后在 onPrepared 回调中调用 seekTo
player.seekTo(pausedPosition);
- 停止播放
javaplayer.stop();
- 其他方法
java// 获取当前音频播放进度
player.getCurrentPosition();
// 获取音频持续时间长度
player.getDuration();
// 查询是否正在播放
player.isPlaying();
// 设置音频来源
player.setDataSource(audioFile);
录制
SDK 提供 AudioRecorder 来支持语音的录制。
AudioRecorder 接口说明:
返回值 | AudioRecorder 接口 | 说明 |
---|---|---|
void | completeRecord(boolean cancel) | 完成(结束)录音,根据参数 cancel,做不同的回调。 如果 cancel 为 true,回调 IAudioRecordCallback#onRecordCancel, 为 false,回调 IAudioRecordCallback#onRecordSuccess |
void | destroyAudioRecorder() | 释放资源 |
int | getCurrentRecordMaxAmplitude() | 获取当前录音时最大振幅, 40ms 更新一次数据 |
void | handleEndRecord(boolean isSuccess, int duration) | 处理录制结束后的操作,回调 IAudioRecordCallback#onRecordSuccess |
boolean | isRecording() | 是否正在录音 |
void | startRecord() | 启动(开始)录音,如果成功,会按照顺序回调 IAudioRecordCallback#onRecordReady 和 IAudioRecordCallback#onRecordStart |
构造录制实例
- API 原型
java/**
* 构造函数
*
* @param context 上下文
* @param recordType 录制音频类型(aac/amr)
* @param maxDuration 最长录音时长,到该长度后,会自动停止录音
* @param cb 录音过程回调
*/
public AudioRecorder(Context context, RecordType recordType,int maxDuration, IAudioRecordCallback cb);
- 参数说明
参数 | 说明 |
---|---|
context | 上下文 |
recordType | 录制音频类型(aac/amr) |
maxDuration | 最长录音时长,到该长度后,会自动停止录音 |
cb | 录音过程回调 |
- IAudioRecordCallback 接口说明:
IAudioRecordCallback 接口 | 说明 |
---|---|
onRecordCancel() | 录音结束, 用户主动取消录音 |
onRecordFail() | 录音结束,出错 |
onRecordReachedMaxTime(int maxTime) | 到达指定的最长录音时间 |
onRecordReady() | 录音器已就绪,提供此接口用于在录音前关闭本地音视频播放(可选) |
onRecordStart(File audioFile, RecordType recordType) | 开始录音回调 |
onRecordSuccess(File audioFile, long audioLength, RecordType recordType) | 录音结束,成功 |
- 示例
java// 定义录音过程回调对象
IAudioRecordCallback callback = new IAudioRecordCallback () {
void onRecordReady() {
// 初始化完成回调,提供此接口用于在录音前关闭本地音视频播放(可选)
}
void onRecordStart(File audioFile, RecordType recordType) {
// 开始录音回调
}
void onRecordSuccess(File audioFile, long audioLength, RecordType recordType) {
// 录音结束,成功
}
void onRecordFail() {
// 录音结束,出错
}
void onRecordCancel() {
// 录音结束, 用户主动取消录音
}
void onRecordReachedMaxTime(int maxTime) {
// 到达指定的最长录音时间
}
};
// 初始化recorder
AudioRecorder recorder = new AudioRecorder(
context,
RecordType.AAC, // 录制音频类型(aac/amr)
maxDuration, // 最长录音时长,到该长度后,会自动停止录音, 默认120s
callback // 录音过程回调
);
录制控制
- 录制音频
java// 启动(开始)录音,如果成功,会按照顺序回调onRecordReady和onRecordStart。
recorder.startRecord();
- 结束/取消录制
java// 结束录音, 正常结束,或者取消录音
// cancel为true,代表取消;为false,代表结束录音。
recorder.completeRecord(cancel);
- 销毁实例
javarecorder.destroyAudioRecorder();
- 其他方法
java
// 是否正在录音
recorder.isRecording();
// 获取当前录音时最大振幅, 40ms更新一次数据。
recorder.getCurrentRecordMaxAmplitude();
// 录制达到最长录音时长时,确认当前录制
recorder.handleEndRecord(true, maxTime)
语音转文字
要使用语音转文字功能,请联系商务顾问申请开通「语音识别」。如果未开通功能的情况下调用接口,将返回403。
语音转文字的原理:
- 录制音频文件(目前最大支持60秒)。
- 上传到云信存储服务器,返回文件url。
- 通过语音转文字接口传入该url和相关参数,返回转换后的文字。
使用 MsgService 接口中如下方法进行语音转文字:
java/**
* 语音转文字并指定上传文件的场景以及是否要强制重新上传文件
* @param voiceUrl - 语音url。可选项。如果没有,SDK自动做nos上传工作。
* @param path - 语音path, 用于获得语音采样率。APP必须保证音频已经下载到本地
* @param duration - 语音时长
* @param sceneKey - 上传文件时用的nos sceneKey ,默认值:NimNosSceneKeyConstant#NIM_DEFAULT_IM , nos token scene 配置参考文件资源场景章节
* @param enableForceUploadFile - 如果服务器存在相同的文件,是否强制重新上传文件 ,默认false
* AbortableFuture 调用跟踪。可设置回调函数,可中止下载操作
*/
AbortableFuture<java.lang.String> transVoiceToTextEnableForce(java.lang.String voiceUrl,
java.lang.String path,
long duration,
java.lang.String sceneKey,
boolean enableForceUploadFile);
示例:
javapublic void voiceToText(IMMessage msg, String sceneKey) {
AudioAttachment attachment = (AudioAttachment) msg.getAttachment();
String voiceUrl = attachment.getUrl();
String path = attachment.getPath();
refreshStartUI();
callFuture = NIMClient.getService(MsgService.class).transVoiceToTextEnableForce(voiceUrl, path, attachment.getDuration(), sceneKey, false);
callFuture.setCallback(new RequestCallback<String>() {
@Override
public void onSuccess(String param) {
voiceTransText.setText(param);
updateUI();
}
@Override
public void onFailed(int code) {
LogUtil.e(TAG, "voice to text failed, code=" + code);
voiceTransText.setText(R.string.trans_voice_failed);
failIcon.setVisibility(View.VISIBLE);
updateUI();
}
@Override
public void onException(Throwable exception) {
LogUtil.e(TAG, "voice to text throw exception, e=" + exception.getMessage());
voiceTransText.setText("参数错误");
failIcon.setVisibility(View.VISIBLE);
updateUI();
}
});
show();
}