IM 即时通讯
Android
开发指南

自定义消息收发

更新时间: 2023/10/19 11:27:47

除了内置消息类型以外,网易云信 NIM Android SDK 还支持收发自定义消息。

功能介绍

SDK 不负责定义和解析自定义消息的具体内容,解析工作由开发者完成。SDK 会将自定义消息存入消息数据库,会和内置消息一并展现在消息记录中。

为了使用更加方便,自定义消息采用附件的方式展示给开发者。体现在IMMessage类中,自定义消息的内容会被解析为MsgAttachment对象。由于 SDK 并不知道自定义消息的格式,您的应用需要注册一个自定义消息解析器。当您的应用调用查询消息历史的方法,或者 SDK 收到消息通知您的应用时,就能将自定义消息内容转换为一个MsgAttachment对象,然后就可参考多媒体消息收发的实现方式,实现自定义消息的收发。

MsgAttachment的长度上限为 5000 字符。

前提条件

  • 初始化 SDK
  • (如发送的为群聊消息)已创建群组。

API使用限制

发送消息(sendMessage)的方法调用存在频控,一分钟内默认最多可调用 300 次。

实现方法

以下给出了两个自定义消息实现的示例。您也可以参照 视频教程:自定义消息集成 了解实现方法。

示例:剪刀石头布

本节以“剪刀石头布”的游戏为例,介绍实现自定义消息收发的流程。

  1. 定义一个自定义消息附件的基类,负责解析您的自定义消息的公用字段,比如类型等。还可以定义一些公共接口,用于一些便利性的调用。

    实现 MsgAttachment 接口的成员都要实现 Serializable。

    // 先定义一个自定义消息附件的基类,负责解析你的自定义消息的公用字段,比如类型等等。
    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();
    }
    
  2. 继承这个基类,实现“剪刀石头布”的附件类型。

    成员变量都要实现 Serializable。

    public 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);
        }
    }
    
    
  3. 实现自定义消息的附件解析器。

    public 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();
        }
    }
    
  4. 将该附件解析器注册到 SDK 中。为了保证生成历史消息时能够正确解析自定义附件,注册一般应放在 Application 的 onCreate 中 的主进程判断语句内完成。

    if (NIMUtil.isMainProcess(this)) {
        // 监听的注册,必须在主进程中。
        NIMClient.getService(MsgService.class).registerCustomAttachmentParser(new CustomAttachParser()); 
    }
    
  5. 参考多媒体消息收发的实现方式,实现自定义消息的收发。

示例:阅后即焚

若需要发送文件类型消息,例如图片等,可以参考阅后即焚的实现。具体实现步骤如下:

  1. 定义一个自定义的附件类型,并继承 FileAttachment。注意,成员变量都要实现 Serializable。

    public 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;
        }
    }
    
  2. 实现自定义消息的附件解析器。

    public 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;
        }
        ...
    }
    
  3. 将该附件解析器注册到 SDK 中。为了保证生成历史消息时能够正确解析自定义附件,注册一般应放在 Application 的 onCreate 中完成。

    if (NIMUtil.isMainProcess(this)) {
        // 监听的注册,必须在主进程中。
        NIMClient.getService(MsgService.class).registerCustomAttachmentParser(new CustomAttachParser()); 
    }
    
  4. 参考多媒体消息收发的实现方式,实现自定义消息的收发。

API参考

SDK 的MessageBuilder类提供多个构建自定义消息的方法,具体如下:

参考文档

本文档介绍的是不含 UI 的自定义消息收发实现流程,若需要实现含 UI 的自定义消息收发,请参考 UIKit 相关文档:实现自定义消息收发

此文档是否对你有帮助?
有帮助
去反馈
  • 功能介绍
  • 前提条件
  • API使用限制
  • 实现方法
  • 示例:剪刀石头布
  • 示例:阅后即焚
  • API参考
  • 参考文档