tencent cloud

文档反馈

Android & iOS & Mac

最后更新时间:2022-09-08 18:18:47

    功能描述

    • 通过 addSimpleMsgListener 监听接收文本、自定义消息,相关回调在 V2TIMSimpleMsgListener 协议中定义。
    • 通过 addAdvancedMsgListener 监听接收所有类型消息(文本、自定义、富媒体消息),相关回调在 V2TIMAdvancedMsgListener 协议中定义。

    设置消息监听器

    SDK 提供了 2 种消息监听器,简单消息监听器 V2TIMSimpleMsgListener 和高级消息监听器 V2TIMAdvancedMsgListener
    两者的区别在于:

    1. 简单消息监听器只能接收文本、自定义消息。如果您的业务只需要这两种消息,可以仅使用简单消息监听器。
    2. 高级消息监听器可以接收所有类型的消息。如果您的业务还需要支持富媒体、合并消息等其他类型,请使用高级消息监听器。
    注意:

    1. addSimpleMsgListeneraddAdvancedMsgListener 请使用其中之一,切勿混用,以免产生不可预知的逻辑 bug。
    2. 如果想要正常接收下面各种类型的消息,必须先添加消息监听器,否则无法正常接收。

    简单消息监听器

    添加监听器

    接收方调用 addSimpleMsgListener (Android / iOS & Mac) 添加简单消息监听器。一般建议在比较靠前的时间点调用,例如聊天消息界面初始化后,确保 App 能及时收到消息。

    示例代码如下:

    V2TIMManager.getInstance().addSimpleMsgListener(simpleMsgListener);
    

    监听器回调事件

    添加成功简单消息监听器后,接收方可以在 V2TIMSimpleMsgListener (Android / iOS & Mac) 的回调中接收不同类型消息,说明如下:

    public abstract class V2TIMSimpleMsgListener {
    // 收到 C2C 文本消息
    public void onRecvC2CTextMessage(String msgID, V2TIMUserInfo sender, String text) {}
        // 收到 C2C 自定义(信令)消息
    public void onRecvC2CCustomMessage(String msgID, V2TIMUserInfo sender, byte[] customData) {}
        // 收到群文本消息
    public void onRecvGroupTextMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, String text) {}
        // 收到群自定义(信令)消息
    public void onRecvGroupCustomMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, byte[] customData) {}
    }
    

    移除监听器

    如果想停止接收消息,接收方可调用 removeSimpleMsgListener (Android / iOS & Mac) 移除简单消息监听器。

    示例代码如下:

    V2TIMManager.getInstance().removeSimpleMsgListener(simpleMsgListener);
    

    高级消息监听器

    添加监听器

    接收方调用 addAdvancedMsgListener (Android / iOS & Mac) 添加高级消息监听器。一般建议在比较靠前的时间点调用,例如例如聊天消息界面初始化后,确保 App 能及时收到消息。

    示例代码如下:

    V2TIMManager.getMessageManager().addAdvancedMsgListener(advancedMsgListener);
    

    监听器回调事件

    添加成功高级消息监听器后,接收方可以在 V2TIMAdvancedMsgListener (Android / iOS & Mac) 的回调中接收不同类型消息,说明如下:

    public abstract class V2TIMAdvancedMsgListener {
    // 收到新消息
    public void onRecvNewMessage(V2TIMMessage msg) {}
        // C2C 对端用户会话已读通知(对端用户调用 markC2CMessageAsRead,自己会收到该通知)
    public void onRecvC2CReadReceipt(List<V2TIMMessageReceipt> receiptList) {}
        // 消息已读回执通知(如果自己发送的消息支持已读回执,消息接收端调用 sendMessageReadReceipts,自己会收到该通知)
    public void onRecvMessageReadReceipts(List<V2TIMMessageReceipt> receiptList) {}
        // 收到消息撤回的通知
    public void onRecvMessageRevoked(String msgID) {}
        // 消息内容被修改
    public void onRecvMessageModified(V2TIMMessage msg) {}
    }
    

    移除监听器

    如果想停止接收消息,接收方可调用 removeAdvancedMsgListener (Android / iOS & Mac) 移除高级消息监听器。

    示例代码如下:

    V2TIMManager.getMessageManager().removeAdvancedMsgListener(advancedMsgListener);
    

    接收文本消息

    使用简单消息监听器接收

    单聊文本消息

    接收方使用简单消息监听器接收单聊文本消息,需要以下几步:

    1. 调用 addSimpleMsgListener 设置事件监听器。
    2. 监听 onRecvC2CTextMessage (Android / iOS & Mac) 回调,在其中接收文本消息。
    3. 希望停止接收消息,调用 removeSimpleMsgListener 移除监听。该步骤不是必须的,客户可以按照业务需求调用。

    代码示例如下:

    // 设置事件监听器
    V2TIMManager.getInstance().addSimpleMsgListener(simpleMsgListener);
    // 接收单聊文本消息
    /**
    * 收到 C2C 文本消息
    *
    * @param msgID 消息唯一标识
    * @param sender 发送方信息
    * @param text 发送内容
    */
    public void onRecvC2CTextMessage(String msgID, V2TIMUserInfo sender, String text) {
    // 可解析消息并展示到 UI
    }
    

    群聊文本消息

    接收方使用简单消息监听器接收群聊文本消息,需要以下几步:

    1. 调用 addSimpleMsgListener 设置事件监听器。
    2. 监听 onRecvGroupTextMessage (Android / iOS & Mac) 回调,在其中接收文本消息。
    3. 希望停止接收消息,调用 removeSimpleMsgListener 移除监听。该步骤不是必须的,客户可以按照业务需求调用。

    代码示例如下:

    // 设置事件监听器
    V2TIMManager.getInstance().addSimpleMsgListener(simpleMsgListener);
    // 接收群聊文本消息
    /**
    * 收到群文本消息
    *
    * @param msgID 消息唯一标识
    * @param groupID 群 ID
    * @param sender 发送方群成员信息
    * @param text 发送内容
    */
    public void onRecvGroupTextMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, String text) {
    // 可解析消息并展示到 UI
    }
    

    使用高级消息监听器接收

    接收方使用高级消息监听器接收单聊、群聊文本消息,需要以下几步:

    1. 调用 addAdvancedMsgListener 设置事件监听器。
    2. 监听 onRecvNewMessage (Android / iOS & Mac) 回调,在其中接收文本消息。
    3. 希望停止接收消息,调用 removeAdvancedMsgListener 移除监听。该步骤不是必须的,客户可以按照业务需求调用。

    代码示例如下:

    // 设置事件监听器
    V2TIMManager.getMessageManager().addAdvancedMsgListener(advancedMsgListener);
    /**
    * 收到新消息
    * @param msg 消息
    */
    public void onRecvNewMessage(V2TIMMessage msg) {
    // 解析出 groupID 和 userID
    String groupID = msg.getGroupID();
    String userID = msg.getUserID();
        // 判断当前是单聊还是群聊:
    // 如果 groupID 不为空,表示此消息为群聊;如果 userID 不为空,表示此消息为群聊
        // 解析出 msg 中的文本消息
    if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) {
        V2TIMTextElem textElem = msg.getTextElem();
        String text = textElem.getText();
        Log.i("onRecvNewMessage", "text:" + text);
    }
    }
    

    接收自定义消息

    使用简单消息监听器接收

    单聊自定义消息

    接收方使用简单消息监听器接收单聊自定义消息,需要以下几步:

    1. 调用 addSimpleMsgListener 设置事件监听器。
    2. 监听 onRecvC2CCustomMessage (Android / iOS & Mac) 回调,在其中接收单聊自定义消息。
    3. 希望停止接收消息,调用 removeSimpleMsgListener 移除监听。该步骤不是必须的,客户可以按照业务需求调用。

    代码示例如下:

    /**
    * 接收单聊自定义消息
    * @param msgID 消息 ID
    * @param sender 发送方信息
    * @param customData 发送内容
    */
    public void onRecvC2CCustomMessage(String msgID, V2TIMUserInfo sender, byte[] customData) {
    Log.i("onRecvC2CCustomMessage", "msgID:" + msgID + ", from:" + sender.getNickName() + ", content:" + new String(customData));
    }
    

    群聊自定义消息

    接收方使用简单消息监听器接收群聊自定义消息,需要以下几步

    1. 调用 addSimpleMsgListener 设置事件监听器。
    2. 监听 onRecvGroupCustomMessage (Android / iOS & Mac) 回调,在其中接收群聊自定义消息。
    3. 希望停止接收消息,调用 removeSimpleMsgListener 移除监听。该步骤不是必须的,客户可以按照业务需求调用。

    /**
    * 接收群聊自定义消息
    * @param msgID 消息 ID
    * @param groupID 群 ID
    * @param sender 发送方群成员信息
    * @param customData 发送内容
    */
    public void onRecvGroupCustomMessage(String msgID, String groupID, V2TIMGroupMemberInfo sender, byte[] customData) {
    Log.i("onRecvGroupCustomMessage", "msgID:" + msgID + ", groupID:" + groupID + ", from:" + sender.getNickName() + ", content:" + new String(customData));
    }
    

    使用高级消息监听器接收

    接收方使用高级消息监听器接收单聊、群聊自定义消息,需要以下几步:

    1. 调用 addAdvancedMsgListener 设置事件监听器。
    2. 监听 onRecvNewMessage (Android / iOS & Mac) 回调,在其中接收自定义消息。
    3. 希望停止接收消息,调用 removeAdvancedMsgListener 移除监听。该步骤不是必须的,客户可以按照业务需求调用。

    代码示例如下:

    // 设置事件监听器
    V2TIMManager.getMessageManager().addAdvancedMsgListener(v2TIMAdvancedMsgListener);
    // 接收消息
    public void onRecvNewMessage(V2TIMMessage msg) {
    // 解析出 groupID 和 userID
    String groupID = msg.getGroupID();
    String userID = msg.getUserID();
        // 判断当前是单聊还是群聊:
    // 如果 groupID 不为空,表示此消息为群聊;如果 userID 不为空,表示此消息为群聊
        // 解析出 msg 中的自定义消息
    if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_CUSTOM) {
        V2TIMCustomElem customElem = msg.getCustomElem();
        String data = new String(customElem.getData());
        Log.i("onRecvNewMessage", "customData:" + data);
    }
    }
    

    接收富媒体消息

    接收富媒体消息只能使用高级消息监听器,需要以下几步:

    1. 接收方调用 addAdvancedMsgListener 接口设置高级消息监听。
    2. 接收方通过监听回调 onRecvNewMessage (Android / iOS & Mac) 获取消息 V2TIMMessage。
    3. 接收方解析 V2TIMMessage 消息中的 elemType 属性,并根据其类型进行二次解析,获取消息内部 Elem 中的具体内容。
    4. 希望停止接收消息,调用 removeAdvancedMsgListener 移除监听。该步骤不是必须的,客户可以按照业务需求调用。

    图片消息

    一个图片消息会包含三种格式大小的图片,分别为原图、大图、微缩图(SDK 会在发送图片消息的时候自动生成微缩图、大图,客户不需要关心):

    • 大图:将原图等比压缩。压缩后宽、高中较小的一个等于 720 像素。
    • 缩略图:将原图等比压缩。压缩后宽、高中较小的一个等于 198 像素。

    接收端收到图片消息后,我们推荐您调用 SDK 的 downloadImage (Android / iOS & Mac) 将图片下载到本地,再取出图片渲染到 UI 层。

    为了避免重复下载,节省资源,我们推荐您将 V2TIMImage 对象的 uuid 属性值设置到图片的下载路径中,作为图片的标识。

    示例代码向您演示如何从 V2TIMMessage 中解析出图片消息内容:

    public void onRecvNewMessage(V2TIMMessage msg) {
    if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE) {
        // 图片消息
        V2TIMImageElem v2TIMImageElem = msg.getImageElem();
        // 一个图片消息会包含三种格式大小的图片,分别为原图、大图、微缩图(SDK 会在发送图片消息的时候自动生成微缩图、大图,客户不需要关心)
        // 大图:是将原图等比压缩,压缩后宽、高中较小的一个等于720像素。
        // 缩略图:是将原图等比压缩,压缩后宽、高中较小的一个等于198像素。
        List<V2TIMImageElem.V2TIMImage> imageList = v2TIMImageElem.getImageList();
        for (V2TIMImageElem.V2TIMImage v2TIMImage : imageList) {
            // 图片 ID,内部标识,可用于外部缓存 key
            String uuid = v2TIMImage.getUUID();
            // 图片类型
            int imageType = v2TIMImage.getType();
            // 图片大小(字节)
            int size = v2TIMImage.getSize();
            // 图片宽度
            int width = v2TIMImage.getWidth();
            // 图片高度
            int height = v2TIMImage.getHeight();
            // 设置图片下载路径 imagePath,这里可以用 uuid 作为标识,避免重复下载
            String imagePath = "/sdcard/im/image/" + "myUserID" + uuid;
            File imageFile = new File(imagePath);
            // 判断 imagePath 下有没有已经下载过的图片文件
            if (!imageFile.exists()) {
                // 下载图片
                v2TIMImage.downloadImage(imagePath, new V2TIMDownloadCallback() {
                    @Override
                    public void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {
                        // 下载进度回调:已下载大小 v2ProgressInfo.getCurrentSize();总文件大小 v2ProgressInfo.getTotalSize()
                    }
                    @Override
                    public void onError(int code, String desc) {
                        // 下载失败
                    }
                    @Override
                    public void onSuccess() {
                        // 下载完成
                    }
                });
            } else {
                // 图片已存在
            }
        }
    }
    }
    

    视频消息

    接收方收到视频消息后,一般需要在聊天界面显示一个视频预览图,当用户点击消息后,才会触发视频的播放。
    所以这里需要两步:

    1. 下载视频截图。我们推荐您调用 SDK 的 downloadSnapshot (Android / iOS & Mac) 进行下载。
    2. 下载视频。我们推荐您调用 SDK 的 downloadVideo (Android / iOS & Mac) 进行下载。

    为了避免重复下载,节省资源,我们推荐您将 V2TIMVideoElem 对象的 videoUUID 属性值设置到视频的下载路径中,作为视频的标识。

    示例代码向您演示如何从 V2TIMMessage 中解析出视频消息内容:

    public void onRecvNewMessage(V2TIMMessage msg) {
    if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_VIDEO) {
        // 视频消息
        V2TIMVideoElem v2TIMVideoElem = msg.getVideoElem();
        // 视频截图 ID,内部标识,可用于外部缓存 key
        String snapshotUUID = v2TIMVideoElem.getSnapshotUUID();
        // 视频截图文件大小
        int snapshotSize = v2TIMVideoElem.getSnapshotSize();
        // 视频截图宽
        int snapshotWidth = v2TIMVideoElem.getSnapshotWidth();
        // 视频截图高
        int snapshotHeight = v2TIMVideoElem.getSnapshotHeight();
        // 视频 ID,内部标识,可用于外部缓存 key
        String videoUUID = v2TIMVideoElem.getVideoUUID();
        // 视频文件大小
        int videoSize = v2TIMVideoElem.getVideoSize();
        // 视频时长
        int duration = v2TIMVideoElem.getDuration();
        // 设置视频截图文件路径,这里可以用 uuid 作为标识,避免重复下载
        String snapshotPath = "/sdcard/im/snapshot/" + "myUserID" + snapshotUUID;
        File snapshotFile = new File(snapshotPath);
        if (!snapshotFile.exists()) {
            v2TIMVideoElem.downloadSnapshot(snapshotPath, new V2TIMDownloadCallback() {
                @Override
                public void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {
                    // 下载进度回调:已下载大小 v2ProgressInfo.getCurrentSize();总文件大小 v2ProgressInfo.getTotalSize()
                }
                @Override
                public void onError(int code, String desc) {
                    // 下载失败
                }
                @Override
                public void onSuccess() {
                    // 下载完成
                }
            });
        } else {
            // 文件已存在
        }
            // 设置视频文件路径,这里可以用 uuid 作为标识,避免重复下载
        String videoPath = "/sdcard/im/video/" + "myUserID" + videoUUID;
        File videoFile = new File(videoPath);
        if (!videoFile.exists()) {
            v2TIMVideoElem.downloadVideo(videoPath, new V2TIMDownloadCallback() {
                @Override
                public void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {
                // 下载进度回调:已下载大小 v2ProgressInfo.getCurrentSize();总文件大小 v2ProgressInfo.getTotalSize()
                }
                @Override
                public void onError(int code, String desc) {
                // 下载失败
                }
                @Override
                public void onSuccess() {
                // 下载完成
                }
            });
        } else {
            // 文件已存在
        }
    }
    }
    

    语音消息

    接收端收到语音消息后,我们推荐您调用 SDK 的 downloadSound (Android / iOS & Mac) 将语音下载到本地,再获取本地语音文件播放。

    为了避免重复下载,节省资源,我们推荐您将 V2TIMSoundElem 对象的 uuid 属性值设置到语音的下载路径中,作为语音的标识。

    示例代码向您演示如何从 V2TIMMessage 中解析出语音消息内容:

    public void onRecvNewMessage(V2TIMMessage msg) {
    if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_SOUND) {
        // 语音消息
        V2TIMSoundElem v2TIMSoundElem = msg.getSoundElem();
        // 语音 ID,内部标识,可用于外部缓存 key
        String uuid = v2TIMSoundElem.getUUID();
        // 语音文件大小
        int dataSize = v2TIMSoundElem.getDataSize();
        // 语音时长
        int duration = v2TIMSoundElem.getDuration();
        // 设置语音文件路径 soundPath,这里可以用 uuid 作为标识,避免重复下载
        String soundPath = "/sdcard/im/sound/" + "myUserID" + uuid;
        File imageFile = new File(soundPath);
        // 判断 soundPath 下有没有已经下载过的语音文件
        if (!imageFile.exists()) {
            v2TIMSoundElem.downloadSound(soundPath, new V2TIMDownloadCallback() {
                @Override
                public void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {
                    // 下载进度回调:已下载大小 v2ProgressInfo.getCurrentSize();总文件大小 v2ProgressInfo.getTotalSize()
                }
                @Override
                public void onError(int code, String desc) {
                    // 下载失败
                }
                @Override
                public void onSuccess() {
                    // 下载完成
                }
            });
        } else {
            // 文件已存在
        }
    }
    }
    

    文件消息

    接收端收到文件消息后,我们推荐您调用 SDK 的 downloadFile (Android / iOS & Mac) 将文件下载到本地,再获取本地文件展示。

    为了避免重复下载,节省资源,我们推荐您将 V2TIMFileElem 对象的 uuid 属性值设置到文件的下载路径中,作为文件的标识。

    示例代码向您演示如何从 V2TIMMessage 中解析出文件消息内容:

    public void onRecvNewMessage(V2TIMMessage msg) {
    if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_FILE) {
        // 文件消息
        V2TIMFileElem v2TIMFileElem = msg.getFileElem();
        // 文件 ID,内部标识,可用于外部缓存 key
        String uuid = v2TIMFileElem.getUUID();
        // 文件名称
        String fileName = v2TIMFileElem.getFileName();
        // 文件大小
        int fileSize = v2TIMFileElem.getFileSize();
        // 设置文件路径,这里可以用 uuid 作为标识,避免重复下载
        String filePath = "/sdcard/im/file/" + "myUserID" + uuid;
        File file = new File(filePath);
        if (!file.exists()) {
            v2TIMFileElem.downloadFile(filePath, new V2TIMDownloadCallback() {
                @Override
                public void onProgress(V2TIMElem.V2ProgressInfo progressInfo) {
                    // 下载进度回调:已下载大小 v2ProgressInfo.getCurrentSize();总文件大小 v2ProgressInfo.getTotalSize()
                }
                @Override
                public void onError(int code, String desc) {
                    // 下载失败
                }
                @Override
                public void onSuccess() {
                    // 下载完成
                }
            });
        } else {
            // 文件已存在
        }
    }
    }
    

    地理位置消息

    接收到地理位置消息后,接收放可直接从 V2TIMLocationElem 中解析出经纬度信息。
    示例代码向您演示如何从 V2TIMMessage 中解析出地理位置消息内容:

    public void onRecvNewMessage(V2TIMMessage msg) {
    if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_LOCATION) {
        // 地理位置消息
        V2TIMLocationElem v2TIMLocationElem = msg.getLocationElem();
        // 地理位置信息描述
        String desc = v2TIMLocationElem.getDesc();
        // 经度
        double longitude = v2TIMLocationElem.getLongitude();
        // 纬度
        double latitude = v2TIMLocationElem.getLatitude();
    }
    }
    

    表情消息

    SDK 仅为表情消息提供消息透传的通道,消息内容字段参考 V2TIMFaceElem (Android / iOS & Mac) 定义。其中 indexdata 的内容由客户自定义。

    例如发送方可设置 index = 1, data = "x12345",表示 “微笑“ 表情。
    接收方收到表情消息后解析出 1 和 "x12345",按照预设的规则将其展示为 “微笑“ 表情。

    示例代码向您演示如何从 V2TIMMessage 中解析出表情消息内容:

    public void onRecvNewMessage(V2TIMMessage msg) {
    if (msg.getElemType() == V2TIMMessage.V2TIM_ELEM_TYPE_FACE) {
        // 表情消息
        V2TIMFaceElem v2TIMFaceElem = msg.getFaceElem();
        // 表情所在的位置
        int index = v2TIMFaceElem.getIndex();
        // 表情自定义数据
        byte[] data = v2TIMFaceElem.getData();
    }
    }
    

    接收多个 Elem 的消息

    1. 通过 Message 对象正常解析出第一个 Elem 对象。
    2. 通过第一个 Elem 对象的 nextElem 方法获取下一个 Elem 对象,如果下一个 Elem 对象存在,会返回 Elem 对象实例,如果不存在,会返回 nil/null。

    示例代码如下:

    @Override
    public void onRecvNewMessage(V2TIMMessage msg) {
    // 查看第一个 Elem
    int elemType = msg.getElemType();
    if (elemType == V2TIMMessage.V2TIM_ELEM_TYPE_TEXT) {
        // 文本消息
        V2TIMTextElem v2TIMTextElem = msg.getTextElem();
        String text = v2TIMTextElem.getText();
        // 查看 v2TIMTextElem 后面还有没有更多 elem
        V2TIMElem elem = v2TIMTextElem.getNextElem();
        while (elem != null) {
            // 判断 elem 类型,以 V2TIMCustomElem 为例
            if (elem instanceof V2TIMCustomElem) {
            V2TIMCustomElem customElem = (V2TIMCustomElem) elem;
            byte[] data = customElem.getData();
        }
        // 继续查看当前 elem 后面还有没更多 elem
        elem = elem.getNextElem();
        }
        // elem 如果为 null,表示所有 elem 都已经解析完
    }
    }
    

    联系我们

    联系我们,为您的业务提供专属服务。

    技术支持

    如果你想寻求进一步的帮助,通过工单与我们进行联络。我们提供7x24的工单服务。

    7x24 电话支持