Android IMLib SDK 开发指南

    前期准备

    注册开发者帐号

    开发者在集成融云即时通讯、实时网络能力前,需前往 融云官方网站 注册创建融云开发者帐号。

    下载 SDK

    您可以到 融云官方网站 下载融云 SDK。融云 SDK 各部分功能以插件化的形式独立提供,开发者可以根据自己的需要,自由组合下载。各组件的功能如下:

    名称 功能介绍 支持的 CPU 架构
    IMKit 融云 IM 界面组件 ——
    IMLib 融云 IM 通讯能力库 armeabi, armeabi-v7a, arm64-v8a, x86
    CallKit 融云音视频界面组件 ——
    CallLib 融云音视频核心组件 armeabi-v7a, x86
    LocationLib 融云位置相关库 ——
    PushLib 融云第三方推送库 armeabi, armeabi-v7a, arm64-v8a, x86
    RedPacket 融云红包相关组件 ——
    IMKit 集成了会话界面,并且提供了丰富的自定义功能,我们推荐首次接触融云的客户直接使用 IMKit 来快速集成和开发。
    IMLib 提供了基础的通信能力,较轻量,适用于对 UI 有较高订制需求的开发者,但您需要自己去实现大量的界面和功能。
    CallKit 融云音视频通话的界面组件,包含了单人、多人音视频通话的界面的各种场景和功能。您可以通过集成该组件来实现丰富的音视频通话界面,并进行自己的 UI 定制开发。同时我们开源了 CallKit,您可以根据您的需要去使用。
    CallLib 融云音视频通话核心能力组件。
    LocationLib 位置相关库文件。
    PushLib 融云支持第三方推送(小米),您可以从这里下载对应的第三方推送 jar 包。
    RedPacket 融云红包相关组件,通过集成该组件,即可快速实现红包功能。

    创建应用

    您要进行应用开发之前,需要先在融云开发者平台创建应用。如果您已经注册了融云开发者帐号,请前往融云开发者平台创建应用。

    您创建完应用后,首先需要了解的是 App Key / Secret,它们是融云 SDK 连接服务器所必须的标识,每一个 App 对应一套 App Key / Secret。针对开发者的生产环境和开发环境,我们提供两套 App Key / Secret,两套环境的功能完全一致。您在应用最终上线前,使用开发环境即可。

    image
    App Key / Secret 位置
    开发环境 App Key / Secret 是专门为您提供的仅供开发使用的,开发环境将和生产环境的数据隔离,避免开发环境数据和线上生产环境数据互相冲突。

    生产环境的 App Key / Secret 默认先不提供,等您提交上线后,我们会提供生产环境的 App Key / Secret。

    获取 Token

    Token 称为用户令牌,App Key 是您的 App 的唯一标识,Token 则是您 App 上的每一个用户的身份授权象征。您可以通过提交 userId 等信息来获得一个该用户对应的 Token,并使用这个 Token 作为该用户的唯一身份凭证与其他用户进行通信。

    Token 的主要作用是身份授权和安全,因此不能通过客户端直接访问融云服务器获取 Token,您必须通过 Server API 从融云服务器获取 Token 返回给您的 App,并在之后连接时使用。详细描述请参考 Server 开发指南 中的用户服务和获取 Token 方法小节。

    为了方便您在集成和测试过程中使用,我们还提供了 API 调试工具,在您不能部署服务器程序时,可以直接通过传入 userId 和 name 来获得 Token。请访问融云开发者平台,打开您想测试的应用,在左侧菜单中选择 “API 调试”即可。
    • userId : 每一个用户对应一个 userId,这个 userId 是您维护的,所以您可以直接赋值,您的两个用户通信,对于融云来说就是两个 userId 间通讯。
    • name : 用户的显示名称,用来在 Push 推送时,或者您没有传入用户信息时,默认显示的用户名称。
    • portraitUri : 用户头像,用来当您没有传入用户信息时作为默认头像,如果图片不存在,IMKit 会显示默认头像。

    通过 API 调试,您可以得到一个 Token 返回值。您就可以直接使用这个 Token 为这位用户进行发送和接受消息。

    集成 SDK

    环境要求

    在您集成融云 SDK 前环境要求如下:

    • Android SDK Build-tools 请升级到 21 及以上版本。
    • JAVA 编译版本 JDK 1.7 及以上版本。
    Android SDK 最低支持 Android API 9: Android 2.3(Gingerbread)。

    导入 SDK

    以 Module 形式导入前面下载的融云 SDK 里面的各个组件。

    打开您的工程, File -> New -> Import Module

    image

    打开您从官网下载的融云 SDK,选择 IMLib。如图:

    image

    根据您的需要,以同样的步骤导入 SDK 里的其它组件:LocationLib、CallLib、PushLib、RedPacket 等。

    将 PushLib 中的 jar 包 和 pushDaemon -> libs 目录下应用所支持平台的 so 拷贝到您应用的 libs 目录下,另外还需要将 pushDaemon -> executable 目录下各平台的可执行文件 push_daemon 拷贝到您应用 Module 的 assets 目录下。如图:

    image

    注意 : 放置 so 的文件夹位置需要和您 build.gradle 文件中配置的 jni 目录一致。

    image

    将 LocationLib 和 PushLib 里的 jar 包拷贝到您应用的 libs 目录下(如果不需要位置功能和小米推送,可跳过此步骤)。

    image

    注意

    音视频通话组件 CallLib 仅支持 armeabi-v7a 和 x86 架构 CPU (组件功能),如果您使用了我们的音视频通话功能,注意需要把 IMLib 和 PushLib 组件中其它 CPU 架构的 so 删除。或者您也可以在应用的 build.gradle 文件中增加如下配置来过滤 so :

    defaultConfig {
        applicationId "XXX"
        ...
        ndk {
            abiFilters "armeabi-v7a", "x86"
        }
    }
    

    添加配置

    打开应用 Module 的 build.gradle,在 dependencies 中添加相应模块的依赖。如图:

    dependencies {
        ...
        compile project(':IMLib')
        compile project(':CallLib')
        ...
    }
    

    打开 IMLib Module 的 AndroidManifest.xml 文件,把 meta-data RONG_CLOUD_APP_KEY 的值修改为您自己的 AppKey. 如图:

    <meta-data
        android:name="RONG_CLOUD_APP_KEY"
        android:value="您的应用 AppKey" />
    

    初始化

    在 Application 的 onCreate() 中,调用融云初始化方法。融云提供两种初始化方法:

    一、默认初始化方法

    
    /**
     * 初始化 SDK,在整个应用程序全局只需要调用一次, 建议在Application继承类中调用。
     *
     * @param context 传入Application类的Context。
     */
    public static void init(Context context)
    

    通过这种方式初始化时, 需要在应用的 AndroidManifest.xml 文件写入 RONG_CLOUD_APP_KEY。

    二、初始化时传入 appKey

    
    /**
     * <p>初始化 SDK,在整个应用程序全局只需要调用一次, 建议在 Application 继承类中调用。
     * 调用此接口传入 AppKey 与在 AndroidManifest.xml 里写入 RONG_CLOUD_APP_KEY 是同样效果,二选一即可。</p>
     *
     * @param context 传入Application类的Context。
     * @param appKey  融云注册应用的AppKey。
     */
    public static void init(Context context, String appKey)
    

    关于初始化后的特殊说明

    融云的 SDK 使用了跨进程机制来进行通信,运行 App 后会发现以下三个进程: 1、您的应用进程;2、您的应用进程: ipc,这是融云的通信进程;3、io.rong.push,这是融云的推送进程。

    连接服务器

    连接服务器前,确认已通过融云 Server API 接口获取 Token

    connect() 方法在整个应用全局只需要调用一次,且必须在主进程调用。如果连接失败,SDK 会自动启动重连机制,进行最多10次重连,分别是 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 秒后。如果仍然没有连接成功,还会在检测网络状态变化时再次重连。您不需要做额外的重连操作。

    /**
     * <p>连接服务器,在整个应用程序全局,只需要调用一次,需在 {@link #init(Context)} 之后调用。</p>
     * <p>如果调用此接口遇到连接失败,SDK 会自动启动重连机制进行最多10次重连,分别是1, 2, 4, 8, 16, 32, 64, 128, 256, 512秒后。
     * 在这之后如果仍没有连接成功,还会在当检测到设备网络状态变化时再次进行重连。</p>
     *
     * @param token    从服务端获取的用户身份令牌(Token)。
     * @param callback 连接回调。
     * @return RongIMClient  客户端核心类的实例。
     */
    private void connect(String token) {
    
        if (getApplicationInfo().packageName.equals(App.getCurProcessName(getApplicationContext()))) {
    
            RongIMClient.connect(token, new RongIMClient.ConnectCallback() {
    
                /**
                 * Token 错误。可以从下面两点检查 1.  Token 是否过期,如果过期您需要向 App Server 重新请求一个新的 Token
                 *                            2.  token 对应的 appKey 和工程里设置的 appKey 是否一致
                 */
                @Override
                public void onTokenIncorrect() {
    
                }
    
                /**
                 * 连接融云成功
                 * @param userid 当前 token 对应的用户 id
                 */
                @Override
                public void onSuccess(String userid) {
                    startActivity(new Intent(LoginActivity.this, MainActivity.class));
                    finish();
                }
    
                /**
                 * 连接融云失败
                 * @param errorCode 错误码,可到官网 查看错误码对应的注释
                 */
                @Override
                public void onError(RongIMClient.ErrorCode errorCode) {
    
                }
            });
        }
    }
    

    自定义广播接收器

    当您的应用处于后台运行或者和融云服务器 disconnect() 的时候,如果收到消息,融云 SDK 会以通知形式提醒您。所以您还需要自定义一个继承融云 PushMessageReceiver 的广播接收器,用来接收提醒通知。示例代码如图:

    public class SealNotificationReceiver extends PushMessageReceiver {
        @Override
        public boolean onNotificationMessageArrived(Context context, PushNotificationMessage message) {
            return false; // 返回 false, 会弹出融云 SDK 默认通知; 返回 true, 融云 SDK 不会弹通知, 通知需要由您自定义。
        }
    
        @Override
        public boolean onNotificationMessageClicked(Context context, PushNotificationMessage message) {
            return false; // 返回 false, 会走融云 SDK 默认处理逻辑, 即点击该通知会打开会话列表或会话界面; 返回 true, 则由您自定义处理逻辑。
        }
    
    }
    

    具体可参考文档

    断开连接

    融云 SDK 提供以下两种断开连接的方法:

    如果您想在断开和融云的连接后,有新消息时,仍然能够收到推送通知,调用 disconnect() 方法。

    /**
     * <p>断开与融云服务器的连接。当调用此接口断开连接后,仍然可以接收 Push 消息。</p>
     * <p>若想断开连接后不接受 Push 消息,可以调用{@link #logout()}</p>
     */
    public void disconnect()
    

    如果断开连接后,有新消息时,不想收到任何推送通知,调用 logout() 方法。

    /**
     * <p>断开与融云服务器的连接,并且不再接收 Push 消息。</p>
     * <p>若想断开连接后仍然接受 Push 消息,可以调用 {@link #disconnect()}</p>
     */
    public void logout()
    

    通过以上步骤,您即完成了融云 SDK 的集成。

    基础消息管理

    发送消息

    融云 SDK 针对普通消息和其它多媒体消息提供了不同的接口。因为多媒体消息涉及到多媒体内容的上传下载等,为了方便用户使用,SDK 提供了针对不同多媒体消息的特殊发送方法。

    默认发送消息方法

    如无特殊说明,大部分消息可以通过下面的两种默认方法发送,这两种方法的效果是一样的,二选其一即可。

    方法一 :

    
    // 构建文本消息实例
    TextMessage textMessage = TextMessage.obtain("我是消息内容");
    
    /**
     * <p>根据会话类型,发送消息。
     * 通过 {@link io.rong.imlib.IRongCallback.ISendMessageCallback} 中的方法回调发送的消息状态及消息体。</p>
     *
     * @param type        会话类型。
     * @param targetId    目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id 或聊天室 Id。
     * @param content     消息内容,例如 {@link TextMessage}, {@link ImageMessage}。
     * @param pushContent 当下发 push 消息时,在通知栏里会显示这个字段。
     *                    如果发送的是自定义消息,该字段必须填写,否则无法收到 push 消息。
     *                    如果发送 sdk 中默认的消息类型,例如 RC:TxtMsg, RC:VcMsg, RC:ImgMsg,则不需要填写,默认已经指定。
     * @param pushData    push 附加信息。如果设置该字段,用户在收到 push 消息时,能通过 {@link io.rong.push.notification.PushNotificationMessage#getPushData()} 方法获取。
     * @param callback    发送消息的回调。参考 {@link io.rong.imlib.IRongCallback.ISendMessageCallback}。
     *                    {@link #sendMessage(Message, String, String, IRongCallback.ISendMessageCallback)}
     */
    RongIMClient.getInstance().sendMessage(conversationType, targetId, textMessage, null, null, new IRongCallback.ISendMessageCallback() {
        @Override
        public void onAttached(Message message) {
            // 消息成功存到本地数据库的回调
        }
    
        @Override
        public void onSuccess(Message message) {
            // 消息发送成功的回调
        }
    
        @Override
        public void onError(Message message, RongIMClient.ErrorCode errorCode) {
            // 消息发送失败的回调
        }
    });
    

    方法二 :

    // 构造 TextMessage 实例
    TextMessage myTextMessage = TextMessage.obtain("我是消息内容");
    
    /* 生成 Message 对象。
     * "7127" 为目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id 或聊天室 Id。
     * Conversation.ConversationType.PRIVATE 为私聊会话类型,根据需要,也可以传入其它会话类型,如群组,讨论组等。
     */
    Message myMessage = Message.obtain("7127", Conversation.ConversationType.PRIVATE, myTextMessage);
    
    /**
     * <p>发送消息。
     * 通过 {@link io.rong.imlib.IRongCallback.ISendMessageCallback}
     * 中的方法回调发送的消息状态及消息体。</p>
     *
     * @param message     将要发送的消息体。
     * @param pushContent 当下发 push 消息时,在通知栏里会显示这个字段。
     *                    如果发送的是自定义消息,该字段必须填写,否则无法收到 push 消息。
     *                    如果发送 sdk 中默认的消息类型,例如 RC:TxtMsg, RC:VcMsg, RC:ImgMsg,则不需要填写,默认已经指定。
     * @param pushData    push 附加信息。如果设置该字段,用户在收到 push 消息时,能通过 {@link io.rong.push.notification.PushNotificationMessage#getPushData()} 方法获取。
     * @param callback    发送消息的回调,参考 {@link io.rong.imlib.IRongCallback.ISendMessageCallback}。
     */
    RongIMClient.getInstance().sendMessage(myMessage, null, null, new IRongCallback.ISendMessageCallback() {
      @Override
      public void onAttached(Message message) {
        //消息本地数据库存储成功的回调
      }
    
      @Override
      public void onSuccess(Message message) {
        //消息通过网络发送成功的回调
      }
    
      @Override
      public void onError(Message message, RongIMClient.ErrorCode errorCode) {
        //消息发送失败的回调
      }
    });
    

    发送位置消息

    构造位置消息:

    /**
     * 生成LocationMessage对象。
     *
     * @param lat    纬度。
     * @param lng    经度。
     * @param poi    poi信息。
     * @param imgUri 地图缩率图地址。
     * @return LocationMessage实例对象。
     */
    public static LocationMessage obtain(double lat, double lng, String poi, Uri imgUri)
    

    根据位置消息生成 Message 实例,如下:

    LocationMessage locationMessage = LocationMessage.obtain(lat, lng, poi, thumb);
    io.rong.imlib.model.Message message = io.rong.imlib.model.Message.obtain(mTargetId, mConversationType, locationMessage);
    

    发送位置消息:

    /**
     * <p>发送地理位置消息。</p>
     * <p>发送前构造 {@link Message} 消息实体,消息实体中的 content 必须为 {@link LocationMessage}, 否则返回失败。</p>
     * <p>其中的缩略图地址 scheme 只支持 file:// 和 http://。也可不设置缩略图地址,传入 null。</p>
     *
     * @param message             消息实体。
     * @param pushContent         当下发 push 消息时,在通知栏里会显示这个字段。
     *                            如果发送的是自定义消息,该字段必须填写,否则无法收到 push 消息。
     *                            如果发送 sdk 中默认的消息类型,例如 RC:TxtMsg, RC:VcMsg, RC:ImgMsg,则不需要填写,默认已经指定。
     * @param pushData            push 附加信息。如果设置该字段,用户在收到 push 消息时,能通过 {@link io.rong.push.notification.PushNotificationMessage#getPushData()} 方法获取。
     * @param sendMessageCallback 发送消息的回调,参考 {@link io.rong.imlib.IRongCallback.ISendMessageCallback}。
     */
    RongIMClient.getInstance().sendLocationMessage(message, pushContent, pushData, new IRongCallback.ISendMessageCallback(){
      @Override
      public void onAttached(Message message) {
    
      }
    
      @Override
      public void onSuccess(Message message) {
    
      }
    
      @Override
      public void onError(Message message, RongIMClient.ErrorCode errorCode) {
    
      }
    });
    
    #### 发送图片消息
    
    ** 默认图片消息发送 **
    
    获取 ImageMessage 实例
    
    ```java
    /**
     * 生成ImageMessage对象。
     *
     * @param thumUri  缩略图地址。
     * @param localUri 大图地址。
     * @param isFull 是否发送原图。
     * @return ImageMessage对象实例。
     */
    public static ImageMessage obtain(Uri thumUri, Uri localUri, boolean isFull)
    

    发送图片消息

    
    /**
     * <p>根据会话类型,发送图片消息。</p>
     *
     * @param conversationType        会话类型。
     * @param targetId    目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id 或聊天室 Id。
     * @param imgMsg      图片消息内容。
     * @param pushContent 当下发 push 消息时,在通知栏里会显示这个字段。
     *                    如果发送的是自定义消息,该字段必须填写,否则无法收到 push 消息。
     *                    如果发送 sdk 中默认的消息类型,例如 RC:TxtMsg, RC:VcMsg, RC:ImgMsg,则不需要填写,传 null 即可,默认已经指定。
     * @param pushData    push 附加信息。如果设置该字段,用户在收到 push 消息时,能通过 {@link io.rong.push.notification.PushNotificationMessage#getPushData()} 方法获取。
     * @param callback    发送消息的回调。
     */
    RongIMClient.getInstance().sendImageMessage(conversationType, targetId, imgMsg, pushContent, pushData, new RongIMClient.SendImageMessageCallback() {
    
            @Override
            public void onAttached(Message message) {
                    //保存数据库成功
            }
    
            @Override
            public void onError(Message message, RongIMClient.ErrorCode code) {
                    //发送失败
            }
    
            @Override
            public void onSuccess(Message message) {
                    //发送成功
            }
    
            @Override
            public void onProgress(Message message, int progress) {
                    //发送进度
            }
    });
    

    发送图片消息并且上传到自己的服务器

    生成图片消息实例

    /**
     * 生成ImageMessage对象。
     *
     * @param thumUri  缩略图地址。
     * @param localUri 大图地址。
     * @param isFull 是否发送原图。
     * @return ImageMessage对象实例。
     */
    public static ImageMessage obtain(Uri thumUri, Uri localUri, boolean isFull)
    

    根据 ImageMessage 生成 Message 对象

    ImageMessage imageMessage = ImageMessage.obtain(thumbPathUri, localPathUri, false);
    Message message = Message.obtain(targetId, conversationType, imageMessage);
    

    调用下面的方法发送图片消息

    /**
     * <p>发送图片消息,可以使用该方法将图片上传到自己的服务器发送,同时更新图片状态。</p>
     * <p>使用该方法在上传图片时,会回调 {@link io.rong.imlib.RongIMClient.SendImageMessageWithUploadListenerCallback}
     * 此回调中会携带 {@link RongIMClient.UploadImageStatusListener} 对象,使用者只需要调用其中的
     * {@link RongIMClient.UploadImageStatusListener#update(int)} 更新进度
     * {@link RongIMClient.UploadImageStatusListener#success(Uri)} 更新成功状态,并告知上传成功后的图片地址
     * {@link RongIMClient.UploadImageStatusListener#error()} 更新失败状态 </p>
     *
     * @param message     发送消息的实体。
     * @param pushContent 当下发 push 消息时,在通知栏里会显示这个字段。
     *                    如果发送的是自定义消息,该字段必须填写,否则无法收到 push 消息。
     *                    如果发送 sdk 中默认的消息类型,例如 RC:TxtMsg, RC:VcMsg, RC:ImgMsg,则不需要填写,默认已经指定。
     * @param pushData    push 附加信息。如果设置该字段,用户在收到 push 消息时,能通过 {@link io.rong.push.notification.PushNotificationMessage#getPushData()} 方法获取。
     * @param callback    发送消息的回调,回调中携带 {@link RongIMClient.UploadImageStatusListener} 对象,用户调用该对象中的方法更新状态。
     *                    {@link #sendImageMessage(Message, String, String, RongIMClient.SendImageMessageCallback)}
     */
     RongIMClient.getInstance().sendImageMessage(message, pushContent, pushData, new RongIMClient.SendImageMessageWithUploadListenerCallback() {
    
         @Override
         public void onAttached(Message message, final RongIMClient.UploadImageStatusListener uploadImageStatusListener) {
             /*上传图片到自己的服务器*/
             uploadImg(imgMsg.getPicFilePath(), new UploadListener() {
                 @Override
                 public void onSuccess(String url) {
                     // 上传成功,回调 SDK 的 success 方法,传递回图片的远端地址
                     uploadImageStatusListener.success(Uri.parse(url));
                 }
    
    
                 @Override
                 public void onProgress(float progress) {
                     //刷新上传进度
                     uploadImageStatusListener.update((int) progress);
                 }
    
    
                 @Override
                 public void onFail() {
                     // 上传图片失败,回调 error 方法。
                     uploadImageStatusListener.error();
                 }
             });
         }
    
    
         @Override
         public void onError(Message message, RongIMClient.ErrorCode errorCode) {
             //发送失败
         }
    
    
         @Override
         public void onSuccess(Message message) {
             //发送成功
         }
    
    
         @Override
         public void onProgress(Message message, int progress) {
             //发送进度
         }
     });
    
    注:图片消息包括两个主要部分:缩略图和大图,缩略图以宽度和高度中较长的边不超过 240 像素等比压缩后,直接 Base64 编码放入 content 中;大图以宽度和高度中较长的边不超过 960 像素等比压缩后,上传到文件服务器(融云 SDK 中默认上传文件存储有效期为 1 个月),然后将云存储上的大图地址放入消息体中。
    大图的压缩比例可以通过修改 rc_configuration.xml 中 rc_image_quality 的值来自定义。
    大图的最大尺寸可以通过修改 rc_configuration.xml 中 rc_image_size 的值来自定义。

    关于图片消息的详细机制,可以参考图片消息文档

    发送文件消息

    生成 FileMessage 实例

    /**
     * 生成 FileMessage 对象。
     * @param localUrl 文件的本地地址,必须以file://开头。
     * */
    public static FileMessage obtain(Uri localUrl)
    

    根据 FileMessage 生成 Message 实例

    FileMessage fileMessage = FileMessage.obtain(url);
    io.rong.imlib.model.Message message = io.rong.imlib.model.Message.obtain(mTargetId, mConversationType, fileMessage);
    

    默认发送文件消息方法

    /**
     * <p>发送多媒体消息</p>
     * <p>发送前构造 {@link Message} 消息实体</p>
     *
     * @param message     发送消息的实体。
     * @param pushContent 当下发 push 消息时,在通知栏里会显示这个字段。
     *                    如果发送的是自定义消息,该字段必须填写,否则无法收到 push 消息。
     *                    如果发送 sdk 中默认的消息类型,例如 RC:TxtMsg, RC:VcMsg, RC:ImgMsg,则不需要填写,默认已经指定。
     * @param pushData    push 附加信息。如果设置该字段,用户在收到 push 消息时,能通过 {@link io.rong.push.notification.PushNotificationMessage#getPushData()} 方法获取。
     * @param callback    发送消息的回调 {@link io.rong.imlib.RongIMClient.SendMediaMessageCallback}。
     */
    public void sendMediaMessage(final Message message, final String pushContent, final String pushData, final IRongCallback.ISendMediaMessageCallback callback)
    

    发送文件消息并上传到自己的服务器

    /**
     * <p>发送多媒体消息,可以使用该方法将多媒体文件上传到自己的服务器。
     * 使用该方法在上传多媒体文件时,会回调 {@link io.rong.imlib.IRongCallback.ISendMediaMessageCallbackWithUploader#onAttached(Message, IRongCallback.MediaMessageUploader)}
     * 此回调中会携带 {@link IRongCallback.MediaMessageUploader} 对象,使用者只需要调用此对象中的
     * {@link IRongCallback.MediaMessageUploader#update(int)} 更新进度
     * {@link IRongCallback.MediaMessageUploader#success(Uri)} 更新成功状态,并告知上传成功后的文件地址
     * {@link IRongCallback.MediaMessageUploader#error()} 更新失败状态
     * {@link IRongCallback.MediaMessageUploader#cancel()} ()} 更新取消状态
     * </p>
     *
     * @param message     发送消息的实体。
     * @param pushContent 当下发 push 消息时,在通知栏里会显示这个字段。
     *                    如果发送的是自定义消息,该字段必须填写,否则无法收到 push 消息。
     *                    如果发送 sdk 中默认的消息类型,例如 RC:TxtMsg, RC:VcMsg, RC:ImgMsg, RC:FileMsg,则不需要填写,默认已经指定。
     * @param pushData    push 附加信息。如果设置该字段,用户在收到 push 消息时,能通过 {@link io.rong.push.notification.PushNotificationMessage#getPushData()} 方法获取。
     * @param callback    发送消息的回调,回调中携带 {@link IRongCallback.MediaMessageUploader} 对象,用户调用该对象中的方法更新状态。
     */
    public void sendMediaMessage(final Message message, final String pushContent, final String pushData, final IRongCallback.ISendMediaMessageCallbackWithUploader callback)
    

    插入消息

    融云 SDK 支持往本地会话插入一条消息,而不往外发送。

    /**
     * 向本地会话中插入一条消息。这条消息只是插入本地会话,不会实际发送给服务器和对方。该消息不一定插入本地数据库,是否入库由消息的属性决定。
     *
     * @param type           会话类型。
     * @param targetId       目标会话Id。比如私人会话时,是对方的id; 群组会话时,是群id; 讨论组会话时,则为该讨论组的id.
     * @param senderUserId   发送用户 Id。如果是模拟本人插入的消息,则该id设置为当前登录用户即可。如果要模拟对方插入消息,则该id需要设置为对方的id.
     * @param content        消息内容。如{@link TextMessage} {@link ImageMessage}等。
     * @param sentTime       消息的发送时间。
     * @param resultCallback 获得消息发送实体的回调。
     */
    public void insertMessage(final Conversation.ConversationType type, final String targetId, final String senderUserId, final MessageContent content, final long sentTime, final ResultCallback<Message> resultCallback)
    

    删除消息

    清空某一会话的所有消息。

    /**
     * 清空指定类型,targetId 的某一会话所有聊天消息记录。
     *
     * @param conversationType 会话类型。不支持传入 ConversationType.CHATROOM。
     * @param targetId         目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id。
     * @param callback         清空是否成功的回调。
     */
    public void clearMessages(final Conversation.ConversationType conversationType, final String targetId, final ResultCallback<Boolean> callback)
    

    删除某一会话的所有消息,同时清理数据库空间,如果数据库特别大,该接口会相对耗时,建议在清理缓存时调用。

    /**
     * <p>清除指定会话的消息</p>。
     * <p>此接口会删除指定会话中数据库的所有消息,同时,会清理数据库空间。
     * 如果数据库特别大,超过几百 M,调用该接口会有少许耗时。</p>
     *
     * @param conversationType 指定的会话类型。
     * @param targetId         目标 Id。根据不同的 conversationType,可能是userId, groupId, discussionId。
     * @param callback         是否删除成功的回调。
     */
    public void deleteMessages(final Conversation.ConversationType conversationType, final String targetId, final ResultCallback<Boolean> callback)
    

    根据 messageId, 删除指定的一条或多条消息。

    /**
     * 根据 messageId,删除指定的一条或者一组消息。
     *
     * @param messageIds 要删除的消息 Id 数组。
     * @param callback   是否删除成功的回调。
     */
    public void deleteMessages(final int[] messageIds, final ResultCallback<Boolean> callback)
    

    获取历史消息

    获取某会话的本地历史消息记录,此接口可以通过指定最后一条消息和拉取条数来分段加载历史消息。

    /**
     * <p>
     * 获取指定类型,targetId 的N条历史消息记录。通过此接口可以根据情况分段加载历史消息,节省网络资源,提高用户体验。
     * 该接口不支持拉取聊天室 {io.rong.imlib.model.Conversation.ConversationType#CHATROOM} 历史消息。
     * </p>
     *
     * @param conversationType 会话类型。
     * @param targetId         目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id。
     * @param oldestMessageId  最后一条消息的 Id,获取此消息之前的 count 条消息,没有消息第一次调用应设置为:-1。
     * @param count            要获取的消息数量。
     * @param callback         获取历史消息记录的回调,按照时间顺序从新到旧排列。
     */
    public void getHistoryMessages(final Conversation.ConversationType conversationType, final String targetId, final int oldestMessageId, final int count, final ResultCallback<List<Message>> callback)
    

    获取某一会话中特定类型消息的本地历史记录,比如可以通过此接口拉取会话中某一条消息之前的 10 条图片消息。

    /**
     * <p>获取本地数据库中保存,特定类型,targetId 的N条历史消息记录。通过此接口可以根据情况分段加载历史消息,节省网络资源,提高用户体验。</p>
     * <p>该接口不支持拉取聊天室 {@link io.rong.imlib.model.Conversation.ConversationType#CHATROOM} 历史消息。</p>
     *
     * @param conversationType 会话类型。
     * @param targetId         目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id 。
     * @param objectName       消息类型标识。{@link MessageTag#value()}, 比如文本消息"RC:TxtMsg", 图片消息"RC:ImgMsg", 或者您自定义消息的 MessageTag 中 value 的值。
     * @param oldestMessageId  最后一条消息的 Id,获取此消息之前的 count 条消息,没有消息第一次调用应设置为:-1。
     * @param count            要获取的消息数量
     * @param callback         获取历史消息记录的回调,按照时间顺序从新到旧排列。
     */
    public void getHistoryMessages(final Conversation.ConversationType conversationType, final String targetId, final String objectName, final int oldestMessageId, final int count, final ResultCallback<List<Message>> callback)
    

    获取会话中某条消息之前或者之后的 N 条特定类型消息的本地历史记录。比如,可以获取 messageId 为 22 的这条消息之前或者之后的 10 条图片消息。

    /**
     * <p>根据会话类型的目标 Id,回调方式获取某消息类型的某条消息之前或之后的N条历史消息记录。如: 要获取messageId为22的之前的10条图片消息,
     * 则相应参数为 getHistoryMessages(conversationType, targetId, "RC:ImgMsg", 22, 10, true, resultCallback)。
     * 注意:返回的消息列表里面不包含oldestMessageId本身。</p>
     *
     * @param conversationType 会话类型。不支持传入 ConversationType.CHATROOM。
     * @param targetId         目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id。
     * @param objectName       消息类型标识。如RC:TxtMsg,RC:ImgMsg,RC:VcMsg等。
     * @param baseMessageId    最后一条消息的 Id,获取此消息之前的 count 条消息,没有消息第一次调用应设置为:-1。
     * @param count            要获取的消息数量
     * @param direction        要获取的消息相对于 oldestMessageId 的方向 {@link io.rong.imlib.RongCommonDefine.GetMessageDirection}
     *                         以指定的 message id 作为获取的起始点,时间早于该 id 则为 FRONT,晚于则为 BEHIND。
     * @param callback         获取历史消息记录的回调,按照时间顺序从新到旧排列。
     */
    public void getHistoryMessages(final Conversation.ConversationType conversationType, final String targetId, final String objectName, final int baseMessageId, final int count, final RongCommonDefine.GetMessageDirection direction, final ResultCallback<List<Message>> callback)
    

    获取会话中指定消息之前 N 条 和之后 M 条的本地历史消息。

    
        /**
         * 获取某会话中指定消息的前 before 数量和 after 数量的消息。
         * 返回的消息列表中会包含指定的消息。消息列表时间顺序从新到旧。
         *
         * @param conversationType 指定的会话类型。
         * @param targetId         指定的会话 id。
         * @param sentTime         指定消息的发送时间,不能为0。
         * @param before           指定消息的前部分消息数量。
         * @param after            指定消息的后部分消息数量。
         * @param resultCallback   搜索结果回调。
         */
        public void getHistoryMessages(final Conversation.ConversationType conversationType, final String targetId, final long sentTime, final int before, final int after, final RongIMClient.ResultCallback<List<Message>> resultCallback)
    

    获取融云服务器中的历史消息记录。和上述接口的区别是,该接口是从融云服务器拉取历史消息记录,通常用户更换新设备后,拉取历史消息。

    /**
     * <p>获取融云服务器中暂存,特定类型,targetId 的N条(一次不超过40条)历史消息记录。通过此接口可以根据情况分段加载历史消息,节省网络资源,提高用户体验。</p>
     * <p>区别于 {@link #getHistoryMessages},该接口是从融云服务器中拉取。通常用于更换新设备后,拉取历史消息。
     * 公众服务会话 {@link io.rong.imlib.model.Conversation.ConversationType#APP_PUBLIC_SERVICE}
     * {@link io.rong.imlib.model.Conversation.ConversationType#PUBLIC_SERVICE} </p>
     *
     * @param conversationType 会话类型。
     * @param targetId         目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id。
     * @param dateTime         从该时间点开始获取消息。即:消息中的 sentTime;第一次可传 0,获取最新 count 条。
     * @param count            要获取的消息数量,最多 40 条。
     * @param callback         获取历史消息记录的回调,按照时间顺序从新到旧排列。
     */
    public void getRemoteHistoryMessages(final Conversation.ConversationType conversationType, final String targetId, final long dateTime, final int count, final ResultCallback<List<Message>> callback)
    
    该功能需要在开发者后台“应用/IM 服务/高级功能设置”中开通公有云专业版后,开启单群聊消息云存储功能才能使用,开发环境下可免费使用。查看收费详情

    根据关键词搜索消息列表,返回包含匹配消息的会话列表,以及各会话中匹配的消息数量。

    /**
     * 搜索本地历史消息。
     * 此接口可快速返回匹配的会话列表,并且会话中包含已匹配的消息数量。通过 {SearchConversationResult#getMatchCount()} 得到。
     * 如果需要自定义消息也能被搜索到,需要在自定义消息中实现 {@link MessageContent#getSearchableWord()} 方法;
     *
     * @param keyword           搜索的关键字。
     * @param conversationTypes 搜索的会话类型。
     * @param objectNames       搜索的消息类型,例如:RC:TxtMsg。
     * @param resultCallback    搜索结果回调。
     */
    public void searchConversations(final String keyword, final Conversation.ConversationType[] conversationTypes, final String[] objectNames, final RongIMClient.ResultCallback<List<SearchConversationResult>> resultCallback)
    

    搜索某会话中所有匹配的消息。

    /**
     * 根据会话,搜索本地历史消息。
     * 搜索结果可分页返回。
     * 如果需要自定义消息也能被搜索到,需要在自定义消息中实现 {@link MessageContent#getSearchableWord()} 方法;
     *
     * @param conversationType 指定的会话类型。
     * @param targetId         指定的会话 id。
     * @param keyword          搜索的关键字。
     * @param count            返回的搜索结果数量, 传0时会返回所有搜索到的消息, 非0时,逐页返回。
     * @param beginTime        查询记录的起始时间, 传0时从最新消息开始搜索。
     * @param resultCallback   搜索结果回调。
     */
    public void searchMessages(final Conversation.ConversationType conversationType, final String targetId, final String keyword, final int count, final long beginTime, final RongIMClient.ResultCallback<List<Message>> resultCallback)
    

    注意

    如果您有自定义消息,且需要这部分自定义消息也被搜索到,那必须在自定义消息中实现 {@link MessageContent#getSearchableWord()} 方法

    消息监听

    通过如下方法设置监听器,可以监听到所有接收的消息。

    /**
     * <p>设置接收消息事件的监听器。所有接收到的消息、通知、状态都经由此处设置的监听器处理。包括私聊消息、讨论组消息、群组消息、聊天室消息以及各种状态。</p>
     * <strong>注意:</strong>如果调用此接口的Activity被释放回收,将无法收到事件回调。
     *
     * @param listener 接收消息的监听器。
     */
    public static void setOnReceiveMessageListener(final OnReceiveMessageListener listener)
    

    注意:建议在您应用的生命周期里设置接受监听器,比如 Application 的 onCreate() 方法里。如果在 Activity 里进行设置,当 Activity 被释放回收后,将无法收到事件回调。

    代码示例:

    RongIMClient.setOnReceiveMessageListener(new MyReceiveMessageListener());
    
    private class MyReceiveMessageListener implements RongIMClient.OnReceiveMessageListener {
    
        /**
         * 收到消息的处理。
         * @param message 收到的消息实体。
         * @param left 剩余未拉取消息数目。
         * @return
         */
        @Override
        public boolean onReceived(Message message, int left) {
            //开发者根据自己需求自行处理
            return false;
        }
    }
    

    更改消息状态

    更改消息未读已读状态

    将会话中某个时间之前的消息由未读状态改为已读状态。

    /**
     * 根据时间戳清除指定类型,目标Id 的某一会话消息未读状态。{@link Message#getSentTime()}在时间戳之前的消息将被置成已读。
     *
     * @param conversationType 会话类型。不支持传入 ConversationType.CHATROOM。
     * @param targetId         目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id。
     * @param timestamp        时间戳。
     * @param callback         清除是否成功的回调。
     */
    public void clearMessagesUnreadStatus(final Conversation.ConversationType conversationType, final String targetId, final long timestamp, final OperationCallback callback)
    

    将某个会话中的所有消息设为已读。

    /**
     * 清除指定类型,targetId 的某一会话消息未读状态。
     *
     * @param conversationType 会话类型。不支持传入 ConversationType.CHATROOM。
     * @param targetId         目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id。
     * @param callback         清除是否成功的回调。
     */
    public void clearMessagesUnreadStatus(final Conversation.ConversationType conversationType, final String targetId, final ResultCallback<Boolean> callback)
    

    根据 messageId 设置消息的各种状态,比如已读,已收听,已下载等。

    /**
     * 根据 messageId 设置接收到的消息状态。用于UI标记消息为已读,已下载等状态。
     *
     * @param messageId      消息 Id。
     * @param receivedStatus 接收到的消息状态。{@link io.rong.imlib.model.Message.ReceivedStatus}
     * @param callback       是否设置成功的回调。
     */
    public void setMessageReceivedStatus(final int messageId, final Message.ReceivedStatus receivedStatus, final ResultCallback<Boolean> callback)
    

    使用示例:

    // 更新内存中消息的已读状态
    message.getReceivedStatus().setRead();
    // 更新数据库中消息的状态
    RongIMClient.getInstance().setMessageReceivedStatus(message.getMessageId(), message.getReceivedStatus(), null);
    

    自定义消息

    1、继承 MessageContent

    新建一自定义消息类,继承 MessageContent 如下面示例代码:

    public class CustomizeMessage extends MessageContent {
          private String content;//消息属性,可随意定义
      }
    

    2、重写和实现方法

    实现 encode() 方法,该方法的功能是将消息属性封装成 json 串,再将 json 串转成 byte 数组,该方法会在发消息时调用,如下面示例代码:

    @Override
    public byte[] encode() {
        JSONObject jsonObj = new JSONObject();
    
        try {
            jsonObj.put("content", "这是一条消息内容");
        } catch (JSONException e) {
            Log.e("JSONException", e.getMessage());
        }
    
        try {
            return jsonObj.toString().getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    
        return null;
    }
    

    覆盖父类的 MessageContent(byte[] data) 构造方法,该方法将对收到的消息进行解析,先由 byte 转成 json 字符串,再将 json 中内容取出赋值给消息属性。

    public CustomizeMessage(byte[] data) {
        String jsonStr = null;
    
        try {
            jsonStr = new String(data, "UTF-8");
        } catch (UnsupportedEncodingException e1) {
    
        }
    
        try {
            JSONObject jsonObj = new JSONObject(jsonStr);
    
            if (jsonObj.has("content"))
                content = jsonObj.optString("content");
    
        } catch (JSONException e) {
            RLog.e(this, "JSONException", e.getMessage());
        }
    
    }
    

    MessageContent 已实现 Parcelable 接口,下面需要实现 Parcelable 中的方法:

    //给消息赋值。
    public CustomizeMessage(Parcel in) {
        content=ParcelUtils.readFromParcel(in);//该类为工具类,消息属性
        ...
        //这里可继续增加你消息的属性
      }
    
      /**
       * 读取接口,目的是要从Parcel中构造一个实现了Parcelable的类的实例处理。
       */
      public static final Creator<CustomizeMessage> CREATOR = new Creator<CustomizeMessage>() {
    
          @Override
          public CustomizeMessage createFromParcel(Parcel source) {
              return new CustomizeMessage(source);
          }
    
          @Override
          public CustomizeMessage[] newArray(int size) {
              return new CustomizeMessage[size];
          }
      };
    
      /**
       * 描述了包含在 Parcelable 对象排列信息中的特殊对象的类型。
       *
       * @return 一个标志位,表明Parcelable对象特殊对象类型集合的排列。
       */
      public int describeContents() {
          return 0;
      }
    
      /**
       * 将类的数据写入外部提供的 Parcel 中。
       *
       * @param dest  对象被写入的 Parcel。
       * @param flags 对象如何被写入的附加标志。
       */
      @Override
      public void writeToParcel(Parcel dest, int flags) {
          ParcelUtils.writeToParcel(dest, content);//该类为工具类,对消息中属性进行序列化
          ...
          //这里可继续增加你消息的属性
      }
    

    3、增加注解信息

    注解名:MessageTag ;属性:value ,flag; value 即 ObjectName 是消息的唯一标识不可以重复,且三端必须一致。开发者命名时不能以 RC 开头,避免和融云内置消息冲突;flag 是用来定义消息的可操作状态。

    如下面代码段,自定义消息名称 CustomizeMessage ,vaule 是 app:custom ,flag 是 MessageTag.ISCOUNTED | MessageTag.ISPERSISTED 表示消息计数且存库。

    @MessageTag(value = "app:custom", flag = MessageTag.ISCOUNTED | MessageTag.ISPERSISTED)
    public class CustomizeMessage extends MessageContent {
      ...
    }
    

    flag 值如下表:

    枚举值 说明
    MessageTag.NONE 为空值,不表示任何意义,发送的自定义消息不会在会话页面和会话列表中展示。
    MessageTag.ISCOUNTED 表示客户端收到消息后,要进行未读消息计数(未读消息数增加 1),所有内容型消息都应该设置此值。非内容类消息暂不支持消息计数。
    MessageTag.ISPERSISTED 表示客户端收到消息后,要进行存储,并在之后可以通过接口查询,存储后会在会话界面中显示。

    4、注册自定义消息

    自定义消息应在 init 后注册,代码如下:

    RongIMClient.registerMessageType(CustomizeMessage.class);
    

    基础会话管理

    获取会话

    获取指定的某个会话

    /**
     * 根据不同会话类型的目标 Id,回调方式获取某一会话信息。
     *
     * @param conversationType 会话类型。
     * @param targetId         目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id 或聊天室 Id。
     * @param callback         获取会话信息的回调。
     */
    public void getConversation(final Conversation.ConversationType conversationType, final String targetId, final ResultCallback<Conversation> callback)
    

    获取用户的所有本地会话列表

    /**
     * <p> 获取当前用户本地会话列表的默认方法,该方法返回的是以下类型的会话列表:私聊,群组,讨论组,系统会话。如果
     * 您需要获取其它类型的会话列表,可以使用{@link #getConversationList(ResultCallback, Conversation.ConversationType...)} 方法。
     * <strong>注意:</strong>当更换设备或者清除缓存后,拉取到的是暂存在融云服务器中该账号当天收发过消息的会话列表。</p>
     *
     * @param callback 获取会话列表的回调。
     */
    public void getConversationList(final ResultCallback<List<Conversation>> callback)
    

    获取某几种会话类型的会话列表

    /**
     * <p>根据会话类型,获取当前用户的本地会话列表。即显示所有本地数据库中收发过消息,并且未被删除的会话。</p>
     * <p><strong>注意:</strong>当更换设备或者清除缓存后,能拉取到暂存在融云服务器中该账号当天收发过消息的会话。</p>
     *
     * @param callback          获取会话列表的回调。
     * @param conversationTypes 选择要获取的会话类型。
     */
    public void getConversationList(final ResultCallback<List<Conversation>> callback, final Conversation.ConversationType... conversationTypes)
    

    分页拉取本地会话列表

    /**
     * <p>分页获取会话列表</p>
     * <p><strong>注意:</strong>当更换设备或者清除缓存后,能拉取到暂存在融云服务器中该账号当天收发过消息的会话。</p>
     *
     *
     * @param callback          获取会话列表的回调
     * @param timeStamp         时间戳,获取从此时间戳往前的会话,第一次传 0
     * @param count             取回的会话个数。当实际取回的会话个数小于 count 值时,表明已取完数据
     * @param conversationTypes 选择要获取的会话类型
     */
    public void getConversationListByPage(final ResultCallback<List<Conversation>> callback, final long timeStamp, final int count, final Conversation.ConversationType... conversationTypes)
    

    删除会话

    /**
     * <p>从会话列表中移除某一会话,但是不删除会话内的消息。</p>
     * <p>如果此会话中有新的消息,该会话将重新在会话列表中显示,并显示最近的历史消息。</p>
     *
     * @param conversationType 会话类型。
     * @param targetId         目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id 或聊天室 Id。
     * @param callback         移除会话是否成功的回调。
     */
    public void removeConversation(final Conversation.ConversationType conversationType, final String targetId, final ResultCallback<Boolean> callback)
    

    会话提醒

    通过融云 SDK,您可以设置会话的提醒状态来实现免打扰功能。按照免打扰作用范围,分为两种类型:

    • 设置单个会话的提醒状态。通过此方法,您可以屏蔽某个会话的通知提醒和推送。

    • 设置所有会话的通知免打扰。可以设置某一个时间段免打扰,也可以设置全天免打扰。

    一、设置单个会话提醒状态

    a.会话提醒状态

    会话状态可以分为以下两种:

    enum ConversationNotificationStatus {
        DO_NOT_DISTURB(0), // 会话免打扰状态
        NOTIFY(1); // 会话提醒状态
      }
    

    当设置会话状态为 DO_NOT_DISTURB 时,客户端将不会收到消息推送。您也可以根据此状态,调整收到在线消息时的处理逻辑,如屏蔽后台通知和提示音等。

    b.设置会话提醒状态:

    /**
     * 设置会话消息提醒状态。
     *
     * @param conversationType   会话类型。
     * @param targetId           目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id。
     * @param notificationStatus 是否屏蔽。
     * @param callback           设置状态的回调。
     */
    public void setConversationNotificationStatus(final Conversation.ConversationType conversationType, final String targetId, final Conversation.ConversationNotificationStatus notificationStatus, final ResultCallback<Conversation.ConversationNotificationStatus> callback)
    

    c.获取会话提醒状态

    /**
     * 获取会话消息提醒状态。
     *
     * @param conversationType 会话类型。
     * @param targetId         目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id。
     * @param callback         获取状态的回调。
     */
    public void getConversationNotificationStatus(final Conversation.ConversationType conversationType, final String targetId, final ResultCallback<Conversation.ConversationNotificationStatus> callback)
    

    注意:会话提醒状态是保存在融云服务器的,建议您在第一次登录应用时,先通过此方法到服务器同步一下会话提醒状态。

    二、设置所有会话的通知免打扰

    通过此方法设置通知免打扰之后,在所设置的免打扰时间段内,如果应用处于离线状态(即和融云服务器处于断开连接的状态),将不会收到消息推送。

    如果处于非离线状态,客户端是仍然可以收到消息的,此时的消息是否提醒逻辑由您自己实现。

    a.设置通知免打扰时间段

    /**
     * 设置消息通知免打扰时间。
     *
     * @param startTime   起始时间 格式 HH:MM:SS。
     * @param spanMinutes 设置的免打扰结束时间距离起始时间的间隔分钟数。 0 &lt; spanMinutes &lt; 1440。
     *                    比如,您设置的起始时间是 00:00, 结束时间为 23:59,则 spanMinutes 为 23 * 60 + 59 = 1339 分钟。                        
     * @param callback    消息通知免打扰时间回调。
     */
    public void setNotificationQuietHours(final String startTime, final int spanMinutes, final OperationCallback callback)
    

    注:spanMinutes 是指您设置的免打扰结束时间距离起始时间的间隔。比如,您设置的起始时间是 00:00, 结束时间为 23:59,则 spanMinutes 为 23 * 60 + 59 = 1339 分钟。

    b.取消通知免打扰

    /**
     * 移除消息通知免打扰时间。
     *
     * @param callback 移除消息通知免打扰时间回调。
     */
    public void removeNotificationQuietHours(final OperationCallback callback)
    

    会话置顶

    可以通过下面的方法设置某一会话为置顶,或者取消置顶。

    /**
     * 设置某一会话为置顶或者取消置顶,回调方式获取设置是否成功。
     *
     * @param conversationType 会话类型。
     * @param id               目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id 或聊天室 Id。
     * @param isTop            是否置顶。
     * @param callback         设置置顶或取消置顶是否成功的回调。
     */
    public void setConversationToTop(final Conversation.ConversationType conversationType, final String id, final boolean isTop, final ResultCallback<Boolean> callback)
    

    获取会话未读消息数

    获取所有会话的未读消息数(不包含聊天室,因为聊天室消息不计数)

    /**
     * 通过回调方式,获取所有未读消息数。即除了聊天室之外其它所有会话类型的未读消息数。
     *
     * @param callback 消息数的回调。
     */
    public void getTotalUnreadCount(final ResultCallback<Integer> callback)
    

    获取指定的某几个会话的未读消息数

    /**
     * 通过回调方式,获取所有指定会话的未读消息数(聊天室除外)。
     *
     * @param callback      获取未读数的回调。
     * @param conversations 需要获取未读数的指定会话。
     */
    public void getTotalUnreadCount(final ResultCallback<Integer> callback, final Conversation... conversations)
    

    获取指定的某一条会话的未读消息数

    /**
     * 根据会话类型的目标 Id,回调方式获取来自某用户(某会话)的未读消息数。
     *
     * @param conversationType 会话类型。
     * @param targetId         目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id。
     * @param callback         未读消息数的回调。
     */
    public void getUnreadCount(final Conversation.ConversationType conversationType, final String targetId, final ResultCallback<Integer> callback)
    

    获取某一种或某几种会话类型的未读消息数

    /**
     * 回调方式获取某会话类型的未读消息数。
     *
     * @param callback          未读消息数的回调。
     * @param conversationTypes 会话类型。
     */
    public void getUnreadCount(final ResultCallback<Integer> callback, final Conversation.ConversationType... conversationTypes)
    

    用户关系管理

    黑名单

    将用户加入黑名单之后,将不再收到对方发来的任何消息。例如,用户 A 将用户 B 加入黑名单,A 仍然可以给 B 发消息,B 也能正常收到。 但 B 无法给 A 发消息,会提示 “您的消息已经发出,但被对方拒收”。

    加入黑名单

    /**
     * 将某个用户加到黑名单中。
     * <p>当把对方加入黑名单后,对方再发消息时,就会提示“您的消息已经发出, 但被对方拒收”。但您仍然可以给对方发送消息。</p>
     *
     * @param userId   用户 Id。
     * @param callback 加到黑名单回调。
     */
    public void addToBlacklist(final String userId, final OperationCallback callback)
    

    将某个用户从黑名单移除

    /**
     * 将个某用户从黑名单中移出。
     *
     * @param userId   用户 Id。
     * @param callback 移除黑名单回调。
     */
    public void removeFromBlacklist(final String userId, final OperationCallback callback)
    

    查询某个用户是否在黑名单中

    /**
     * 获取某用户是否在黑名单中。
     *
     * @param userId   用户 Id。
     * @param callback 获取用户是否在黑名单回调。
     */
    public void getBlacklistStatus(final String userId, final ResultCallback<BlacklistStatus> callback)
    

    该查询方法会以回调方式返回该用户的黑名单状态,黑名单状态 BlacklistStatus 定义如下:

    /**
     * 是否在黑名单中状态。
     */
    public enum BlacklistStatus {
    
        /**
         * 在黑名单中。
         */
        IN_BLACK_LIST(0),
    
        /**
         * 不在黑名单中。
         */
        NOT_IN_BLACK_LIST(1);
      }
    

    获取黑名单列表

    /**
     * 获取当前用户设置的黑名单列表。
     *
     * @param callback 获取黑名单回调。
     */
    public void getBlacklist(final GetBlacklistCallback callback)
    

    消息体内携带用户信息

    在发送消息时可以设置携带用户信息,以便快捷的实现用户信息的刷新及显示.

    使用示例:

    String targetId = "1111";
    TextMessage textMessage = TextMessage.obtain("test");
    
    //设置用户信息方法一: 只在文本消息内设置携带的用户信息。其它类型的消息也可以用同样的方法单独设置。
    textMessage.setUserInfo(getCurrentUserInfo());
    // 构造 Message 对象
    Message message = Message.obtain(targetId, Conversation.ConversationType.PRIVATE, textMessage);
    
    // 设置用户信息方法二: 通过调用 MessageContent 的 setUserInfo() 方法, 设置所有类型的消息都携带用户信息。
    message.getContent().setUserInfo(getCurrentUserInfo());
    
    // 发送消息
    RongIMClient.getInstance().sendMessage(message, null, null, new IRongCallback.ISendMessageCallback() {
        @Override
        public void onAttached(Message message) {
    
        }
    
        @Override
        public void onSuccess(Message message) {
    
        }
    
        @Override
        public void onError(Message message, RongIMClient.ErrorCode errorCode) {
    
        }
    });
    

    接受到消息时,通过 message.getContent.getUserInfo() 即可获取携带的用户信息。

    群组业务

    群组关系和群组列表由您的 App 维护,客户端的所有群组操作都需要请求您的 App Server , 您的 App Server 可以根据自己的逻辑进行管理和控制,然后通过 Server API 接口进行群组操作,并将结果返回给客户端。

    以下展示了客户端进行群组操作的流程。

    创建群组

    App -> App Server: App 向自已应用服务器发起创建群组请求。 App Server -> RongCloud Server: 授权成功后,在融云服务端同步创建群组。\n /group/create RongCloud Server -> App Server: 创建成功,返回状态。 App Server -> App: 创建成功,可以发送群组信息。

    加入群组

    App -> App Server: App 向自已应用服务器发起加入群组请求。 App Server -> RongCloud Server: 授权成功后,调用融云服务端加入群组接口。\n /group/join RongCloud Server -> App Server: 加入成功,返回状态。 App Server -> App: 加入成功,用户可在群组中发送信息。

    退出群组

    App -> App Server: App 向自已应用服务器发起退出群组请求。 App Server -> RongCloud Server: 授权成功后,调用融云服务端退出群组接口。\n /group/quit RongCloud Server -> App Server: 退出成功,返回状态。 App Server -> App: 退出群组,用户不会再收到此群组信息。

    解散群组

    App -> App Server: App 向自已应用服务器发起解散群组请求。 App Server -> RongCloud Server: 授权成功后,调用融云服务端解散群组接口。\n /group/dismiss RongCloud Server -> App Server: 解散成功,返回状态。 App Server -> App: 成功解散群组。

    设置群组信息

    App -> App Server: App 向自已应用服务器发起设置群组信息请求。 App Server -> RongCloud Server: 授权成功后,调用融云服务端设置群组信息接口。\n /group/refresh RongCloud Server -> App Server: 设置成功,返回状态。 App Server -> App: 群组信息设置成功。

    获取群组成员列表

    App -> App Server: App 向自已应用服务器发起查询群组成员请求。 App Server -> App: 成功,返回成员信息。

    获取群组列表

    App -> RongCloud Server: 连接融云服务器。 connect RongCloud Server -> App: 连接成功,返回状态信息。 App --> App Server: 请求获取群组列表 App Server -> RongCloud Server: 如有变更,需要向融云服务端同步群组信息。 RongCloud Server -> App Server: 成功,返回状态信息。 App Server --> App: 成功,返回群组列表。
    建议在登录成功之后从 App 服务器获取一次群组列表信息,以保证客户端和服务器的群组信息同步,提升用户体验。

    聊天室业务

    聊天室业务基本概念

    聊天室是指多个用户一起聊天,用户数量没有上限。和其它业务场景的主要区别如下:

    1. 用户退出聊天界面后即视为离开聊天室,不会再接收到任何聊天室消息。

    2. 聊天室消息不会保存到本地数据库,融云服务端最多保存聊天室最近的 50 条消息。客户端在调用加入聊天室接口时可以设置进入聊天室时的拉取消息数量。

    3. 聊天室的会话关系由融云负责建立并保持连接,通过 SDK 相关接口,可以让用户加入或者退出聊天室。

    加入聊天室

    加入聊天室,如果聊天室不存在,会自动创建并加入。

    /**
     * 加入聊天室。如果聊天室不存在,sdk 会创建聊天室并加入,如果已存在,则直接加入。加入聊天室时,可以选择拉取聊天室消息数目。
     *
     * @param chatRoomId      聊天室 Id。
     * @param defMessageCount 进入聊天室拉取消息数目,-1 时不拉取任何消息,0 时拉取 10 条消息,最多只能拉取 50 条。
     * @param callback        状态回调。
     */
    public void joinChatRoom(final String chatRoomId, final int defMessageCount, final OperationCallback callback)
    

    加入已经存在的聊天室,如果聊天室不存在,则加入失败。

    /**
     * 加入已存在的聊天室。如果聊天室不存在,则加入失败。加入聊天室时,可以选择拉取聊天室消息数目。
     *
     * @param chatRoomId      聊天室 Id。
     * @param defMessageCount 进入聊天室拉取消息数目,-1 时不拉取任何消息,0 时拉取 10 条消息,最多只能拉取 40 条。
     * @param callback        状态回调。
     */
    public void joinExistChatRoom(final String chatRoomId, final int defMessageCount, final OperationCallback callback)
    

    退出聊天室

    /**
     * 退出聊天室。
     *
     * @param chatRoomId 聊天室 Id。
     * @param callback   状态回调。
     */
    public void quitChatRoom(final String chatRoomId, final OperationCallback callback)
    

    查询聊天室信息

    查询聊天室中最早或最晚加入的 N 个成员信息,包括成员 id, 加入聊天室时间,以及当前聊天室总人数。

    /**
     * 查询聊天室信息。回调中返回{@link ChatRoomInfo}
     *
     * @param chatRoomId     聊天室 Id。
     * @param defMemberCount 进入聊天室拉成员数目,最多 20 条。
     * @param order          按照何种顺序返回聊天室成员信息。升序, 返回最早加入的用户列表; 降序, 返回最晚加入的用户列表。{@link io.rong.imlib.model.ChatRoomInfo.ChatRoomMemberOrder}
     * @param callback       状态回调。
     */
    public void getChatRoomInfo(final String chatRoomId, final int defMemberCount, final ChatRoomInfo.ChatRoomMemberOrder order, final ResultCallback<ChatRoomInfo> callback)
    

    获取服务器聊天室历史消息

    该功能需开通后才能使用,详细请查看聊天室消息云存储服务说明

    开通聊天室消息存储功能后,融云内置的文字、语音、图片、图文、位置、文件等消息会自动在服务器端进行存储,如果您的聊天室中用到了自定义类消息,可通过定义 MessageTag.ISPERSISTED 来设置消息是否进行存储。

    从服务器端获取聊天室历史消息的接口如下:

    /**
     * 获取聊天室历史消息记录。
     * 此方法从服务器端获取之前的历史消息,但是必须先开通聊天室消息云存储功能。
     * 如果指定时间 0,则从存储的第一条消息开始拉取。
     *
     * @param targetId   目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id。
     * @param recordTime 起始的消息发送时间戳,单位: 毫秒。
     * @param count      要获取的消息数量,count 大于 0 ,小于等于 200。
     * @param order      拉取顺序: 降序, 按照时间戳从大到小; 升序, 按照时间戳从小到大。
     */
    public void getChatroomHistoryMessages(final String targetId, final long recordTime, final int count, final TimestampOrder order, final IRongCallback.IChatRoomHistoryMessageCallback callback)
    

    讨论组业务

    讨论组是用户自发创建的多人聊天,在客户端您可以完成讨论组的创建、加入、退出、踢人、设置等。

    /**
     * 创建讨论组。
     *
     * @param name       讨论组名称,如:当前所有成员的名字的组合。
     * @param userIdList 讨论组成员 Id 列表。
     * @param callback   创建讨论组成功后的回调。
     */
    public void createDiscussion(final String name, final List<String> userIdList, final CreateDiscussionCallback callback)
    
    /**
     * 添加一名或者一组用户加入讨论组。
     *
     * @param discussionId 讨论组 Id。
     * @param userIdList   邀请的用户 Id 列表。
     * @param callback     执行操作的回调。
     */
    public void addMemberToDiscussion(final String discussionId, final List<String> userIdList, final OperationCallback callback)
    
    /**
     * <p>供创建者将某用户移出讨论组。
     * 如果当前登陆用户不是此讨论组的创建者并且此讨论组没有开放加人权限,则会返回错误 {@link RongIMClient.ErrorCode}。
     * 不能使用此接口将自己移除,否则会返回错误 {@link RongIMClient.ErrorCode}。
     * 如果您需要退出该讨论组,可以使用 {@link #quitDiscussion(String, OperationCallback)} 方法。</p>
     *
     * @param discussionId 讨论组 Id。
     * @param userId       用户 Id。
     * @param callback     执行操作的回调 {@link io.rong.imlib.RongIMClient.OperationCallback}。
     */
    public void removeMemberFromDiscussion(final String discussionId, final String userId, final OperationCallback callback)
    
    /**
     * 退出当前用户所在的某讨论组。
     *
     * @param discussionId 讨论组 Id。
     * @param callback     执行操作的回调。
     */
    public void quitDiscussion(final String discussionId, final OperationCallback callback)
    
    /**
     * 获取讨论组信息和设置。
     *
     * @param discussionId 讨论组 Id。
     * @param callback     获取讨论组的回调。
     */
    public void getDiscussion(final String discussionId, final ResultCallback<Discussion> callback)
    
    /**
     * 设置讨论组名称。
     *
     * @param discussionId 讨论组 Id。
     * @param name         讨论组名称。
     * @param callback     设置讨论组的回调。
     */
    public void setDiscussionName(final String discussionId, final String name, final OperationCallback callback)
    
    /**
     * 设置讨论组成员邀请权限。
     * 讨论组默认开放加人权限,即所有成员都可以加人。
     * 如果关闭加人权限之后,只有讨论组的创建者有加人权限。
     * @param discussionId 讨论组 Id。
     * @param status       邀请状态,默认为开放。
     * @param callback     设置权限的回调。
     */
    public void setDiscussionInviteStatus(final String discussionId, final DiscussionInviteStatus status, final OperationCallback callback)
    

    客服业务

    对界面要求较高、有定制要求的用户,可以使用 IMLib 进行集成,IMLib 中客服功能集成使用说明:

    • 在进入到客服聊天界面时,调用 startCustomService() 来启动客服服务。这个方法没有回调,有一个监听 ICustomServiceListener,启动的状态要在监听的回调里面处理,启动成功后会回调 onSuccess ,并携带配置信息 CustomServiceConfig
    • 根据 onModeChanged 的回调来处理不同的键盘输入。在机器人优先模式下,需要在界面上加上转人工的按钮。
    • onQuit 时,离开客服会话或者提示客服服务已经结束。
    • 当用户按下转人工服务时,调用 switchToHumanMode 来切换到人工服务。如果调用成功,onModeChanged 回调返回服务类型。
    • 当离开界面时,调用 stopCustomeService 来结束客服。
    • 在适当的时机对客服进行评价,调用 evaluateCustomService,根据参数不同评价机器人或者人工。

    RongIMClient 类文件中的客服相关接口:

    #pragma mark - 客服方法
    
    /**
     * <p>启动客服服务</p>
     *
     * @param kefuId            客服 id,用户去融云开发者后台申请开通后获得客服Id
     * @param listener          客服监听,监听客服的状态 {@link io.rong.imlib.ICustomServiceListener}
     * @param customServiceInfo 客服用户信息,包括用户基本信息,用户联系信息以及请求信息
     *                          其中 nickName 不能为空, 如果为空,则上传当前用户userId
     *                          {@link io.rong.imlib.model.CSCustomServiceInfo}
     */
    public void startCustomService(String kefuId, ICustomServiceListener listener, CSCustomServiceInfo customServiceInfo)
    
    /**
     * <p>切换到人工客服模式,切换的结果需要在 {@link ICustomServiceListener#onModeChanged(CustomServiceMode)} 方法回调中处理</p>
     * 如果客服没有分组, 则直接切人工模式;如果客服有分组,那么需要在回调{@link ICustomServiceListener#onSelectGroup(List)}
     * 中去弹出分组选择窗口并选择分组,之后在这个回调中调用 @see{@link RongIMClient#selectCustomServiceGroup(String, String)}
     * 根据客服 Id 和 分组 Id 去切换到人工模式
     * <p>客服模式 分为无服务,机器人模式,人工模式,机器人优先模式,人工优先模式</p>
     *
     * @param kefuId 客服 id,用户去融云开发者后台申请开通后获得客服Id
     *               {@link io.rong.imlib.model.CustomServiceMode}
     */
    public void switchToHumanMode(final String kefuId)
    
    /**
     * 根据客服ID和分组ID转换人工模式
     *
     * @param kefuId  客服ID
     * @param groupId 分组ID
     */
    public void selectCustomServiceGroup(String kefuId, String groupId) {
        sendChangeModelMessage(kefuId, groupId);
    }
    
    
    /**
     * <p>对机器人客服评价,在机器人模式下使用此方法进行评价</p>
     *
     * @param kefuId          客服 id,用户去融云开发者后台申请开通后获得客服Id
     * @param isRobotResolved robot 客服是否解决了您的问题. true 表示解决 ,false 表示未解决
     * @param knowledgeId     机器人评价的消息id,同时满足以下4个条件,此参数有效,其余情况可以传空字符串.
     *                        当参数有效时, 取出4中描述的 “sid” 对应的值就是需要传入的knowledgeId,
     *                        <p>1.机器人模式
     *                        <p>2.新收到的消息,不是从数据库中加载的历史消息
     *                        <p>3.CustomServiceConfig 的 robotSessionNoEva 为true  @see {@link io.rong.imlib.CustomServiceConfig }
     *                        这个CustomServiceConfig 是客服启动成功后的回调onSuccess()带回的参数 @see {@link io.rong.imlib.ICustomServiceListener}
     *                        <p>4.MessageContent 的 Extra 中有“robotEva”和“sid”两个字段.
     */
    public void evaluateCustomService(String kefuId, boolean isRobotResolved, String knowledgeId)
    
    /**
     * <p>对人工客服评价,在人工模式下使用此方法进行评价</p>
     *
     * @param kefuId   客服 id,用户去融云开发者后台申请开通后获得客服Id
     * @param source   星级,范围 1-5,5为最高,1为最低
     * @param suggest  客户的针对人工客服的意见和建议
     * @param dialogId 会话 Id. 客服后台主动拉评价的时候这个参数有效,其余情况传空字符串即可.
     *                 客服主动拉评价的时候, 会走 ICustomServiceListener 的 onPullEvaluation 回调,并带回 dialogId
     * {@link io.rong.imlib.ICustomServiceListener}
     */
    public void evaluateCustomService(String kefuId, int source, String suggest, String dialogId)
    
    /**
     * <p>结束客服. 调用此方法后,将向客服发起结束请求</p>
     *
     * @param kefuId 客服 id,用户去融云开发者后台申请开通后获得客服Id
     */
    public void stopCustomService(String kefuId)
    
    /**
    * 开启客服成功后,回调时携带的配置信息
    */
    public class CustomServiceConfig {
    
      /**
       * 是否被加入黑名单
       */
      public boolean isBlack;
    
      /**
       * 描述
       */
      public String msg;
    
      /**
       * 公司名称
       */
      public String companyName;
    
      /**
       * 公司logo
       */
      public String companyIcon;
    
      /**
       * 机器人是否需要评价会话
       */
      public boolean robotSessionNoEva;
    
      /**
       * 满意度评价列表
       *
       * CSHumanEvaluateItem getValue():取满意度评价值
       * CSHumanEvaluateItem getDescription():取满意度评价描述
       * {@link io.rong.message.CSHumanEvaluateItem}
       */
      public ArrayList<CSHumanEvaluateItem> humanEvaluateList;
    
      public CustomServiceConfig() {
      }
    }
    
    /**
    * 开启客服时,传入监听
    */
    public interface ICustomServiceListener {
      /**
       * 开启客服成功
       *
       * @param config    开启客服成功后,返回的配置信息
       *                  @see {@link io.rong.imlib.CustomServiceConfig}
       */
      void onSuccess(CustomServiceConfig config);
    
      /**
       * 客服开启失败
       *
       * @param code      错误码
       * @param msg       错误描述
       */
      void onError(int code, String msg);
    
      /**
       * 客服模式发生变化
       *
       * @param mode      变化后的客服模式, 以下模式之一 : 无服务,机器人,人工,机器人优先,人工优先
       *                  @see {@link io.rong.imlib.model.CustomServiceMode}
       */
      void onModeChanged(CustomServiceMode mode);
    
      /**
       * 离开客服
       *
       * @param msg 离开描述
       */
      void onQuit(String msg);
    
      /**
       * 客服主动下发满意度评价
       *
       * @param dialogId  会话Id. 客服主动下发评价时,提交评价要带上此参数
       */
      void onPullEvaluation(String dialogId);
    
      /**
       * 客服有分组时,选择分组.
       * 当初始化客服的握手响应消息(@see {@link io.rong.message.CSChangeModeResponseMessage})中带回的分组数据不为空的时候,触发此回调。
       * 需要在此回调中弹出分组选择列表,并选择一个分组。根据选择的groupId调用 {@link RongIMClient#selectCustomServiceGroup(String, String)}转人工模式
       *
       * @param groups 客服的分组列表 @see {@link io.rong.imlib.model.CSGroupItem}
       */
      void onSelectGroup(List<CSGroupItem> groups);
    }
    

    公众号业务

    融云公众服务是为应用开发者和公众帐号运营者提供的连接服务产品,通过融云公众服务,App 可以具备为自己的用户提供公众帐号服务的能力和资源。

    公众服务包括应用公众服务公众服务平台

    应用公众服务:是为应用开发者提供的 App 内建公众服务能力,通过在融云开发者站点创建 App 公众号,实现应用内的公众服务。

    公众服务平台:是在应用开发者和公众帐号运营者之间建立的对接平台,应用开发者可以通过平台引入公众服务资源,帮助 App 快速覆盖用户需求,公众帐号持有者通过平台可以有机会向所有集成融云 SDK 的 App 提供服务,进而获得更加精准更加丰富的受众渠道。

    开发者可以参考融云公众号开发文档,注册您应用自己的公众服务。客户端可以通过 SDK 中的接口来订阅或者取消订阅公众号。

    前提条件:

    1. RongIMClient.init(this),接口已经执行。
    2. RongIMClient.connect(....),接口已经执行且 onSuccess() 被回调。

    订阅公众号

    /**
     * 订阅公众号。
     *
     * @param publicServiceType 公众服务类型。
     * @param publicServiceId   公共服务 Id。
     * @param callback          订阅公众号回调。
     */
    public void subscribePublicService(final Conversation.PublicServiceType publicServiceType, final String publicServiceId, final OperationCallback callback)
    

    取消订阅

    /**
     * 取消订阅公众号。
     *
     * @param publicServiceType 公众服务类型。
     * @param publicServiceId   公共服务 Id。
     * @param callback          取消订阅公众号回调。
     */
    public void unsubscribePublicService(final Conversation.PublicServiceType publicServiceType, final String publicServiceId, final OperationCallback callback)
    

    获取已关注的公众号信息列表

    /**
     * 获取己关注公共账号列表。
     *
     * @param callback 获取己关注公共账号列表回调。
     */
    public void getPublicServiceList(final ResultCallback<PublicServiceProfileList> callback)
    

    获取某个公众号的信息

    /**
     * 获取某公共服务信息。
     *
     * @param publicServiceType 公众服务类型。
     * @param publicServiceId   公共服务 Id。
     * @param callback          公共账号信息回调。
     */
    public void getPublicServiceProfile(final Conversation.PublicServiceType publicServiceType, final String publicServiceId, final ResultCallback<PublicServiceProfile> callback)
    

    推送服务

    推送服务的概念

    融云推送服务指的是从服务端远程发送一条包含消息内容的推送,当客户端 App 接收到之后,可以在通知栏弹出提醒。

    由于谷歌推送服务(GCM/FCM)在国内不能使用,所以 Android App 需要实现自己的推送服务,融云作为即时通信能力的提供者,也提供了实时推送的能力。您可以通过开发者后台使用我们的推送服务,另外我们的 IMKit 和 IMLib SDK 默认都具备推送功能。

    开发者后台的推送服务

    您可以登录开发者后台,在“广播推送”服务中推送内容。

    通过该推送服务,您可以往系统内全部或部分用户发送一条通知提醒,提醒内容为您在推送服务界面填写的内容。无论您的应用是否在前台,该推送固定通过推送通道送达客户端,并且在客户端通知栏以通知的形式展示。

    SDK 默认具备的推送功能

    融云 SDK 在 connect() 成功之后,会有两个长连接通道:主消息通道和推送通道。当主消息通道处于连接状态时,消息通过主通道送达。当主消息通道断开连接时,会通过推送通道发送一条关于该消息的推送通知,用户点击该通知重新 connect() 成功后,会通过主通道接受到该消息。

    如何使用推送

    详细请参考 Android 推送集成文档

    @ 功能

    1、新增 MentionedInfo 类,说明如下:

    public class MentionedInfo implements Parcelable {
        /*@消息类型,可以@部分人或者@所有人*/
        private MentionedType type;
        /*@消息的@成员列表。如果 MentionedType 为 All, 该 List 传 null 即可。如果 MentionedType 为 PART, 该 List 为需要 @ 的成员列表,不能为 null。*/
        private List<String> userIdList;
        /*@消息的提醒内容。如果填写了该内容,那被 @ 的人在收到该 @ 消息的通知时,通知内容展示为此处填写的内容。如果没有填写,则通知展示为 SDK 默认内容*/
        private String mentionedContent;
    
        public enum MentionedType {
        ALL(1),
        PART(2);
        }
    }
    

    2、MessageContent 里增加了设置 @ 信息的方法:

    void setMentionedInfo(MentionedInfo info)
    

    您可以通过该方法将 @ 信息设置到具体的消息内容里去。如:

    MentionedInfo mentionedInfo = new
    MentionedInfo(MentionedInfo.MentionedType.ALL, null, null);
    textMessage.setMentionedInfo(mentionedInfo);
    

    3、Conversation 类里增加了方法来获取该会话的未读 @ 消息个数。

    /**
     * 获取本会话里自己被@的消息数量。
     * @return 返回该会话里的@消息个数。
     */
    public int getMentionedCount() {
        return mentionedCount;
    }
    

    4、RongIMClient 里新增加获取会话里所有未读 @ 消息的方法。

    /**
     * 获取某会话里未读的@消息。
     *
     * @param conversationType 会话类型。
     * @param targetId         目标 Id。根据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id。
     * @param callback         获取未读@消息的回调。回调里返回的消息列表,按照时间顺序从旧到新。最多返回最近的十条未读 @ 消息。
     * */
    public void getUnreadMentionedMessages(final Conversation.ConversationType conversationType, final String targetId, final ResultCallback<List<Message>> callback)
    
    @ 消息推送会越过所有免打扰逻辑,给用户推送 Push 通知。
    如果是自定义消息,在使用 @ 功能时,发送消息必须设置 pushContent,否则不会发送 Push。

    高级功能

    消息撤回

    通过调用 recallMessage 接口来撤回一条已发送的消息,接口定义:

    /**
     * 撤回消息
     *
     * @param message 将被撤回的消息
     * @param callback onSuccess里回调{@link RecallNotificationMessage},IMLib 已经在数据库里将被撤回的消息用{@link RecallNotificationMessage} 替换,
     *                 用户需要在界面上对{@link RecallNotificationMessage} 进行展示。
     */
    public void recallMessage(final Message message, final RongIMClient.ResultCallback<RecallNotificationMessage> callback)
    

    其中,RecallNotificationMessage 的结构如下:

    /**
     * 撤回通知消息,当用户撤回消息或者收到一条撤回信令消息时,需要根据此通知消息在界面上进行展示。
     *
     */
    @MessageTag(value = "RC:RcNtf", flag = MessageTag.ISPERSISTED)
    public class RecallNotificationMessage extends MessageContent {
        /**
         * 发起撤回消息的用户id
         */
        public String getOperatorId();
    
        /**
         * 撤回的时间(毫秒)
         */
        public long getRecallTime();
    
        /**
         * 原消息的消息类型名
         */
        public String getOriginalObjectName();
    }
    

    通过 RecallNotificationMessage 的三个 get 方法来获取必要的信息。

    您还需要设置撤回指令的监听器,以便在接收端收到撤回指令时刷新界面。

    /**
     * 撤回消息监听器
     */
     public interface OnRecallMessageListener {
         boolean onMessageRecalled(Message message, RecallNotificationMessage recallNotificationMessage);
     }
    
    /**
     * 设置撤回消息监听器
     *
     * @param listener 撤回消息监听器
     */
    public static void setOnRecallMessageListener(final OnRecallMessageListener listener)
    

    同样,您需要在 onMessageRecalled 回调里根据 recallNotificationMessage 的内容来进行界面刷新。

    RongIMClient.setRecallMessageListener(new RongIMClient.RecallMessageListener() {
        @Override
        public void onMessageRecalled(int messageId, RecallNotificationMessage recallNotificationMessage) {
            //根据 recallNotificationMessage 的内容进行界面刷新
        }
    });
    

    消息阅读回执

    单聊消息阅读回执

    您可以在用户查看了单聊会话中的未读消息之后,向会话中发送阅读回执,会话中的用户可以根据此回执,在 UI 中更新消息的显示。

    其中,timestamp 为会话中用户已经阅读的最后一条消息的发送时间戳(MessagesentTime 属性),代表用户已经阅读了该会话中此消息之前的所有消息。

    /**
     * 发送某个会话中消息阅读的回执
     * @param conversationType 会话类型
     * @param targetId 目标会话ID
     * @param timestamp 该会话中已阅读点最后一条消息的发送时间戳
     * 目前只支持单聊, 如果使用Lib可以注册监听 setReadReceiptListener ,使用kit直接设置rc_config.xml 中 rc_read_receipt为true
     */
    public void sendReadReceiptMessage(Conversation.ConversationType conversationType, String targetId, long timestamp)
    

    在接收端,您可以监听已读回执的监听来更新消息的相关显示。

    /**
     * 消息回执监听器
     */
    public interface ReadReceiptListener {
        /**
         * 单聊会话收到消息回执
         * @param message 封装了一个ReadReceiptMessage
         */
        void onReadReceiptReceived (Message message);
    
        /**
         * 群组和讨论组中,某人发起了回执请求,会话中其余人会收到该请求,并回调此方法。
         * 接收方需要在合适的时机(读取了消息之后)调用 {@link RongIMClient#sendReadReceiptResponse(Conversation.ConversationType, String, List, OperationCallback)} 回复响应。
         *
         * @param type           会话类型
         * @param targetId       会话目标 id
         * @param messageUId     请求已读回执的消息 uId
         */
        void onMessageReceiptRequest(Conversation.ConversationType type, String targetId, String messageUId);
    
        /**
         * 在群组和讨论组中发起了回执请求的用户,当收到接收方的响应时,会回调此方法。
         *
         * @param type              会话类型
         * @param targetId          会话 id
         * @param messageUId        收到回执响应的消息的 uId
         * @param respondUserIdList 会话中响应了此消息的用户列表。其中 key: 用户 id ; value: 响应时间
         */
        void onMessageReceiptResponse(Conversation.ConversationType type, String targetId, String messageUId, HashMap<String, Long> respondUserIdList);
    }
    
    /**
    * 设置消息回执监听器
    * @param listener 消息回执监听器
    */
    RongIMClient.setReadReceiptListener(new RongIMClient.ReadReceiptListener() {
       @Override
       public void onReadReceiptReceived(final Message message) {
       }
    
       @Override
       public void onMessageReceiptRequest(Conversation.ConversationType type, String targetId, String messageUId) {
       }
    
       @Override
       public void onMessageReceiptResponse(Conversation.ConversationType type, String targetId, String messageUId, HashMap<String, Long> respondUserIdList) {
       }
    });
    

    onReadReceiptReceived() 回调里,请先判断 message.getConversationType()message.getTargetId() 和当前会话一致,然后在UI里把该会话中发送时间戳之前的所有已发送消息状态置为已读(底层数据库消息状态已经改为已读)。

    void onReadReceiptReceived (Message message) {
        if (mConversation != null && mConversation.getTargetId().equals(message.getTargetId()) && mConversation.getConversationType() == message.getConversationType()) {
    
            ReadReceiptMessage content = (ReadReceiptMessage) message.getContent();
            //获取发送时间戳
            long ntfTime = content.getLastMessageSendTime();
            //自行进行UI处理,把会话中发送时间戳之前的所有已发送消息状态置为已读
            ...
        }
    }
    

    群组、讨论组消息阅读回执

    此功能目前仅在 GROUP 和 DISCUSSION 类型的会话中开放。用户可以对自己发送的消息发起阅读回执请求,发起后可以看到有多少人阅读过这条消息。

    发起阅读回执请求
    /**
     * 发起群组消息回执请求。
     * 只能对自己发送的消息发起消息回执请求。
     *
     * @param message       需要请求回执的那条消息,io.rong.imlib.model.Message对象
     * @param callback      回调函数
     */
    RongIMClient.getInstance().sendReadReceiptRequest(message, new RongIMClient.OperationCallback() {
        @Override
        public void onSuccess() {
        }
    
        @Override
        public void onError(RongIMClient.ErrorCode errorCode) {
            RLog.e(TAG, "sendReadReceiptRequest failed, errorCode = " + errorCode);
        }
    });
    
    响应消息回执请求

    如果在会话中收到了回执请求,接收者需要在合适的时机响应该请求,以通知发送者自己已经阅读了该消息。

    可以一次响应同一会话中的多条消息,调用下面接口:

    /**
     * 发送群消息已读回执
     *
     * @param type          会话类型,Conversation.ConversationType对象
     * @param targetId      会话 id
     * @param messageList   会话中需要发送回执的消息列表,List<io.rong.imlib.model.Message>对象
     * @param callback      回调函数
     */
     RongIMClient.getInstance().sendReadReceiptResponse(type, targetId, messageList, new RongIMClient.OperationCallback() {
         @Override
         public void onSuccess() {
         }
    
         @Override
         public void onError(RongIMClient.ErrorCode errorCode) {
             RLog.e(TAG, "sendReadReceiptResponse failed, errorCode = " + errorCode);
         }
     });
    
    设置消息回执监听

    您需要设置消息回执监听,以此来接收回执消息并更新消息的显示。

    /**
     * 消息回执监听器。
     */
    public interface ReadReceiptListener {
        /**
         * 单聊中收到消息回执的回调。
         *
         * @param message 封装了一个{@link ReadReceiptMessage}
         */
        void onReadReceiptReceived(Message message);
    
        /**
         * 群组和讨论组中,某人发起了回执请求,会话中其余人会收到该请求,并回调此方法。
         * 接收方需要在合适的时机(读取了消息之后)调用 {@link RongIMClient#sendReadReceiptResponse(Conversation.ConversationType, String, List, OperationCallback)} 回复响应。
         *
         * @param type           会话类型
         * @param targetId       会话目标 id
         * @param messageUId     请求已读回执的消息 uId
         */
        void onMessageReceiptRequest(Conversation.ConversationType type, String targetId, String messageUId);
    
        /**
         * 在群组和讨论组中发起了回执请求的用户,当收到接收方的响应时,会回调此方法。
         *
         * @param type              会话类型
         * @param targetId          会话 id
         * @param messageUId        收到回执响应的消息的 uId
         * @param respondUserIdList 会话中响应了此消息的用户列表。其中 key: 用户 id ; value: 响应时间
         */
        void onMessageReceiptResponse(Conversation.ConversationType type, String targetId, String messageUId, HashMap<String, Long> respondUserIdList);
    }
    
    /**
     * 设置消息回执监听器
     * @param listener 消息回执监听器
     */
     RongIMClient.setReadReceiptListener(new RongIMClient.ReadReceiptListener() {
         @Override
         public void onReadReceiptReceived(final Message message) {
         }
    
         @Override
         public void onMessageReceiptRequest(Conversation.ConversationType type, String targetId, String messageUId) {
         }
    
         @Override
         public void onMessageReceiptResponse(Conversation.ConversationType type, String targetId, String messageUId, HashMap<String, Long> respondUserIdList) {
         }
      });
    

    多端阅读消息数同步

    多端登录时,通知其它终端同步某个会话的阅读状态,请调用下面接口:

    /**
     * 多端登录时,通知其它终端清除某个会话的未读消息数
     *
     * @param type      会话类型,Conversation.ConversationType对象
     * @param targetId  目标会话 ID
     * @param timestamp 该会话中已读的最后一条消息的发送时间戳{@link Message#getSentTime()}
     * @param callback  回调函数
     */
    RongIMClient.getInstance().syncConversationReadStatus(type, targetId, timestamp, new RongIMClient.OperationCallback() {
        @Override
        public void onSuccess() {
        }
    
        @Override
        public void onError(RongIMClient.ErrorCode errorCode) {
        }
    });
    

    另外,请设置同步阅读状态监听器。

    /**
     * 同步阅读状态监听
     * 多端登录,收到其它端清除某一会话未读数通知的时候,回调 onSyncMessageReadStatus
     */
    public interface SyncConversationReadStatusListener {
        void onSyncConversationReadStatus(Conversation.ConversationType type, String targetId);
    }
    
    RongIMClient.getInstance().setSyncConversationReadStatusListener(new RongIMClient.SyncConversationReadStatusListener() {
        @Override
        public void onSyncConversationReadStatus(Conversation.ConversationType type, String targetId) {
            //重新获取会话的未读数,并且显示到界面上
        }
    });
    

    输入状态提醒

    您可以在用户正在输入的时候,向对方发送正在输入的状态。目前该功能只支持单聊。

    其中,您可以在 typingContentType 中传入消息的类型名,会话中的其他用户输入状态监听中会收到此消息类型。您可以通过此消息类型,自定义不同的输入状态提示(如:正在输入、正在讲话、正在拍摄等)。

    6 秒之内,如果同一个用户在同一个会话中多次调用此接口发送正在输入的状态,为保证产品体验和网络优化,将只有最开始的一次生效。

    /**
     * 向会话中发送正在输入的状态
     *
     * @param conversationType 会话类型
     * @param targetId         会话id
     * @param typingContentType 正在输入的消息的类型名
     * typingContentType为用户当前正在编辑的消息类型名,即message中getObjectName的返回值。
     * 如文本消息,应该传类型名"RC:TxtMsg"。
     * 目前只支持单聊
     */
    public void sendTypingStatus(Conversation.ConversationType conversationType, String targetId, String typingContentType)
    

    开发者可以用下面代码来发送正在输入的状态。

    RongIMClient.getInstance().sendTypingStatus(mCurrentConversation.getConversationType(),
          mCurrentConversation.getTargetId(), objectName);
    

    在接收端,您可以设置输入状态的监听器。

    当前会话正在输入的用户有变化时,会触发监听中的 onTypingStatusChanged(),回调里携带有当前正在输入的用户列表和消息类型。对于单聊而言,当对方正在输入时,监听会触发一次;当对方不处于输入状态时,该监听还会触发一次,但是回调里上来的输入用户列表为空,开发者需要在此时取消正在输入的显示。

    RongIMClient.setTypingStatusListener(new RongIMClient.TypingStatusListener() {
        @Override
        public void onTypingStatusChanged(Conversation.ConversationType type, String targetId, Collection<TypingStatus> typingStatusSet) {
            //当输入状态的会话类型和targetID与当前会话一致时,才需要显示
            if (type.equals(mConversationType) && targetId.equals(mTargetId)) {
                //count表示当前会话中正在输入的用户数量,目前只支持单聊,所以判断大于0就可以给予显示了
                int count = typingStatusSet.size();
                if (count > 0) {
                    Iterator iterator = typingStatusSet.iterator();
                    TypingStatus status = (TypingStatus) iterator.next();
                    String objectName = status.getTypingContentType();
    
                    MessageTag textTag = TextMessage.class.getAnnotation(MessageTag.class);
                    MessageTag voiceTag = VoiceMessage.class.getAnnotation(MessageTag.class);
                    //匹配对方正在输入的是文本消息还是语音消息
                    if (objectName.equals(textTag.value())) {
                        //显示“对方正在输入”
                        mHandler.sendEmptyMessage(SET_TEXT_TYPING_TITLE);
                    } else if (objectName.equals(voiceTag.value())) {
                        //显示"对方正在讲话"
                        mHandler.sendEmptyMessage(SET_VOICE_TYPING_TITLE);
                    }
                } else {
                    //当前会话没有用户正在输入,标题栏仍显示原来标题
                    mHandler.sendEmptyMessage(SET_TARGETID_TITLE);
                }
            }
        }
    });
    

    日志管理

    设置连接相关的 Log 输出监听。注意此方法需要在 connect 之前调用。

    /**
      * 设置连接服务器阶段的 Log 输出监听。需要在connect之前调用,
      *
      * @param listener Log 输出监听器
      */
     public static void setRCLogInfoListener(RCLogInfoListener listener)
    

    Log 监听

    /**
     * 连接服务器阶段 Log 输出监听
     */
    public interface RCLogInfoListener {
        /**
         * 当有 Log 被写文件输出时,回调此方法
         *
         * @param logStr Log 信息
         */
        void onRCLogInfoOccurred(String logStr);
    }
    

    位置共享

    融云 SDK 内置了位置共享相关的各种方法,用户可以通过这些方法,快速实现实时位置共享的功能。

    内置的位置共享方法如下:

    获取位置共享的实例。当你需要在某个会话里发起位置共享时,需要先通过该方法获取 RealTimeLocation 对象。

    /**
     * 获取 RealTimeLocation 实例,每发起一次位置共享业务,就要获取一个实例。
     * 如果获取实例失败,返回 error code,对应具体的失败信息。
     * 使用时,每次进入会话,获取该会话对应的实例,以此判断位置共享业务是否可用或者正在进行中。
     * 如果返回成功,使用者可以设置监听,发起位置共享。
     * 如果返回正在进行中,则是对方已发起位置共享,使用者可以设置监听,加入。
     * 如果返回其他失败信息,使用者可以据此做出相应的提示。
     *
     * @param conversationType 发起位置共享的所在会话的会话类型。
     * @param targetId         发起位置共享的 target id。
     * @return 是否获取实例成功。
     */
    public RealTimeLocationErrorCode getRealTimeLocation(Conversation.ConversationType conversationType, String targetId)
    

    发起位置共享

    /**
     * 发起位置共享。
     *
     * @param conversationType 发起位置共享的会话类型。
     * @param targetId         发起位置共享的 targetId。
     * @return 是否开启成功。对应具体的错误码 {@link RealTimeLocationErrorCode}
     */
    public RealTimeLocationErrorCode startRealTimeLocation(final Conversation.ConversationType conversationType, final String targetId)
    

    加入位置共享

    /**
     * 加入位置共享。
     *
     * @param conversationType 位置共享的会话类型。
     * @param targetId         位置共享的 targetId。
     * @return 是否加入成功。对应具体的错误码 {@link RealTimeLocationErrorCode}
     */
    public RealTimeLocationErrorCode joinRealTimeLocation(final Conversation.ConversationType conversationType, final String targetId)
    

    退出位置共享

    /**
     * 退出位置共享。
     *
     * @param conversationType 位置共享的会话类型。
     * @param targetId         位置共享的 targetId。
     */
    public void quitRealTimeLocation(final Conversation.ConversationType conversationType, final String targetId)
    

    获取参与位置共享的所有成员

    /**
     * 获取参与该位置共享的所有成员。
     *
     * @param conversationType 位置共享的会话类型。
     * @param targetId         位置共享的 targetId。
     * @return 参与成员 id 列表。
     */
    public List<String> getRealTimeLocationParticipants(Conversation.ConversationType conversationType, String targetId)
    

    获取位置共享状态

    /**
     * 获取位置共享状态。
     *
     * @param conversationType 位置共享的会话类型。
     * @param targetId         位置共享的 targetId。
     * @return 正在进行的位置共享状态。
     */
    public RealTimeLocationStatus getRealTimeLocationCurrentState(Conversation.ConversationType conversationType, String targetId)
    

    添加位置共享监听

    /**
     * 添加位置共享监听。
     *
     * @param conversationType 位置共享的会话类型。
     * @param targetId         位置共享的 targetId。
     * @param listener         位置共享监听。
     */
    public void addRealTimeLocationListener(final Conversation.ConversationType conversationType, final String targetId, final RealTimeLocationListener listener)
    

    移除位置共享监听

    /**
     * 移除位置共享监听
     * @param conversationType 会话类型
     * @param targetId 位置共享的会话 id
     * */
    public void removeRealTimeLocationObserver(final Conversation.ConversationType conversationType, final String targetId)
    

    实时位置共享监听的相关方法如下

    public interface RealTimeLocationListener {
        /**
         * 位置共享状态发生改变。
         *
         * @param status 空闲、加入、退出、建立连接等状态
         */
        void onStatusChange(RealTimeLocationStatus status);
    
        /**
         * 接收到位置共享信息。
         *
         * @param latitude  维度
         * @param longitude 经度
         * @param userId    发送者 id
         */
        void onReceiveLocation(double latitude, double longitude, String userId);
    
        /**
         * 对方加入位置共享。
         *
         * @param userId 加入者 id
         */
        void onParticipantsJoin(String userId);
    
        /**
         * 对方退出位置共享
         *
         * @param userId 退出者 id
         */
        void onParticipantsQuit(String userId);
    
        /**
         * 位置共享过程出现错误。
         *
         * @param errorCode 错误码
         */
        void onError(RealTimeLocationErrorCode errorCode);
    }
    

    关于连接

    连接时机

    调用如下方法连接融云服务器。该方法在整个应用全局,只需要调用一次。

    /**
     * 连接服务器,在整个应用程序全局,只需要调用一次。
     *
     * @param token    从服务端获取的 <a
     *                 href="http://docs.rongcloud.cn/android#token">用户身份令牌(
     *                 Token)</a>。
     * @param callback 连接回调。
     * @return  IM 客户端核心类的实例。
     */
    connect(final String token, final RongIMClient.ConnectCallback callback)
    

    连接状态监听

    您可以通过下面的方法设置连接状态监听器,当连接状态发生变化时,会通过该方法监听到。

    /**
     * 设置连接状态变化的监听器。在自定义UI时,会需要调用此接口判断当前连接状态,来绘制UI及决定逻辑走向。
     *
     * @param listener 连接状态变化的监听器。
     */
    public static void setConnectionStatusListener(final ConnectionStatusListener listener)
    

    连接回调异常时的处理

    connect() 方法有三个回调 onSuccess() 、onError 和 onTokenIncorrect(), 每次调用只会回调其中一个,且只会回调一次。

    回调 onTokenIncorrect(),说明 Token 无效,一般有以下两种原因。

    一、Token 错误,请您检查客户端初始化使用的 AppKey 和您服务器获取 Token 使用的 AppKey 是否一致。

    二、Token 过期,是因为您在开发者后台设置了 Token 过期时间,您需要请求您的服务器重新获取 Token 并再次用新的 Token 建立连接。

    通过 connect() 的 onError() 回调,或者通过 setConnectionStatusListener() 设置的监听器监听到错误码时,开发者仅需要关注以下几种连接错误码,其余错误码 SDK 均会进行自动重连,开发者无须处理。

    以下为需要您自己处理的错误码:

    1、AppKey 错误,请检查您使用的 AppKey 是否正确。

    RC_CONN_ID_REJECT = 31002

    2、Token 无效

    RC_CONN_USER_OR_PASSWD_ERROR = 31004

    3、AppKey 与 Token 不匹配

    RC_CONN_NOT_AUTHRORIZED = 31005

    请检查您使用的 AppKey 与 Token 是否正确,是否匹配。一般有以下两种原因。

    一是 Token 错误,请您检查客户端初始化使用的 AppKey 和您服务器获取 Token 使用的 AppKey 是否一致;

    二是 Token 过期,是因为您在开发者后台设置了 Token 过期时间,您需要请求您的服务器重新获取 Token 并再次用新的 Token 建立连接。

    4、包名和后台注册信息不匹配

    RC_CONN_PACKAGE_NAME_INVALID = 31007

    请检查您 App 的 BundleID 是否正确。

    5、AppKey 被封禁或已删除

    RC_CONN_APP_BLOCKED_OR_DELETED = 31008

    请检查您使用的 AppKey 是否正确。

    6、用户被封禁

    RC_CONN_USER_BLOCKED = 31009

    请检查您使用的 Token 是否正确,以及对应的 UserId 是否被封禁。

    7、当前用户在其他设备上登录,此设备被踢下线

    RC_DISCONN_KICK = 31010

    8、SDK 没有初始化

    RC_CLIENT_NOT_INIT = 33001

    在使用 SDK 任何功能之前,必须先 Init。

    9、开发者接口调用时传入的参数错误

    RC_INVALID_PARAMETER = 33003

    请检查接口调用时传入的参数类型和值。

    10、开发者接口调用时传入的参数错误

    RC_INVALID_ARGUMENT = -1000

    请检查接口调用时传入的参数类型和值。

    重连机制

    融云 SDK 中已经为开发者做了重连机制。

    在与服务器的连接断开后,融云会尝试 10 次重新连接服务器,首次断开 1 秒后会重新连接,如果仍然连接不成功,会在 2 秒后(重连间隔时间为上次重连间隔时间乘 2 )尝试重新连接服务器,以此类推当尝试重连 10 次后,仍然连不上服务器将不再尝试重新连接,只有在网络情况发生变化或重新打开应用时才会再次尝试重连。

    在获取到以下错误状态码时,会进行重连:

    code 描述
    30001 进行通信操作过程中,当前 Socket 失效。
    30002 Socket 连接不可用。应该是您当前网络连接不可用。
    30003 进行各种信令的通信操作过程中,信令 ACK 返回超时。
    30004 导航操作时,Http 请求失败。
    30005 HTTP 请求失败。
    30006 HTTP 接收失败。
    30007 通过 HTTP 获取连接网络必须的配置数据时,服务器返回的不是 200 OK,而是 HTTP 的其它错误码。
    30008 通过 HTTP 获取配置数据时,成功获得数据,但得到的内容体部分是空。可能是你所在的网络被劫持,HTTP 被修改。
    30009 导航数据解析后,其中不存在有效 IP 地址。
    30010 创建 Socket 失败。
    30011 Socket 连接被断开,主要有两种情况,一是用户主动调用 disconnect 之后,Socket 被服务器断开;二是中间路由原因导致 Socket 断开。
    30013 PING 超时。
    31000 做 connect 连接时,收到的 ACK 超时。
    30015 调用 connect() 方法过于频繁,间隔时间少于3秒。
    32061 服务器拒绝链接,SDK 会重新获取导航,再次链接。

    常见状态码及处理

    集成融云 SDK 过程中,如遇到问题可查看常见状态码及处理表

    收不到消息提醒解决方案

    部分 Android 手机系统在黑屏待机后自动清理后台运行的软件,这样影响了应用正常接收新的消息,需要将应用设置为后台运行应用。查看各类机型的设置说明