Flutter

消息收发

更新时间: 2024/03/15 16:12:32

NetEase IM Flutter SDK(以下简称“NIM SDK”)支持收发多种消息类型,助您快速实现多样化的消息业务场景。NIM SDK 提供MessageBuilder类和MessageService类,支持构建、监听和收发多种类型的消息。SDK 中定义消息的结构为NIMMessage(不支持继承扩展),不同消息类型以NIMMessageType作区分。发送不同类型消息的方法均为sendMessage。单聊消息和群聊消息都通过该方法发送,通过参数NIMSessionType 设置发送的为单聊消息还是群聊消息。

本文介绍通过网易云信 NIM SDK 实现消息收发的技术原理、前提条件以及具体的实现流程。

  • 聊天室和圈组的消息收发,需单独配置。具体实现流程请分别参见聊天室消息收发圈组消息收发
  • 本文的时序图可能因为网络问题而显示异常。如显示异常,一般刷新当前页面即可正常显示。

技术原理

应用集成 NIM SDK 并完成 SDK 初始化后,消息收发流程如下图所示(本地提示消息通知消息除外)。

上图中的流程可归纳为如下三步:

  1. 账号集成与登录。
    1. 开发者将应用的用户账号传入云信 IM 服务器,注册云信 IM 账号(又称 accid)。
    2. 云信 IM 服务器返回 Token 给应用服务器。
    3. 应用客户端登录应用服务器。
    4. 应用服务器将 Token 返回给应用客户端。
    5. 用户带 Token 登录云信 IM 服务器。
  2. 用户A 发送一条消息到云信 IM 服务器。
  3. 云信 IM 服务器投递消息至其他用户,分为如下两种情况:
    • 如为单聊消息,IM 服务器将其投递至用户B。
    • 如为群聊消息,IM 服务器将其投递至群内其他每一位用户。

上图仅以静态 Token 登录为例展示消息收发流程。网易云信 IM 还支持动态 Token 登录鉴权和第三方回调登录鉴权,相关详情请参见登录鉴权

前提条件

在实现消息收发之前,请确保:

API使用限制

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

实现消息收发

收发文本消息

uml diagram

实现流程

  1. 发送方注册onMessageStatus事件流,监听消息状态变化。

    NimCore.instance.messageService.onMessageStatus.listen((NIMMessage message) {
        // 1、根据sessionId判断是否是自己的消息
        // 2、更改内存中消息的状态
        // 3、刷新界面
    });
    
  2. 接收方注册onMessage事件流和onMessageStatus事件流,分别监听消息接收和消息状态变化。

    NimCore.instance.messageService.onMessage.listen((List<NIMMessage> list) {
        // 处理新收到的消息,为了上传处理方便,SDK 保证参数 messages 全部来自同一个聊天对象。
    });
    
  3. 发送方调用createTextMessage方法,构建一条文本消息。

    通过sessionType参数,可设置发送的文本消息为单聊消息或群聊消息。如设置为群聊消息,请确保已创建相应的群组。

    参数 类型 类型说明
    sessionId String 聊天对象的 ID,根据会话类型sessionType判断
    • 如果是单聊,则sessionId为用户的云信IM帐号(即accid
    • 如果是群聊,则sessionId为群组 ID
    sessionType NIMSessionType 会话类型
    text String 文本消息内容
  4. 发送方调用sendMessage方法,发送已构建的文本消息。

    可通过消息配置选项NIMCustomMessageConfig设置该消息是否存入云端、写入漫游、计入未读数等。具体配置示例请参见消息配置选项


    创建并发送文本消息的示例代码如下:

    // 该帐号为示例
    String account = 'testAccount';
    // 以单聊类型为例
    NIMSessionType sessionType = NIMSessionType.p2p;
    String text = 'this is an example';
    // 创建并且发送一个文本消息
    Future<NIMResult<NIMMessage>> result = MessageBuilder.createTextMessage(
        sessionId: account, sessionType: sessionType, text: text)
        .then((value) => value.isSuccess
        ? NimCore.instance.messageService
            .sendMessage(message: value.data!, resend: false)
        : Future.value(value));
    
  5. 接收方通过onMessage回调收到文本消息。

收发多媒体消息

多媒体消息包括图片消息、语音消息、视频消息和文件消息。

NIM SDK 提供了高清语音的录制与播放的功能,用于处理语音消息。相关详情请参见语音消息处理

API调用时序

uml diagram

实现流程

  1. 发送方注册如下事件流。

    监听消息状态变化
    NimCore.instance.messageService.onMessageStatus.listen((NIMMessage message) {
        // 1、根据sessionId判断是否是自己的消息
        // 2、更改内存中消息的状态
        // 3、刷新界面
    });
    
    监听消息附件上传/下载进度
    NimCore.instance.messageService.onAttachmentProgress.listen((NIMAttachmentProgress process) {
      // todo 根据附件下载/上传进度更新UI
    });
    
  2. 接收方注册如下事件流。

    监听消息接收
    NimCore.instance.messageService.onMessage.listen((List<NIMMessage> list) {
        // 处理新收到的消息,为了上传处理方便,SDK 保证参数 messages 全部来自同一个聊天对象。
    });
    
    监听消息附件上传/下载进度
    NimCore.instance.messageService.onAttachmentProgress.listen((NIMAttachmentProgress process) {
      // todo 根据附件下载/上传进度更新UI
    });
    
  3. 发送方构建多媒体消息。

    消息类型
    构建方法
    多媒体资源云端存储配置
    图片消息 createImageMessage 调用时可指定多媒体资源(图片、语音、视频或文件)在网易对象存储(Netease Object Storage,NOS)服务上的过期时间,具体参见多媒体资源存储场景
    语音消息 createAudioMesssage
    视频消息 createVideoMessage
    文件消息 createFileMessage

    上述方法的部分重要参数说明如下:

    参数 类型 类型说明
    sessionId String 聊天对象的 ID,根据会话类型sessionType判断
    • 如果是单聊,则sessionId为用户的云信IM帐号(即accid
    • 如果是群聊,则sessionId为群组 ID
    sessionType NIMSessionType 会话类型
    filePath String 多媒体资源的文件路径,web 端可传空字符串
  4. 发送方调用sendMessage方法,发送已构建的多媒体消息。

    • 可通过消息配置选项NIMCustomMessageConfig设置该消息是否存入云端、写入漫游、计入未读数等。具体配置示例请参见消息配置选项
    • 发送多媒体消息后可调用cancelUploadAttachment方法取消上传多媒体资源。如果多媒体资源已经上传成功,操作将会失败。如果成功取消了多媒体资源的上传,那么相应的消息会发送失败,对应的消息状态是NIMMessageStatus.fail,附件状态是NIMMessageAttachmentStatus.cancel
    • 如果同一个多媒体消息需要多次发送时,建议控制时序依次发送,避免出现发送失败的问题。

    构建并发送多媒体消息的示例代码如下:

    图片消息
    // 该帐号为示例
        String account = 'testAccount';
    // 以单聊类型为例
        NIMSessionType sessionType = NIMSessionType.p2p;
    // 示例图片,需要开发者在相应目录下有图片
        File file = new File('filePath');
    // 显示名称
        String displayName = 'this is a file';
    // web 端需要base64,其他端可忽略
        String base64 = 'this is base64';
    // 发送图片消息
        Future<NIMResult<NIMMessage>> result =
        MessageBuilder.createImageMessage(
            sessionId: account,
            sessionType: sessionType,
            filePath: file.path,
            fileSize: file.lengthSync(),
            displayName: displayName,
            base64: base64,
            nosScene: NIMNosScene.defaultIm)
            .then((value) => value.isSuccess
            ? NimCore.instance.messageService
            .sendMessage(message: value.data!, resend: false)
            : Future.value(value));
    
    语音消息
    // 该帐号为示例
        String account = 'testAccount';
    // 以单聊类型为例
        NIMSessionType sessionType = NIMSessionType.p2p;
    // 示例音频,需要开发者在相应目录下有文件
        File file = new File('filePath');
    // 显示名称
        String displayName = 'this is a file';
        // web 端需要base64,其他端可忽略 
        String base64 = 'this is base64';
    // 发送语音消息
        Future<NIMResult<NIMMessage>> result =
        MessageBuilder.createAudioMessage(
            sessionId: account,
            sessionType: sessionType,
            filePath: file.path,
            fileSize: file.lengthSync(),
            base64: base64,
            duration: 2000,
            displayName: displayName,
            nosScene: NIMNosScene.defaultIm)
            .then((value) => value.isSuccess
            ? NimCore.instance.messageService
            .sendMessage(message: value.data!, resend: false)
            : Future.value(value));
    
    视频消息
    // 该帐号为示例
    String account = 'testAccount';
    // 以单聊类型为例
        NIMSessionType sessionType = NIMSessionType.p2p;
    // 示例视频,需要开发者在相应目录下有文件
        File file = new File('filePath');
    // 显示名称
        String displayName = 'this is a file';
        // web 端需要base64,其他端可忽略 
        String base64 = 'this is base64';
    // 发送消息
        Future<NIMResult<NIMMessage>> result =
        MessageBuilder.createVideoMessage(
            sessionId: account,
            sessionType: sessionType,
            filePath: file.path,
            fileSize: file.lengthSync(),
            base64: base64,
            duration: 2000,
            width: 1080,
            height: 720,
            displayName: displayName,
            nosScene: NIMNosScene.defaultIm)
            .then((value) => value.isSuccess
            ? NimCore.instance.messageService
            .sendMessage(message: value.data!, resend: false)
            : Future.value(value));
    
    文件消息
    // 该帐号为示例
        String account = 'testAccount';
    // 以单聊类型为例
        NIMSessionType sessionType = NIMSessionType.p2p;
    // 示例文件,需要开发者在相应目录下有文件
        File file = new File('filePath');
    // 显示名称
        String displayName = 'this is a file';
        // web 端需要base64,其他端可忽略 
        String base64 = 'this is base64';
    // 发送消息
        Future<NIMResult<NIMMessage>> result = MessageBuilder.createFileMessage(
            sessionId: account,
            sessionType: sessionType,
            filePath: file.path,
            fileSize: file.lengthSync(),
            base64: base64,
            displayName: displayName,
            nosScene: NIMNosScene.defaultIm)
            .then((value) => value.isSuccess
            ? NimCore.instance.messageService
            .sendMessage(message: value.data!, resend: false)
            : Future.value(value));
    
  5. 接收方通过onMessage事件流的回调接收多媒体消息。

    多媒体资源一般默认自动下载,但不同消息类型的默认下载策略稍有区别,具体请参见下表:

    消息类型 默认资源下载策略
    图片/视频消息 SDK 在收到消息时,自动下载缩略图和封面图片
    语音消息 SDK 在收到消息时,自动下载原音频
    文件消息 SDK 默认不下载原文件
    • 如果需要下载文件消息的文件资源,可调用downloadAttachment方法手动下载。其他类型多媒体消息的资源如自动下载失败,也可调用该方法手动重新下载。

      downloadAttachment方法的参数
      参数
      类型
      说明
      message NIMMessage 附件所在的消息体
      thumb bool 是否只下载缩略图。为 true 时,仅下载缩略图。该参数仅对图片和视频类消息有效(Windows 和 macOS 暂不支持该参数)
    • 如需自主选择下载时机,需将初始化配置参数NIMSDKOptions.enablePreloadMessageAttachment设置为false,关闭默认资源下载策略,再在合适的时机调用downloadAttachment方法。


    手动下载多媒体资源示例如下:

    NimCore.instance.messageService.downloadAttachment(message, true);
    
  6. 接收方可以在多媒体资源下载完成后,通过对应的NIMMessageAttachment获取到具体的附件内容。多媒体附件的基类NIMFileAttachment,继承自NIMMessageAttachment。它的子类主要有:

    多媒体附件的部分参数说明
    参数 类型 说明
    path String 可选参数,文件本地路径,若文件不存在,返回 null。
    语音消息的文件路径,在附件下载完成之后可以获取。
    图片或视频的文件路径,需要手动下载之后获取,收到消息时,SDK 只默认自动下载缩略图文件
    thumbPath String 可选参数,缩略图文件的本地路径,若文件不存在,返回 null。
    当消息状态显示缩略图下载完成之后,可获取缩略图文件路径(Windows 和 macOS 暂不支持)
    thumbUrl String 可选参数,缩略远程路径(Windows 和 macOS 暂不支持)
    size int 可选参数,获取文件大小,单位为 byte
    md5 String 可选参数,获取文件内容 MD5
    url String 可选参数,获取文件在服务器上的下载 url。若文件还未上传,返回 null
    extension String 可选参数,文件后缀名
    expire int 可选参数,过期时间(Windows 和 macOS 暂不支持)
    nosScene NIMNosScene 上传文件时用的对 token 对应的场景,默认 [NIMNosScenes.defaultIm]
    displayName String 可选参数,文件的显示名。可以和文件名不同,仅用于界面展示
    base64 String 通用可选字段,目前用于 Web 传入文件信息,Web 端发送文件必传

    文件消息附件为NIMFileAttachment本身。

收发地理位置消息

地理位置消息收发流程与文本消息收发流程基本一致,区别在于构建消息的调用方法不同。本节仅简要展示相关调用示例,具体实现流程请参考上文的收发文本消息

  1. 调用createLocationMessage方法构建地理位置消息。

    参数 类型 说明
    sessionId String 聊天对象的 ID,如果是单聊,为用户帐号(accid),如果是群聊,为群组 ID (teamId)
    sessionType NIMSessionType 会话类型, NIMSessionType.p2p 为单聊类型,NIMSessionType.team 为群聊类型
    latitude double 纬度
    longitude double 经度
    address String 地理位置描述信息

    可通过消息配置选项NIMCustomMessageConfig设置该消息是否存入云端、写入漫游、计入未读数等。具体配置示例请参见消息配置选项

  2. 调用sendMessage方法方法将构建的地理位置消息发送至接收方。

    创建并发送地理位置消息的示例代码如下:

    // 该帐号为示例
    String account = 'testAccount';
    // 以单聊类型为例
    NIMSessionType sessionType = NIMSessionType.p2p;
    // 显示名称
    String address = 'this is a address';
    // 发送消息
    Future<NIMResult<NIMMessage>> result =
        MessageBuilder.createLocationMessage(
                sessionId: account,
                sessionType: sessionType,
                latitude: 30.3,
                longitude: 120.2,
                address: address)
            .then((value) => value.isSuccess
                ? NimCore.instance.messageService
                    .sendMessage(message: value.data!, resend: false)
                : Future.value(value));
    

收发提示消息

提示消息(又叫做 Tip 消息)主要用于会话内的通知提醒,可以看做是自定义消息的简化,有独立的消息类型NIMMessageType.tip。 区别于自定义消息,Tip 消息暂不支持通过setAttachment方法设置附件,如需使用附件请使用自定义消息。 Tip 消息的典型使用场景包括进入会话时出现的欢迎消息会话过程中命中敏感词后的提示等。这些应用场景也可以用自定义消息实现,但会相对复杂。

本节以 “您撤回了一条消息提示出现在群组中(仅对发送者可见且不发送到服务端)” 这个应用场景为例,介绍实现提示消息收发的流程。

API调用时序

uml diagram

实现流程

  1. 用户A 在登录 IM 前,注册onMessageStatusonReceiveSystemMsg事件流,分别监听消息状态NIMMessageStatus的变化和系统通知的接收(本场景下为监听消息撤回系统通知)。

    监听消息状态变化
    NimCore.instance.messageService.onMessageStatus.listen((NIMMessage message) {
        // 1、根据sessionId判断是否是自己的消息
        // 2、更改内存中消息的状态
        // 3、刷新界面
    });
    
    监听系统通知接收
    NimCore.instance.systemMessageService.onReceiveSystemMsg.  NimCore.instance.systemMessageService.onReceiveSystemMsg.listen((SystemMessage event) {
    
            });
    
    
  2. 用户A 调用createTeam方法创建高级群,相关示例代码请参见创建群组

  3. 其他用户加入用户A 创建的高级群,具体加入方法请参见入群操作

  4. 用户A 调用createTipMessage方法构建提示消息,调用时将enableUnreadCount参数设置为false,使该提示消息不计入未读计数。

    该方法的部分参数说明如下:

    参数 类型 类型说明
    sessionId String 聊天对象的 ID,根据会话类型sessionType判断
    • 如果是单聊,则sessionId为用户的云信IM帐号(即accid
    • 如果是群聊,则sessionId为群组 ID
    sessionType NIMSessionType 会话类型
  5. 用户A 调用saveMessageToLocalEx方法,保存该提示消息到本地数据库,但不发送到服务器。

    第 4 至 5 步的示例代码如下:

 //创建消息
      var tipMessageBuild = await MessageBuilder.createTipMessage(sessionId: sessionId, sessionType: sessionType,content: "content");
      var message = tipMessageBuild.data!;
      message.config = NIMCustomMessageConfig(enableUnreadCount:false);
      //保存消息
      NimCore.instance.messageService.saveMessageToLocalEx(message: message, time: time).then((value) {
        if(value.isSuccess){
          //todo success
        }
      });

接收通知消息

针对一些特定场景的事件,云信服务器预置了一些通知消息,在事件发生时下发到 SDK。通知消息也是一种特定消息,开发者需解析消息中附带的信息,来获取通知内容。如最常见的通知消息——群通知事件,如有新成员进群,则群内已有成员将收到此通知消息。通知消息与系统通知的区别,见通知消息和系统通知

  • 通知消息属于会话内的一种消息,其对应的数据结构为 NIMMessage,消息类型为 NIMMessageType.notification。通知消息目前用于在群和聊天室的事件通知。

  • 通知消息需要进行解析,具体请参见群组通知消息

收发自定义消息

除了上述消息类型以外,NIM SDK 还支持收发自定义消息类型。SDK 不负责定义和解析自定义消息的具体内容,解释工作由开发者完成。SDK 会将自定义消息存入消息数据库,会和其他类型消息一并展现在消息记录中。

为了使用更加方便,自定义消息采用附件的方式展示给开发者。体现在 NIMMessage 类中,自定义消息的内容会被解析为 NIMCustomMessageAttachment 对象。

常见问题

发送消息后如何获取消息内容

注册 onMessageStatus事件流,监听消息状态变化,该方法可以监听消息发送状态变化中回调NIMMessage对象。

可以通过NIMMessage对象的如下参数获取消息内容:

  • messageDirection:消息方向(发送或接收)
  • sessionId:聊天对象的账号(accid)或群组 ID(teamId
  • content:文本消息具体内容
  • messageAttachment:消息附件对象
  • status:消息收发状态
  • timestamp:消息发送时间(单位为毫秒)

如何设置消息的扩展字段

单聊或群聊消息具有服务端扩展字段和客户端扩展字段。服务端扩展字段只能在消息发送前设置,会同步到其他端;客户端扩展字段在消息发送前后设置均可,不会同步到其他端。

扩展字段,请使用 JSON 格式封装,并传入非格式化的 JSON 字符串,最大长度1024字节。


具体方法如下:

更新客户端扩展字段
  1. 对于单聊或群聊消息,构造NIMMessage对象时,通过localExtension参数设置客户端扩展字段。

  2. 调用updateMessage方法更新消息的本地扩展字段。

    设置消息的客户端扩展字段后,必须调用updateMessage方法,否则无法生效。

更新服务端扩展字段

对于单聊或群聊消息,构造NIMMessage对象时,通过remoteExtension方法设置消息的服务端扩展字段。

此文档是否对你有帮助?
有帮助
去反馈
  • 技术原理
  • 前提条件
  • API使用限制
  • 实现消息收发
  • 收发文本消息
  • 收发多媒体消息
  • 收发地理位置消息
  • 收发提示消息
  • 接收通知消息
  • 收发自定义消息
  • 常见问题
  • 发送消息后如何获取消息内容
  • 如何设置消息的扩展字段