Android SDK 开发指南

Android SDK 开发指南

视频详解

如下视频是对融云 Android SDK 开发使用的详细讲解,您能够在阅读文档时配合学习。html

 

更多视频教程以下:java

  1. CSDN 融云 Android SDK 开发使用教学视频
  2. InfoQ 融云 Android SDK 开发使用教学视频

前期准备

注册开发者账号

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

下载 SDK

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

名称 功能介绍 支持的 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 融云红包相关组件,经过集成该组件,便可快速实现红包功能。 

建立应用

您要进行应用开发以前,须要先在融云开发者平台建立应用。若是您已经注册了融云开发者账号,请前往融云开发者平台建立应用。github

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

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 方法小节。json

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

经过 API 调试,您能够获得一个 Token 返回值。您就能够直接使用这个 Token 为这位用户进行发送和接受消息。api

SDK 集成

环境要求数组

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

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

咱们建议初次集成 SDK 的用户,先建立一个空项目来集成融云的 SDK,而后再考虑加入您的工程。

导入 SDK

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

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

image

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

image

根据您的须要,以一样的步骤导入SDK里的其它组件: IMKit, CallKit, CallLib, RedPacket。

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

image

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

image

将 LocationLib 里的 jar 包拷贝到您应用的 libs 目录下(若是不须要位置功能,可跳过此步骤)。

image

注意

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

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

添加配置

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

image

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

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

打开应用的 App Module 的 AndroidManifest.xml 文件, 把从高德官网获取的 AppKey 添加到 meta-data 里 (若是您不使用位置功能,可跳过此步骤)。

<meta-data
    android:name="com.amap.api.v2.apikey" android:value="高德地图的 AppKey" /> 

在应用的 App Module 的 AndroidManifest.xml 文件中,添加 FileProvider 相关配置,修改 android:authorities 为 “您的应用的包名称.FileProvider”。

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="您的应用包名.FileProvider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/rc_file_path" />
</provider>

初始化

在整个应用程序全局,您只须要调用一次 init 方法。对于快速集成,咱们建议您在 App 主进程初始化,您只须要实现一句函数,如下为融云 Demo 代码示例:

public class App extends Application { @Override public void onCreate() { super.onCreate(); RongIM.init(this); } } 

关于初始化的注意事项

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

您能够在任意进程使用 RongIM,咱们推荐初次集成的用户在主进程使用。

链接服务器

链接服务器前,确认已经过融云 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 RongIM 客户端核心类的实例。 */ private void connect(String token) { if (getApplicationInfo().packageName.equals(App.getCurProcessName(getApplicationContext()))) { RongIM.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) { Log.d("LoginActivity", "--onSuccess" + userid); startActivity(new Intent(LoginActivity.this, MainActivity.class)); finish(); } /** * 链接融云失败 * @param errorCode 错误码,可到官网 查看错误码对应的注释 */ @Override public void onError(RongIMClient.ErrorCode errorCode) { } }); } } 

配置会话列表

融云 IMKit SDK 使用了 Fragment 做为会话列表和会话界面的组件,其优势是支持各类嵌套方式,更符合您的定制化需求。 下面说明如何在 Activity 里以静态方式加载融云 Fragment.

配置布局文件

这是您的会话列表 Activity 对应的布局文件:conversationlist.xml。注意 android:name 固定为融云的 ConversationListFragment。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/conversationlist"
        android:name="io.rong.imkit.fragment.ConversationListFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>
新建 Activity
public class ConversationListActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.conversationlist); } } 
配置 intent-filter:

融云 SDK 是经过隐式调用的方式来实现界面跳转的。所以您须要在 AndroidManifest.xml 中,您的会话列表 Activity 下面配置 intent-filter,其中,android:host 是您应用的包名,须要手动修改,其余请保持不变。

<!--会话列表-->
<activity
    android:name="io.rong.fast.activity.ConversationListActivity"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateHidden|adjustResize">

    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />

        <data
            android:host="io.rong.fast"
            android:pathPrefix="/conversationlist"
            android:scheme="rong" />
    </intent-filter>
</activity>

配置聚合会话列表

融云支持在会话列表页面自定义某种类型的会话以聚合形式展现,好比,定义全部私聊会话聚合显示,则在会话列表页全部私聊会话聚合显示为“个人私人会话”,点击“个人私人会话”,会进入全部私聊会话的展现页面,这个页面即为聚合会话列表,如图:

image
聚合会话列表

若是您的应用定义了聚合会话,请按照下面的说明进行相应配置,不然能够直接跳过此步骤。

自定义聚合会话列表请参考会话列表自定义

配置布局文件

这是您的聚合会话列表 Activity 对应的布局文件:subconversationlist.xml。 注意 android:name 固定为融云的 SubConversationListFragment。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <fragment
        android:id="@+id/subconversationlist"
        android:name="io.rong.imkit.fragment.SubConversationListFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

新建 Activity :

public class SubConversationListActivtiy extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.subconversationlist); } } 

配置 intent-filter

在 AndroidManifest.xml 中, 聚合会话 Activity 下面配置 intent-filter。 注意请修改 android:host 为您应用的包名,其余保持不变。

<!--聚合会话列表-->
 <activity
     android:name="io.rong.fast.activity.SubConversationListActivtiy"
     android:screenOrientation="portrait"
     android:windowSoftInputMode="stateHidden|adjustResize">

     <intent-filter>
         <action android:name="android.intent.action.VIEW" />

         <category android:name="android.intent.category.DEFAULT" />

         <data
             android:host="io.rong.fast"
             android:pathPrefix="/subconversationlist"
             android:scheme="rong" />
     </intent-filter>
 </activity>

配置会话界面

会话 Fragment 跟会话列表是彻底一致的,您能够用一样的方式快速的配置好。

配置布局文件

这是您的会话 Activity 对应的布局文件 conversation.xml,注意 android:name 固定为融云的 ConversationFragment。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <fragment
        android:id="@+id/conversation"
        android:name="io.rong.imkit.fragment.ConversationFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>
新建 Activity
public class ConversationActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.conversation); } } 
配置 intent-filter

在 AndroidManifest.xml 中,会话 Activity 下面配置 intent-filter。 注意请修改 android:host 为您应用的包名,其余保持不变。

<!--会话界面-->
 <activity
     android:name="io.rong.fast.activity.ConversationActivity"
     android:screenOrientation="portrait"
     android:windowSoftInputMode="stateHidden|adjustResize">

     <intent-filter>
         <action android:name="android.intent.action.VIEW" />

         <category android:name="android.intent.category.DEFAULT" />

         <data
             android:host="io.rong.fast"
             android:pathPrefix="/conversation/"
             android:scheme="rong" />
     </intent-filter>
 </activity>

会话列表及界面实现的视频教程

视频讲解会话界面、会话列表的配置以及 Fragment 的嵌套和 ViewPager+Fragment 的使用。

 
注:在按钮点击事件下可经过调用  RongIM.getInstance().startConversationList(); 去唤起会话列表。

会话界面 Title 配置的视频教程

此视频讲解了会话界面的 Title 如何编写,以及怎样经过 intent 的方式拿到 targetId 、昵称、会话类型等。

 

启动界面

完成以上配置后,便可启动会话及会话列表界面,启动界面操做必须在执行初始化 SDK 方法 init 及链接融云服务器 connect 以后进行,示例以下:

/** * <p>启动会话界面。</p> * <p>使用时,能够传入多种会话类型 {@link io.rong.imlib.model.Conversation.ConversationType} 对应不一样的会话类型,开启不一样的会话界面。 * 若是传入的是 {@link io.rong.imlib.model.Conversation.ConversationType#CHATROOM},sdk 会默认调用 * {@link RongIMClient#joinChatRoom(String, int, RongIMClient.OperationCallback)} 加入聊天室。 * 若是你的逻辑是,只容许加入已存在的聊天室,请使用接口 {@link #startChatRoomChat(Context, String, boolean)} 而且第三个参数为 true</p> * * @param context 应用上下文。 * @param conversationType 会话类型。 * @param targetId 根据不一样的 conversationType,多是用户 Id、讨论组 Id、群组 Id 或聊天室 Id。 * @param title 聊天的标题,开发者能够在聊天界面经过 intent.getData().getQueryParameter("title") 获取该值, 再手动设置为标题。 */ public void startConversation(Context context, Conversation.ConversationType conversationType, String targetId, String title) /** * 启动会话列表界面。 * * @param context 应用上下文。 * @param supportedConversation 定义会话列表支持显示的会话类型,及对应的会话类型是否聚合显示。 * 例如:supportedConversation.put(Conversation.ConversationType.PRIVATE.getName(), false) 非聚合式显示 private 类型的会话。 */ public void startConversationList(Context context, Map<String, Boolean> supportedConversation) /** * 启动聚合后的某类型的会话列表。<br> 例如:若是设置了单聊会话为聚合,则经过该方法能够打开包含全部的单聊会话的列表。 * * @param context 应用上下文。 * @param conversationType 会话类型。 */ public void startSubConversationList(Context context, Conversation.ConversationType conversationType) 

自定义广播接收器

当您的应用处于后台运行或者和融云服务器 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 的集成。

您也能够参考下面的快速集成 Demo 来快速集成融云 SDK。 Android Studio 快速集成

用户信息

功能说明

设计原理说明:

融云认为,每个设计良好且功能健全的 App 都应该可以在本地获取、缓存并更新用户信息。因此,融云不维护用户基本信息(用户 Id昵称头像)。此外,App 提供用户信息也避免了因为缓存致使的用户信息更新不及时,App 中不一样界面上的用户信息不统一(好比:一部分 App 从 App 服务器上获取并显示,一部分由融云服务器获取并显示),可以得到最佳的用户体验。

融云提供了两种方式从 App 的数据源显示用户昵称和头像

请不要两种方式都实现,根据实际需求选取其中一种方式实现便可。

一、设置用户信息提供者:

调用 RongIM.setUserInfoProvider 方法设置 UserInfoProvider。用户信息提供者采用 Provider 模式,即您提供给融云的 IMKit 一个 UserInfoProvider,当融云的 IMKit 须要使用用户信息的时候,调用您传入的 UserInfoProvider.getUserInfo 方法,向您获取用户信息。因此您在 UserInfoProvider.getUserInfo 方法中,须要根据传入的 userId 参数,向咱们返回对应的用户信息。

/** * 设置用户信息的提供者,供 RongIM 调用获取用户名称和头像信息。 * * @param userInfoProvider 用户信息提供者。 * @param isCacheUserInfo 设置是否由 IMKit 来缓存用户信息。<br> * 若是 App 提供的 UserInfoProvider * 每次都须要经过网络请求用户数据,而不是将用户数据缓存到本地内存,会影响用户信息的加载速度;<br> * 此时最好将本参数设置为 true,由 IMKit 将用户信息缓存到本地内存中。 * @see UserInfoProvider */ RongIM.setUserInfoProvider(new RongIM.UserInfoProvider() { @Override public UserInfo getUserInfo(String userId) { return findUserById(userId);//根据 userId 去你的用户系统里查询对应的用户信息返回给融云 SDK。 } }, true); 
API 文档连接: RongIM. setUserInfoProvider

不少时候 getUserInfo 这个方法会去 App 服务器异步获取用户信息,不能实时返回用户信息。这种状况下,请在成功获取到用户信息的异步回调中使用下面方法来刷新信息。

刷新用户信息:

/** * 刷新用户缓存数据。 * * @param userInfo 须要更新的用户缓存数据。 */ RongIM.getInstance().refreshUserInfoCache(new UserInfo("userId", "啊明", Uri.parse("http://rongcloud-web.qiniudn.com/docs_demo_rongcloud_logo.png"))); 

刷新群组信息

/** * 刷新群组缓存数据。 * * @param group 须要更新的群组缓存数据。 */ public void refreshGroupInfoCache(Group group) 

刷新讨论组信息

/** * 刷新讨论组缓存数据,可用于讨论组修更名称后刷新讨论组内其余人员的缓存数据。 * * @param discussion 须要更新的讨论组缓存数据。 */ public void refreshDiscussionCache(Discussion discussion) 

二、使用消息携带用户信息

当 App 自己没有用户系统或者由于某些缘由不方便使用上述用户信息提供者的时候,可使用消息携带用户信息来发送给消息接收方。

请注意这种方式不要和用户信息提供者混用。而且,这种方式会在每条发送的消息里都携带当前登录用户的信息,增长消息的长度。

首先,须要使用 setCurrentUserInfo 方法来设置当前的用户信息。

/** * 设置当前用户信息, * * @param userInfo 当前用户信息 */ RongIM.getInstance().setCurrentUserInfo(userInfo); 

接下来,在 init 以后调用下面方法设置消息携带用户信息。

/** * 设置消息体内是否携带用户信息。 * * @param state 是否携带用户信息,true 携带,false 不携带。 */ RongIM.getInstance().setMessageAttachedUserInfo(true); 

接收方在接收到消息后,SDK 会自动从消息中取出用户信息,并显示到 UI 上。

使用这种方式跟 iOS 互通时,须要 iOS 侧也在消息里携带用户信息,这样才能在两侧都正常显示昵称和头像。

常见问题:

实现教程

如下视频主要讲解融云 IMKit 中用户信息的实现包括头像及昵称。

 
功能代码示例,请参考 设置用户信息提供者 Demo

基础功能

单聊

单聊是最基本的聊天界面,提供文字、表情、语音片断、图片、VoIP 等多种输入内容,解决 App 内用户的沟通瓶颈。会话关系由融云负责创建并保持,退出聊天界面或者离线后能够收到推送通知。

前提条件:

  1. RongIM.init(this),接口已经执行。
  2. RongIM.connect(....),接口已经执行且 onSuccess() 被回调。
  3. 会话 Activity 已经在 AndroidManifest.xml 文件中,配置了对应的 intent-filter,详见配置说明文档

打开单聊窗口:

/** * 启动单聊界面。 * * @param context 应用上下文。 * @param targetUserId 要与之聊天的用户 Id。 * @param title 聊天的标题,开发者须要在聊天界面经过 intent.getData().getQueryParameter("title") * 获取该值, 再手动设置为聊天界面的标题。 */ RongIM.getInstance().startPrivateChat(getActivity(), "9527", "标题"); 
API 文档连接: RongIM. getInstance(). startPrivateChat

常见问题:

讨论组

讨论组业务的描述,请参见新手指南中的说明。

前提条件:

  • RongIM.init(this),接口已经执行。
  • RongIM.connect(....),接口已经执行且 onSuccess() 被回调。
  • 会话 Activity 已经在 AndroidManifest.xml 文件中,配置了对应的 intent-filter,详见配置说明文档

打开讨论组聊天窗口:

/** * 启动已经建立的讨论组聊天界面。 * * @param context 应用上下文。 * @param targetDiscussionId 要启动的讨论组 Id。 * @param title 聊天的标题,开发者能够在聊天界面经过 intent.getData().getQueryParameter("title") 获取该值, 再手动设置为标题。 */ RongIM.getInstance().startDiscussionChat(getActivity(), "9527", "标题"); 

建立讨论组会话并进入会话界面:

/** * 建立讨论组会话并进入会话界面。 * 讨论组建立成功后,会返回讨论组 id。 * * @param context 应用上下文。 * @param targetUserIds 要与之聊天的讨论组用户 Id 列表。 * @param title 聊天的标题,若是传入空值,则默认显示与之聊天的用户名称。 * @param callback 讨论组回调,成功时,返回讨论组 id。 */ public void createDiscussionChat(final Context context, final List<String> targetUserIds, final String title, final RongIMClient.CreateDiscussionCallback callback) {}) 

建立讨论组

/** * 建立讨论组。 * * @param name 讨论组名称,如:当前全部成员的名字的组合。 * @param userIdList 讨论组成员 Id 列表。 * @param callback 建立讨论组成功后的回调。 */ public void createDiscussion(final String name, final List<String> userIdList, final RongIMClient.CreateDiscussionCallback callback) 

添加讨论组成员:

同一个用户最多可加入 500 个讨论组。

ArrayList<String> userIds = new ArrayList<String>(); userIds.add("101");//增长 userId。 userIds.add("102");//增长 userId。 userIds.add("103");//增长 userId。 /** * 添加一名或者一组用户加入讨论组。 * * @param discussionId 讨论组 Id。 * @param userIdList 邀请的用户 Id 列表。 * @param callback 执行操做的回调。 */ RongIM.getInstance().addMemberToDiscussion("9527", userIds, new RongIMClient.OperationCallback() { @Override public void onSuccess() { } @Override public void onError(RongIMClient.ErrorCode errorCode) { } }); 

移除讨论组成员:

/** * 供建立者将某用户移出讨论组。 * * 移出本身或者调用者非讨论组建立者将产生 {@link RongIMClient.ErrorCode#UNKNOWN} 错误。 * * @param discussionId 讨论组 Id。 * @param userId 用户 Id。 * @param callback 执行操做的回调。 */ RongIM.getInstance().removeMemberFromDiscussion("discussionId_9527", "user_9527", new RongIMClient.OperationCallback() { @Override public void onSuccess() { } @Override public void onError(RongIMClient.ErrorCode errorCode) { } }); 

讨论组人数上限设置:

讨论组人数在服务端有上限限制,为 500 人,客户端根据具体的业务需求,能够经过配置文件配置讨论组人数上限,请在 res/values/rc_config.xml 文件中修改, xml 文件以下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer name="discussion_member_max_count">50</integer>
</resources>

群组

群组业务的描述,请参见新手指南中的说明。

群组信息与群成员信息是由 App 自已提供并进行维护管理,融云只是同步群组关系数据,并不保存群组的具体信息,融云会根据开发者同步的群组数据,计算群组的成员信息并群发消息。因此,当界面组件建立会话须要显示群组信息时,须要向 App 获取。App 须要设置一个群组信息提供者给 IMKit,以便 IMKit 读取好友关系。

只有您使用融云 IMKit 提供的群组功能时,才须要设置群组信息提供者。若是您没有使用群组功能,则不须要设置群组信息提供者。提供的群组功能以下:

前提条件:

  1. RongIM.init(this),接口已经执行。
  2. RongIM.connect(....),接口已经执行且 onSuccess() 被回调。
  3. 会话 Activity 已经在 AndroidManifest.xml 文件中,配置了对应的 intent-filter,详见配置说明文档

启动群组聊天界面:

/** * 启动群组聊天界面。 * * @param context 应用上下文。 * @param targetGroupId 要聊天的群组 Id。 * @param title 聊天的标题,开发者能够在聊天界面经过 intent.getData().getQueryParameter("title") 获取该值, 再手动设置为标题。 */ RongIM.getInstance().startGroupChat(getActivity(), "9527", "标题"); 
API 文档连接: RongIM. getInstance(). startGroupChat

客户端的全部群组操做都须要请求您的 App Server, 您的 App Server 能够根据本身的逻辑进行管理和控制,而后经过 Server API 接口进行群组操做,并将结果返回给客户端。

详请见 Server API 群组服务接口

如下展现了客户端进行群组操做的流程:

建立群组

加入群组

退出群组

解散群组

设置群组信息

获取群组成员列表

获取群组列表

聊天室

聊天室业务的描述,请参见新手指南中的说明。

聊天室与群组最大的不一样在于,聊天室的消息没有 Push 通知,也没有成员的概念。想参与聊天室聊天,接收聊天室消息,加入聊天室便可;不参与聊天室聊天,不接收消息,退出聊天室便可。IMKit 组件中已经内置了加入和退出聊天室的接口调用,您直接启动便可:

前提条件:

  1. RongIM.init(this),接口已经执行。
  2. RongIM.connect(....),接口已经执行且 onSuccess() 被回调。
  3. 会话 Activity 已经在 AndroidManifest.xml 文件中,配置了对应的 intent-filter,详见配置说明文档

启动聊天室界面:

/** * <p>启动聊天室会话。</p> * <p>设置参数 createIfNotExist 为 true,对应到 kit 中调用的接口是 * {@link RongIMClient#joinChatRoom(String, int, RongIMClient.OperationCallback)}. * 若是聊天室不存在,则自动建立并加入,若是回调失败,则弹出 warning。</p> * <p>设置参数 createIfNotExist 为 false,对应到 kit 中调用的接口是 * {@link RongIMClient#joinExistChatRoom(String, int, RongIMClient.OperationCallback)}. * 若是聊天室不存在,则返回错误 {@link io.rong.imlib.RongIMClient.ErrorCode#RC_CHATROOM_NOT_EXIST},而且会话界面会弹出 warning. * </p> * * @param context 应用上下文。 * @param chatRoomId 聊天室 id。 * @param createIfNotExist 若是聊天室不存在,是否建立。 */ public void startChatRoomChat(Context context, String chatRoomId, boolean createIfNotExist); 

加入聊天室

加入聊天室,若是聊天室不存在,则建立聊天室并加入;若是已经存在,则直接加入。

/** * 加入聊天室。 * <p>若是聊天室不存在,sdk 会建立聊天室并加入,若是已存在,则直接加入</p> * <p>加入聊天室时,能够选择拉取聊天室消息数目。</p> * * @param chatroomId 聊天室 Id。 * @param defMessageCount 进入聊天室拉取消息数目,-1 时不拉取任何消息,0 时拉取 10 条消息,最多只能拉取 50 条。 * @param callback 状态回调。 */ public void joinChatRoom(final String chatroomId, final int defMessageCount, final RongIMClient.OperationCallback callback) 

加入已经存在的聊天室

/** * 加入已存在的聊天室。 * <p>若是聊天室不存在,则加入失败</p> * <p>加入聊天室时,能够选择拉取聊天室消息数目。</p> * * @param chatroomId 聊天室 Id。 * @param defMessageCount 进入聊天室拉取消息数目,-1 时不拉取任何消息,0 时拉取 10 条消息,最多只能拉取 50 条。 * @param callback 状态回调。 */ public void joinExistChatRoom(final String chatroomId, final int defMessageCount, final RongIMClient.OperationCallback callback) 

聊天室拉取消息数设置:

进入聊天室时默认拉取消息数为 10 条,根据需求可经过配置文件修改拉取消息条数,建议拉取消息数不超过 50 条,请在 res/values/rc_config.xml 文件中修改,为 -1 表示不获取任何历史消息,0 表示不特殊设置而使用 SDK 默认的设置(默认为获取10条),最大值为50。 xml 文件以下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <integer name="rc_chatroom_first_pull_message_count">10</integer>
</resources>
如您在使用 IMLib 开发时注意,因聊天室没有成员关系,须要在每次显示聊天室聊天界面以前,执行加入聊天室的操做,并在退出聊天室聊天界面以后执行退出聊天室的操做。不然,您的 App 将消耗没必要要的流量(不退出聊天室将会持续接收来自该聊天室的消息)。

系统会话

前提条件:

  1. RongIM.init(this),接口已经执行。
  2. RongIM.connect(....),接口已经执行且 onSuccess() 被回调。
  3. 会话 Activity 已经在 AndroidManifest.xml 文件中,配置了对应的 intent-filter,详见配置说明文档

打开系统会话聊天界面:

/** * 启动系统会话聊天界面。 * * @param context 应用上下文。 * @param conversationType 开启会话类型。 * @param targetId 目标 Id; * @param title 聊天的标题,开发者能够在聊天界面经过 intent.getData().getQueryParameter("title") 获取该值, 再手动设置为标题。 */ RongIM.getInstance().startConversation(getActivity(), Conversation.ConversationType.SYSTEM, "9527", "标题"); 
API 文档连接: RongIM. getInstance(). startConversation
系统会话消息由应用服务端发送,客户端只能接收消息,不能进行回复。

客服

IMKit 中提供封装好的客服功能和 UI 界面,轻松的几行代码就能完成集成,为应用中用户提供优质的客服服务。

前提条件:

  1. RongIM.init(this),接口已经执行。
  2. RongIM.connect(....),接口已经执行且 onSuccess() 被回调。
  3. 会话 Activity 已经在 AndroidManifest.xml 文件中,配置了对应的 intent-filter,详见配置说明文档
  4. 已在 融云开发者平台 开启客服服务,并获取 客服 ID
开发者后台客服使用说明,详细请参见 客服使用文档

打开客服聊天界面:

//首先须要构造使用客服者的用户信息 CSCustomServiceInfo.Builder csBuilder = new CSCustomServiceInfo.Builder(); CSCustomServiceInfo csInfo = csBuilder.nickName("融云").build(); /** * 启动客户服聊天界面。 * * @param context 应用上下文。 * @param customerServiceId 要与之聊天的客服 Id。 * @param title 聊天的标题,开发者能够在聊天界面经过 intent.getData().getQueryParameter("title") 获取该值, 再手动设置为标题。 * @param customServiceInfo 当前使用客服者的用户信息。{@link io.rong.imlib.model.CSCustomServiceInfo} */ RongIM.getInstance().startCustomerServiceChat(getActivity(), id, "在线客服",csInfo); 

使用咱们的客服须要集成 ConversationFragment 到 Activity 中 ,当您退出这个 Activity 的时候调用以下代码:

@Override public void onBackPressed() { ConversationFragment fragment = (ConversationFragment) getSupportFragmentManager().findFragmentById(R.id.conversation); if(!fragment.onBackPressed()) { finish(); } } 

当触发 onKeyDown 事件的时候,作如下处理:

@Override public boolean onKeyDown(int keyCode, KeyEvent event) { return super.onKeyDown(keyCode, event); } 

目的就是为了让咱们的 ConversationFragment 捕捉到 back 事件,而后弹出 Dialog

退出客服界面是否关闭客服设置

在 rc_config.xml 配置文件中,设置退出客服界面后是否关闭客服功能,默认为 true 退出后关闭客服不接收客服消息,为 false 时退出客服界面后不关闭客服,还能正常接收客服消息。

<resources>
    <!-- 退出客服页面是否关闭客服 -->
    <bool name="rc_stop_custom_service_when_quit">true</bool>
</resources>

客服界面提示窗自定义

客服界面的提示窗口,首先集成一个自定义的类继承自 ConversationFragment, 而后在自定义类中重写 onCustomServiceWarning() 方法,以下图:

image

机器人模式的评价和人工模式的评价,能够经过在自定义类中重写 onCustomServiceEvaluation() 方法来自定义,以下图:

image

公众号

融云公众服务是为应用开发者和公众账号运营者提供的链接服务产品,经过融云公众服务,App 能够具有为本身的用户提供公众账号服务的能力和资源。

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

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

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

开发者可在 融云开发者平台 的公众服务模块中,经过添加公众服务应用公众服务中的公众号到自已的应用中。

IMKit 组件中已经内置了订阅和取消订阅公众号的接口调用,您直接启动便可:

前提条件:

  1. RongIM.init(this),接口已经执行。
  2. RongIM.connect(....),接口已经执行且 onSuccess() 被回调。
  3. 会话 Activity 已经在 AndroidManifest.xml 文件中,配置了对应的 intent-filter,详见配置说明文档

打开应用公众服务会话界面:

/** * 启动应用公众服务会话界面。 * * @param context 应用上下文。 * @param conversationType 开启会话类型。 * @param targetId 目标 Id。 * @param title 聊天的标题,开发者能够在聊天界面经过 intent.getData().getQueryParameter("title") 获取该值, 再手动设置为标题。 */ RongIM.getInstance().startConversation(getActivity(), Conversation.ConversationType.APP_PUBLIC_SERVICE, "9527", "公众账号标题"); 
API 文档连接: RongIM. getInstance(). startConversation

打开公众服务号会话界面:

/** * 启动公众服务号会话界面。 * * @param context 应用上下文。 * @param conversationType 开启会话类型。 * @param targetId 目标 Id。 * @param title 聊天的标题,开发者能够在聊天界面经过 intent.getData().getQueryParameter("title") 获取该值, 再手动设置为标题。 */ RongIM.getInstance().startConversation(getActivity(), Conversation.ConversationType.PUBLIC_SERVICE, "9527", "公众账号标题"); 
API 文档连接: RongIM. getInstance(). startConversation

打开应用公众服务信息界面:

/** * 启动应用公众服务信息界面。 * * @param context 应用上下文。 * @param conversationType 会话类型。 * @param targetId 目标 Id。 */ RongIM.getInstance().startPublicServiceProfile(getActivity(), Conversation.ConversationType.APP_PUBLIC_SERVICE, "9527"); 

打开公共服务号信息界面:

/** * 启动公共服务号信息界面。 * * @param context 应用上下文。 * @param conversationType 会话类型。 * @param targetId 目标 Id。 */ RongIM.getInstance().startPublicServiceProfile(getActivity(), Conversation.ConversationType.PUBLIC_SERVICE, "9527"); 

搜索公众号

经过 searchPublicService 或 searchPublicServiceByType 方法搜索已经添加的公众号列表,能够按关键字精确匹配或模糊匹配方式进行搜索。

/** * 搜索所有公众服务。 * * @param searchType 搜索类型枚举。 * @param keywords 搜索关键字。 */ RongIM.getInstance().searchPublicService(RongIMClient.SearchType.EXACT, keywords, new RongIMClient.SearchPublicServiceCallback() { @Override public void onError(RongIMClient.ErrorCode e) { //错误回调处理 } @Override public void onSuccess(PublicServiceProfileList publicServiceProfileList) { //成功回调处理 } }); /** * 按公众服务类型搜索公众服务。 * * @param conversationType 会话类型。 * @param searchType 搜索类型枚举。 * @param keywords 搜索关键字。 */ RongIM.getInstance().searchPublicServicebyType(Conversation.PublicServiceType.PUBLIC_SERVICE, RongIMClient.SearchType.EXACT, keywords, new RongIMClient.SearchPublicServiceCallback() { @Override public void onError(RongIMClient.ErrorCode e) { //错误回调处理 } @Override public void onSuccess(PublicServiceProfileList publicServiceProfileList) { //成功回调处理 } }); 

获取己关注公共帐号列表:

在应用中须要展现已关注公共帐号列表时,可经过 getPublicServiceList 方法获取己关注公共帐号列表信息。

RongIM.getInstance().getPublicServiceList(new RongIMClient.SearchPublicServiceCallback() { @Override public void onSuccess(PublicServiceProfileList publicServiceProfileList) { //成功回调处理 } @Override public void onError(RongIMClient.ErrorCode e) { //错误回调处理 } }); 

获取某公众号信息

/** * 按公众服务类型搜索公众服务。 * * @param publicServiceType 公众服务类型。 * @param publicServiceId 公众号 Id。 */ RongIM.getInstance().getPublicServiceProfile(Conversation.PublicServiceType.PUBLIC_SERVICE, publicServiceId, new RongIMClient.ResultCallback<PublicServiceProfile>() { @Override public void onSuccess(PublicServiceProfile profile) { //成功后返回公众号信息 } @Override public void onError(RongIMClient.ErrorCode e) { //错误回调处理 } }); 

消息发送

文本消息发送

发送文本消息以下:

// 构造 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}。 */ RongIM.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:// 其余暂不支持。</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}。 */ public void sendLocationMessage(Message message, String pushContent, final String pushData, final IRongCallback.ISendMessageCallback sendMessageCallback) 

融云 SDK 默认使用的是高德地图,您也能够基于其它第三方实现位置功能,请参考基于百度地图实现融云 SDK 文档

图片消息发送

默认图片消息发送

获取 ImageMessage 实例

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

发送图片消息

/** * <p>根据会话类型,发送图片消息。</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 发送消息的回调。 */ RongIM.getInstance().sendImageMessage(Conversation.ConversationType.PRIVATE, "9517", imgMsg, null, null, 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) { //发送进度 } }); 

上面的方法是 SDK 默认发送图片的方法,图片会存储到七牛,默认保存一个月。

发送图片消息而且上传到本身的服务器

构造消息实例

ImageMessage imageMessage = ImageMessage.obtain(thumbPathUri, localPathUri);
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)} */ RongIM.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) { //发送进度 } }); 
注:图片消息包括两个主要部分:缩略图和大图,缩略图直接 Base64 编码后放入  content 中,大图首先上传到文件服务器(融云 SDK 中默认上传到七牛云存储, 图片有效期为 1 个月。),而后将云存储上的大图地址放入消息体中。

图片缩略图机制:

缩略图尺寸为:240 x 240 像素,以宽度和高度中较长的边不超过 240 像素等比压缩。

大图尺寸为:960 x 960 像素,以宽度和高度中较长的边不超过 960 像素等比压缩。

语音消息发送

基本原理:录制语音,本地存储转换为 AMR 格式,获取语音时长,构造语音消息并发送。

/** * 获取语音消息实体。 * * @param Uri 语音 Uri 。 * @param duration 语音时长(单位:秒)。 */ VoiceMessage vocMsg = VoiceMessage.obtain(Uri.fromFile(voiceFile), 10); /** * <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}。 */ RongIM.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) { //消息发送失败的回调 } }); 
注:语音消息默认的码率为 7950 bps, 您也能够经过更改资源文件 rc_configuration.xml 里 rc_audio_encoding_bit_rate 字段的值, 来自定义语音消息的码率。

图文消息发送

生成图文消息实例:

/** * 生成RichContentMessage对象。 * * @param title 消息标题。 * @param content 消息内容。 * @param imageUrl 消息图片url. * @return 生成RichContentMessage对象。 */ public static RichContentMessage obtain(String title, String content, String imageUrl) 

发送消息

RichContentMessage richContentMessage = RichContentMessage.obtain("标题", "内容", "http://rongcloud.cn/images/logo.png"); //"9517" 为目标 Id。根据不一样的 conversationType,多是用户 Id、讨论组 Id、群组 Id 或聊天室 Id。 //Conversation.ConversationType.PRIVATE 为会话类型。 Message myMessage = Message.obtain("9517", Conversation.ConversationType.PRIVATE, richContentMessage); /** * <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}。 */ RongIM.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) { //消息发送失败的回调 } }); 

文件消息发送

融云 SDK 默认支持文件发送功能,点击查看文件消息产品介绍

注: 融云 SDK 默认实现了文件管理器功能,若是您想自定义文件管理器,能够经过自定义会话扩展区的方式来自定义文件管理器。

1. 自定义文件保存位置

接受到文件消息,并点击下载后,该文件默认保存在 SD 卡的 /RongCloud/Media/ 下。

您能够经过更改 SDK 的 res/values/rc_configuration.xml 里面的 rc_media_message_default_save_path 的值,来自定义文件的存储路径。

2. 文件消息相关功能说明

发送文件消息

/** * <p>发送多媒体消息</p> * <p>发送前构造 {@link Message} 消息实体</p> * @param message 发送消息的实体。 * @param pushContent 当下发 push 消息时,在通知栏里会显示这个字段。 * 发送文件消息时,此字段必须填写,不然会收不到 push 推送。 * @param pushData push 附加信息。若是设置该字段,用户在收到 push 消息时,能经过 {@link io.rong.push.notification.PushNotificationMessage#getPushData()} 方法获取。 * @param callback 发送消息的回调 {@link io.rong.imlib.RongIMClient.SendMediaMessageCallback}。 */ public void sendMediaMessage(Message message, String pushContent, final String pushData, final IRongCallback.ISendMediaMessageCallback callback) 

下载文件消息

/** * 下载多媒体消息。 * 用来获取媒体原文件时调用。若是本地缓存中包含此文件,则从本地缓存中直接获取,不然将从服务器端下载。 * * @param message 文件消息。 * @param callback 下载文件的回调。 */ public void downloadMediaMessage(Message message, final IRongCallback.IDownloadMediaMessageCallback callback) 

取消文件下载

/** * 取消多媒体消息下载。 * @param message 包含多媒体文件的消息, * @param callback 取消下载多媒体文件时的回调。 * */ public void cancelDownloadMediaMessage(Message message, RongIMClient.OperationCallback callback) 

若是您使用的是 IMLib SDK 集成,可参考 IMLib 文件消息文档

消息推送

融云推送服务及集成第三方推送服务,详细请查看推送服务开发指南

事件监听

获取发出消息监听器

设置本身发出消息的监听器,在 init() 以后便可设置。

注意:若是在 Activity 里设置,须要在 Activity 销毁时,将监听设置为 null,防止内存泄露。

/** * 设置发送消息的监听。 * * @param listener 发送消息的监听。 */ public void setSendMessageListener(OnSendMessageListener listener) 

设置后实现消息发送监听接口 OnSendMessageListener ,消息发送失败可在 onSent 方法中根据 SentMessageErrorCode 返回的状态码实现自已的逻辑处理。onSent 返回 true 表示走自已的处理方式,不然走融云默认处理方式。

RongIM.getInstance().setSendMessageListener(new MySendMessageListener()); private class MySendMessageListener implements RongIM.OnSendMessageListener { /** * 消息发送前监听器处理接口(是否发送成功能够从 SentStatus 属性获取)。 * * @param message 发送的消息实例。 * @return 处理后的消息实例。 */ @Override public Message onSend(Message message) { //开发者根据本身需求自行处理逻辑 return message; } /** * 消息在 UI 展现后执行/本身的消息发出后执行,不管成功或失败。 * * @param message 消息实例。 * @param sentMessageErrorCode 发送消息失败的状态码,消息发送成功 SentMessageErrorCode 为 null。 * @return true 表示走自已的处理方式,false 走融云默认处理方式。 */ @Override public boolean onSent(Message message,RongIM.SentMessageErrorCode sentMessageErrorCode) { if(message.getSentStatus()== Message.SentStatus.FAILED){ if(sentMessageErrorCode== RongIM.SentMessageErrorCode.NOT_IN_CHATROOM){ //不在聊天室 }else if(sentMessageErrorCode== RongIM.SentMessageErrorCode.NOT_IN_DISCUSSION){ //不在讨论组 }else if(sentMessageErrorCode== RongIM.SentMessageErrorCode.NOT_IN_GROUP){ //不在群组 }else if(sentMessageErrorCode== RongIM.SentMessageErrorCode.REJECTED_BY_BLACKLIST){ //你在他的黑名单中 } } MessageContent messageContent = message.getContent(); if (messageContent instanceof TextMessage) {//文本消息 TextMessage textMessage = (TextMessage) messageContent; Log.d(TAG, "onSent-TextMessage:" + textMessage.getContent()); } else if (messageContent instanceof ImageMessage) {//图片消息 ImageMessage imageMessage = (ImageMessage) messageContent; Log.d(TAG, "onSent-ImageMessage:" + imageMessage.getRemoteUri()); } else if (messageContent instanceof VoiceMessage) {//语音消息 VoiceMessage voiceMessage = (VoiceMessage) messageContent; Log.d(TAG, "onSent-voiceMessage:" + voiceMessage.getUri().toString()); } else if (messageContent instanceof RichContentMessage) {//图文消息 RichContentMessage richContentMessage = (RichContentMessage) messageContent; Log.d(TAG, "onSent-RichContentMessage:" + richContentMessage.getContent()); } else { Log.d(TAG, "onSent-其余消息,本身来判断处理"); } return false; } } 

接收消息监听

接收消息的监听器,在 init() 以后便可设置。注意,建议设置在 Application 里面,这样才能在整个应用的生命周期,都能监听到接收消息事件。

/** * 设置接收消息的监听器。 * <p/> * 全部接收到的消息、通知、状态都经由此处设置的监听器处理。包括私聊消息、讨论组消息、群组消息、聊天室消息以及各类状态。 * * @param listener 接收消息的监听器。 */ public static void setOnReceiveMessageListener(RongIMClient.OnReceiveMessageListener listener) 
API 文档连接: RongIM. setOnReceiveMessageListener

接收消息监听器的实现,全部接收到的消息、通知、状态都经由此处设置的监听器处理。包括私聊消息、讨论组消息、群组消息、聊天室消息以及各类状态。

RongIM.setOnReceiveMessageListener(new MyReceiveMessageListener()); private class MyReceiveMessageListener implements RongIMClient.OnReceiveMessageListener { /** * 收到消息的处理。 * * @param message 收到的消息实体。 * @param left 剩余未拉取消息数目。 * @return 收到消息是否处理完成,true 表示本身处理铃声和后台通知,false 走融云默认处理方式。 */ @Override public boolean onReceived(Message message, int left) { //开发者根据本身需求自行处理 return false; } } 

Push 消息监听

您能够在自定义的继承融云 PushMessageReceiver 的广播接收器里面监听到 push 事件。

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

关于融云推送的详细机制和功能,您能够参考推送服务开发指南

链接状态监听

设置链接状态监听,必须在 init 后进行调用。 注意:建议设置在 Application 里面,这样才能在整个应用的生命周期,都能监听到状态变化。

/** * 设置链接状态变化的监听器。 * * @param listener 链接状态变化的监听器。 */ public static void setConnectionStatusListener(final RongIMClient.ConnectionStatusListener listener) 

实现链接状态监听器,以获取当前链接相关状态。

RongIM.setConnectionStatusListener(new MyConnectionStatusListener()); private class MyConnectionStatusListener implements RongIMClient.ConnectionStatusListener { @Override public void onChanged(ConnectionStatus connectionStatus) { switch (connectionStatus){ case CONNECTED://链接成功。 break; case DISCONNECTED://断开链接。 break; case CONNECTING://链接中。 break; case NETWORK_UNAVAILABLE://网络不可用。 break; case KICKED_OFFLINE_BY_OTHER_CLIENT://用户帐户在其余设备登陆,本机会被踢掉线 break; } } } 

会话列表操做监听

会话列表操做监听,在调用 init 以后便可进行设置。

/** * 设置会话列表界面操做的监听器。 */ RongIM.setConversationListBehaviorListener(new MyConversationListBehaviorListener()); 

实现会话列表操做监听接口 ConversationListBehaviorListener 。

private class MyConversationListBehaviorListener implements RongIM.ConversationListBehaviorListener{ /** * 当点击会话头像后执行。 * * @param context 上下文。 * @param conversationType 会话类型。 * @param targetId 被点击的用户id。 * @return 若是用户本身处理了点击后的逻辑处理,则返回 true,不然返回 false,false 走融云默认处理方式。 */ boolean onConversationPortraitClick(Context context, Conversation.ConversationType conversationType, String targetId){ } /** * 当长按会话头像后执行。 * * @param context 上下文。 * @param conversationType 会话类型。 * @param targetId 被点击的用户id。 * @return 若是用户本身处理了点击后的逻辑处理,则返回 true,不然返回 false,false 走融云默认处理方式。 */ boolean onConversationPortraitLongClick(Context context, Conversation.ConversationType conversationType, String targetId){ return false; } /** * 长按会话列表中的 item 时执行。 * * @param context 上下文。 * @param view 触发点击的 View。 * @param uiConversation 长按时的会话条目。 * @return 若是用户本身处理了长按会话后的逻辑处理,则返回 true, 不然返回 false,false 走融云默认处理方式。 */ @Override public boolean onConversationLongClick(Context context, View view, UIConversation uiConversation) { return false; } /** * 点击会话列表中的 item 时执行。 * * @param context 上下文。 * @param view 触发点击的 View。 * @param uiConversation 会话条目。 * @return 若是用户本身处理了点击会话后的逻辑处理,则返回 true, 不然返回 false,false 走融云默认处理方式。 */ @Override public boolean onConversationClick(Context context, View view, UIConversation uiConversation) { return false; } } 

会话界面操做的监听器

会话界面操做的监听器,在调用 init 后便可进行设置。

/** * 设置会话界面操做的监听器。 */ RongIM.setConversationBehaviorListener(new MyConversationBehaviorListener()); 

实现会话界面操做的监听接口 ConversationBehaviorListener 。会话界面中点击用户头像、长按用户头像、点击消息、长按消息的操做都在此处理。

private class MyConversationBehaviorListener implements RongIM.ConversationBehaviorListener{ /** * 当点击用户头像后执行。 * * @param context 上下文。 * @param conversationType 会话类型。 * @param userInfo 被点击的用户的信息。 * @return 若是用户本身处理了点击后的逻辑,则返回 true,不然返回 false,false 走融云默认处理方式。 */ @Override public boolean onUserPortraitClick(Context context, Conversation.ConversationType conversationType, UserInfo userInfo) { return false; } /** * 当长按用户头像后执行。 * * @param context 上下文。 * @param conversationType 会话类型。 * @param userInfo 被点击的用户的信息。 * @return 若是用户本身处理了点击后的逻辑,则返回 true,不然返回 false,false 走融云默认处理方式。 */ @Override public boolean onUserPortraitLongClick(Context context, Conversation.ConversationType conversationType, UserInfo userInfo) { return false; } /** * 当点击消息时执行。 * * @param context 上下文。 * @param view 触发点击的 View。 * @param message 被点击的消息的实体信息。 * @return 若是用户本身处理了点击后的逻辑,则返回 true, 不然返回 false, false 走融云默认处理方式。 */ @Override public boolean onMessageClick(Context context, View view, Message message) { return false; } /** * 当长按消息时执行。 * * @param context 上下文。 * @param view 触发点击的 View。 * @param message 被长按的消息的实体信息。 * @return 若是用户本身处理了长按后的逻辑,则返回 true,不然返回 false,false 走融云默认处理方式。 */ @Override public boolean onMessageLongClick(Context context, View view, Message message) { return false; } /** * 当点击连接消息时执行。 * * @param context 上下文。 * @param link 被点击的连接。 * @return 若是用户本身处理了点击后的逻辑处理,则返回 true, 不然返回 false, false 走融云默认处理方式。 */ @Override public boolean onMessageLinkClick(Context context, String link) { return false; } } 

未读消息数监听器

未读消息数监听器,必须在 init 以后便可调用。

/** * 设置未读消息数变化监听器。 * 注意:若是是在 activity 中设置,那么要在 activity 销毁时,调用 {@link #removeUnReadMessageCountChangedObserver(IUnReadMessageObserver)} * 不然会形成内存泄漏。 * * @param observer 接收未读消息消息的监听器。 * @param conversationTypes 接收未读消息的会话类型。 */ public void addUnReadMessageCountChangedObserver(final IUnReadMessageObserver observer, Conversation.ConversationType... conversationTypes) } 

Activity 销毁时,移除监听。

/** * 注销已注册的未读消息数变化监听器。 * * @param observer 接收未读消息消息的监听器。 */ public void removeUnReadMessageCountChangedObserver(final IUnReadMessageObserver observer) 

UI 自定义

会话列表自定义

会话列表相关布局文件

rc_fr_conversationlist.xml 会话列表布局文件

rc_item_conversation.xml 会话列表各个 item 对应的布局文件

能够经过修改这些布局文件修改背景或字体颜色等。

根据会话类型过滤显示的会话,以及配置是否聚合显示

能够根据会话类型,限制会话列表只显示某几个类型的会话,以及这些会话是否以聚合形式显示。

下面以自定义会话列表只显示单聊和群组会话为例,说明如何自定义:

a. 配置 Uri

image

b. 把自定义的 Uri 赋值给 ConversationListFragment

listFragment.setUri(uri);

头像位置自定义

对于会话列表中每种会话类型的会话,开发者均可以自定义头像位置的显示方式,显示方式有:靠左显示、靠右显示、不显示。

自定义步骤:

一、新建一类继承要改变的会话提供者类,而后重写注解,修改 portraitPosition 的值以完成显示方式。

  • 注解说明:

注解名称:ConversationProviderTag。属性:conversationType ,portraitPosition 。

conversationType 的值不能重复不可修改,它是会话提供者的惟一标识;portraitPosition 用来控制头像的显示方式,它的值能够修改,它的值有:1:靠左显示, 2:靠右显示, 3:不显示。

  • 模板说明:
提供者名称 类名 注解 conversationType 值
(不可修改)
注解 portraitPosition 
初始值 (可修改)
二人会话提供者 PrivateConversationProvider.java private 1
讨论组会话提供者 DiscussionConversationProvider.java discussion 1
群聊会话提供者 GroupConversationProvider.java group 1
客服会话提供者 CustomerServiceConversationProvider.java customer_service 1
系统会话提供者 SystemConversationProvider.java system 1
应用公众服务会话提供者 AppServiceConversationProvider.java app_public_service 1
公众服务平台会话提供者 PublicServiceConversationProvider.java public_service 1

二、从新注册该会话模板,注册方法应在 init 后调用

RongIM.getInstance().registerConversationTemplate;

自定义示例:

如何在会话列表中让所单聊会话头像都靠右显示?

第一步:

@ConversationProviderTag(conversationType = "private", portraitPosition = 2) public class MyPrivateConversationProvider extends PrivateConversationProvider { ... } 

第二步:

RongIM.getInstance().registerConversationTemplate(new MyPrivateConversationProvider()); 
注:在 init 后调用。

会话页面自定义

会话页面相关布局文件

rc_fr_conversation.xml 会话页面布局

rc_item_message.xml 消息列表单个 item 对应的布局

您能够经过修改上述布局文件来更改字体大小颜色及背景色等。

消息展现自定义

融云 IMKit SDK 中每一种消息类型(要在 UI 展现的)都对应一个 UI 展现的 Provider,开发者能够修改 Provider 的注解属性来完成消息显示的自定义。

自定义步骤:

一、新建一类并继承要修改的消息提供者类,而后重写注解。

  • 注解说明:

注解名称:ProviderTag。

注解属性:

属性 描述
messageContent    对应的消息类型 ( 如:TextMessage.class )。
showPortrait 设置是否显示头像,默认为 true。
centerInHorizontal 消息内容是否横向居中,默认 false。
hide 是否隐藏消息, 默认 false。
showProgress 是否显示发送进度,默认 true。
showSummaryWithName 是否在会话的内容体里显示发送者名字,默认 true。

自定义示例:

如何在会话中让 TextMessage 不显示头像且消息内容横向居中显示?

第一步:

自定义 TextMessage 的展现模板

@ProviderTag ( messageContent = TextMessage.class , showPortrait = false , centerInHorizontal = true ) public class MyTextMessageItemProvider extends TextMessageItemProvider {...} 

第二步:

从新注册该消息模板,注册方法应在 init 后调用

RongIM.getInstance().registerMessageTemplate(new MyTextMessageItemProvider()); 

未读消息数目和新消息提醒

未读消息数目和新消息气泡在 IMKit 中默认不显示,如须要显示新消息提醒和未读消息数目能够在链接成功后经过下面方法设置。

RongIM.getInstance().enableNewComingMessageIcon(true);//显示新消息提醒 RongIM.getInstance().enableUnreadMessageIcon(true);//显示未读消息数目 
image

新消息大于 1 条即展现,超过 99 条显示为 "99+",未读消息大于 10 条即展现,超过 150 条显示为 "150+条新消息"。另外,控件的样式能够在 layout/rc_fr_messagelist.xml 中进行调整。

适配器 adapter 自定义

能够经过自定义会话列表或者会话界面的适配器,来自定义界面的展现。

下面以自定义会话界面消息列表的适配器为例,说明如何自定义:

3.1 自定义会话 fragment 继承自 ConversationFragment,复写 onResolveAdapter() 方法,返回自定义的 adapter。

另外您的 activity 布局文件中也须要配置成自定义的 fragment。

image

3.2 自定义继承 MessageListAdapter 的消息列表适配器,根据须要复写其中的 newView() 或者 bindView() 方法

image

输入区域自定义

输入区域相关概念:

一、输入区域扩展栏对外接口类为 RongExtension。如图 1

二、Plugin 是开发者自定义 “+” 号区域展开后的 item,如图 1

image
图 1

三、EmoticonTab 是开发者自定义 表情 tab 页。如图 2

image
图 2

1、布局自定义

部分布局文件以下,您能够经过修改对应的布局文件来调整界面布局,修改背景,更改字体等。

一、rc_ext_extension_bar.xml 输入框布局文件。它是整个输入框的容器,内部有对各部分组件功能描述。

二、rc_ext_input_edit_text.xml EditText 布局文件。若是想要替换背景,直接修改便可。

三、rc_ext_voice_input.xml 语音输入布局文件。

四、输入框模式自定义。

另外,在会界面中能够设置输入框的模式。针对聊天会话的语音/文本切换功能、内容输入功能、扩展功能,融云目前提供了 5 种排列组合模式:

style 组合模式
SCE 语音/文本切换功能+内容输入功能+扩展功能
SC 语音/文本切换功能+内容输入功能
EC 扩展功能+内容输入功能
CE 内容输入功能+扩展功能
C 内容输入功能

用户能够经过更改 rc_fr_conversation.xml 里 app:RCStyle="SCE" ,更改默认输入显示形式。

2、“+”号扩展区域自定义

自定义 Plugin

一、自定义 Plugin 并实现 IPluginModule。 如:

public class MyPlugin implements IPluginModule { … } 

二、自定义一个 ExtensionModule 继承自 DefaultExtensionModule,复写其中的 getPluginModules() 方法,返回须要展现的 plugin 列表。如:

public class MyExtensionModule extends DefaultExtensionModule { private MyPlugin myPlugin; @Override public List<IPluginModule> getPluginModules(Conversation.ConversationType conversationType) { List<IPluginModule> pluginModules = super.getPluginModules(conversationType); pluginModules.add(myPlugin); return pluginModules; } } 

三、在初始化以后,取消 SDK 默认的 ExtensionModule,注册自定义的 ExtensionModule, 以下:

public void setMyExtensionModule() { List<IExtensionModule> moduleList = RongExtensionManager.getInstance().getExtensionModules(); IExtensionModule defaultModule = null; if (moduleList != null) { for (IExtensionModule module : moduleList) { if (module instanceof DefaultExtensionModule) { defaultModule = module; break; } } if (defaultModule != null) { RongExtensionManager.getInstance().unregisterExtensionModule(defaultModule); RongExtensionManager.getInstance().registerExtensionModule(new MyExtensionModule()); } } } 

四、视频讲解如何在已默认支持照片、拍照、地理位置、语音通话等功能的状况下,新增自定义及减小默认功能项。

 

自定义 EmoticonTab

一、自定义 EmoticonTab 实现 IEmoticonTab。 如:

public class MyEmoticon implements IEmoticonTab { … } 

二、自定义一个 ExtensionModule 继承自 DefaultExtensionModule,复写其中的 getEmoticonTabs() 方法,返回须要展现的 EmoticonTab 列表。如:

public class MyExtensionModule extends DefaultExtensionModule { private MyEmoticon myEmoticon; @Override public List<IEmoticonTab> getEmoticonTabs() { List<IEmoticonTab> emoticonTabs = super.getEmoticonTabs(); emoticonTabs.add(myEmoticon); return emoticonTabs; } } 

三、在初始化以后,取消 SDK 默认的 ExtensionModule,注册自定义的 ExtensionModule, 以下:

public void setMyExtensionModule() { List<IExtensionModule> moduleList = RongExtensionManager.getInstance().getExtensionModules(); IExtensionModule defaultModule = null; if (moduleList != null) { for (IExtensionModule module : moduleList) { if (module instanceof DefaultExtensionModule) { defaultModule = module; break; } } if (defaultModule != null) { RongExtensionManager.getInstance().unregisterExtensionModule(defaultModule); RongExtensionManager.getInstance().registerExtensionModule(new MyExtensionModule()); } } } 

3、输入区事件监听

自定义 fragment 继承 ConversationFragment, 便可获取或者复写 ConversationFragment 里的各个事件,如输入文本内容的变化,发送按钮或者语音按钮的点击事件等。

详细请参考融云 Android Extension 开发文档

消息自定义

新建消息

一、继承 MessageContent

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

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

二、重写和实现方法

实现 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);//该类为工具类,对消息中属性进行序列化 ... //这里可继续增长你消息的属性 } 

三、增长注解信息

注解名: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 表示客户端收到消息后,要进行存储,并在以后能够经过接口查询,存储后会在会话界面中显示。

四、注册自定义消息

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

RongIM.registerMessageType(CustomizeMessage.class);

消息展现

自定义消息在会话列表和会话页面显示。

步骤:

一、建立消息提供者

新建一个消息类继承 IContainerItemProvider.MessageProvider 类,实现对应接口方法,接口方法以下表:

方法名 描述
newView 初始化 View。
bindView 将数据填充 View 上。
getContentSummary 该条消息为该会话的最后一条消息时,会话列表要显示的内容,经过该方法进行定义。  
onItemClick 点击该类型消息触发。
onItemLongClick 长按该类型消息触发。

代码片断以下:

@ProviderTag(messageContent = CustomizeMessage.class) public class CustomizeMessageItemProvider extends IContainerItemProvider.MessageProvider<CustomizeMessage> { class ViewHolder { TextView message; } @Override public View newView(Context context, ViewGroup group) { View view = LayoutInflater.from(context).inflate(io.rong.imkit.R.layout.item_customize_message, null); ViewHolder holder = new ViewHolder(); holder.message = (TextView) view.findViewById(android.R.id.text1); view.setTag(holder); return view; } @Override public void bindView(View v, int position, CustomizeMessage content, Message message) { ViewHolder holder = (ViewHolder) v.getTag(); if (message.getMessageDirection() == Message.MessageDirection.SEND) {//消息方向,本身发送的 holder.message.setBackgroundResource(io.rong.imkit.R.drawable.rc_ic_bubble_right); } else { holder.message.setBackgroundResource(io.rong.imkit.R.drawable.rc_ic_bubble_left); } holder.message.setText(content.getContent()); AndroidEmoji.ensure((Spannable) holder.message.getText());//显示消息中的 Emoji 表情。 } @Override public Spannable getContentSummary(CustomizeMessage data) { return new SpannableString("这是一条自定义消息CustomizeMessage"); } @Override public void onItemClick(View view, int position, CustomizeMessage content, Message message) { } @Override public void onItemLongClick(View view, int position, CustomizeMessage content, Message message) { } } 

二、注册消息模板

RongIM.getInstance().registerMessageTemplate(new CustomizeMessageItemProvider); 

发送消息

调用 RongIM.getInstance().sendMessage() 发送自定义消息。须要注意的是,该方法有两个参数 pushContent 和 pushData 。 说明以下:

  • pushContent:当客户端离线,接受推送通知时,通知的内容会显示为 pushContent 的内容。若是发送的是自定义消息,该字段必须填写,不然会没法收到该消息的推送

  • pushData:收到该消息的推送时的附加信息。若是设置该字段,用户在收到该消息的推送时,能经过推送监听 onNotificationMessageArrived() 里的参数 PushNotificationMessage 的 getPushData() 方法获取。

关于链接

对链接的几点特殊说明:

connect() 方法在整个应用全局,建议仅调用一次。 SDK 有重连机制,您不须要屡次重连。

connect() 方法的回调仅在调用时回调一次,后续 SDK 的链接状态发生变化时,不会再经过 connect() 的回调返回,而是 经过您设置的链接状态监听器得到。详细请参考链接状态监听

重连机制:

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

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

  1. App Key 错误,请检查您使用的 App Key 是否正确。

    RC_CONN_ID_REJECT = 31002
  2. Token 无效

    RC_CONN_USER_OR_PASSWD_ERROR = 31004

    Token 无效通常有如下两种缘由。

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

    二、Token 过时,是由于您在开发者后台设置了 Token 过时时间,您须要请求您的服务器从新获取 Token 并再次用新的 Token 创建链接。

  3. BundleID 不正确

    RC_CONN_PACKAGE_NAME_INVALID = 31007

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

  4. App Key 被封禁或已删除

    RC_CONN_APP_BLOCKED_OR_DELETED = 31008

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

  5. 用户被封禁

    RC_CONN_USER_BLOCKED = 31009

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

  6. 当前用户在其余设备上登陆,此设备被踢下线

    RC_DISCONN_KICK = 31010
  7. SDK 没有初始化

    BIZ_ERROR_CLIENT_NOT_INIT = 33001

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

  8. 开发者接口调用时传入的参数错误

    BIZ_ERROR_INVALID_PARAMETER = 33003

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

功能进阶

正在输入的状态提示

若是聊天的用户正在输入文字或者正在录制语音消息,SDK 能够在聊天界面的标题栏中显示对方正在输入对方正在讲话的提示。

您能够经过 rc_configuration.xml 里的开关开启输入状态提醒的功能,目前仅支持单聊。默认 true 是开启,设置为 false 为关闭。

<!-- 设置发送输入状态 -->
<bool name="rc_typing_status">true</bool>

融云 SDK 内部已经处理好逻辑,开发者不须要关心如何发送输入状态,何时取消输入状态等细节。只须要注册监听,在回调里更新标题栏便可。

因为融云只提供 fragment ,因此标题栏的处理须要开发者本身添加。请在集成了 ConversationFragment的activity 里注册输入状态的监听,您能够在 activity 的 onCreate() 里添加以下代码。

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); } } } }); 

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

如何您使用的是 IMLib SDK 集成,实现方式 请参见文档

消息阅读回执

您能够经过 rc_config.xml 里的开关,开启消息的阅读回执功能。默认 false 为关闭状态,设置成 true 为开启。

<!-- 设置已读回执 -->
    <bool name="rc_read_receipt">true</bool>

另外,请在 init 以后调用下面方法来设置支持消息回执的会话类型。目前只支持 PRIVATE、GROUP 和 DISCUSSION 三种类型。

Conversation.ConversationType[] types = new Conversation.ConversationType[] { Conversation.ConversationType.PRIVATE, Conversation.ConversationType.GROUP, Conversation.ConversationType.DISCUSSION }; RongIM.getInstance().setReadReceiptConversationTypeList(types); 

若是不设置的话,默认只有 PRIVATE 类型的会话支持消息回执。

如何您使用的是 IMLib SDK 集成,实现方式 请参见文档

群组、讨论组 @ 功能

从 2.6.8 版本开始支持在群组或者讨论组中实现 @ 功能,您能够 @ 指定用户或 @ 全部人。

一、开启 @ 功能

@ 功能默认为关闭状态,能够在 rc_config.xml 设置 rc_enable_mentioned_message 为 true 开启 @ 功能。

二、设置 @ 成员信息提供者

在会话 activity,经过 RongIM.getInstance().setGroupMembersProvider(String groupId, RongIM.IGroupMemberCallback) 来设置 @ 成员信息提供者。

您能够参考咱们 SealTalk 中的 ConversationActivity 来实现。

在 activity 的 onCreate 里设置 @ 群组信息提供者:

RongIM.getInstance().setGroupMembersProvider(new RongIM.IGroupMembersProvider() { @Override public void getGroupMembers(String groupId, RongIM.IGroupMemberCallback callback) { ... //获取群组成员信息列表 callback.onGetGroupMembersResult(list); // 调用 callback 的 onGetGroupMembersResult 回传群组信息 } }); 

三、@ 成员列表界面自定义

通过第一步打开功能开关后,您就能够长按头像 @ 某人或者输入 @ 字符,弹出成员列表。该成员列表界面您能够自定义。

自定义步骤以下:

a. RongMentionManager.setMentionedInputListener(IMentionedInputListener listener) 设置 @ 字符输入监听器。

b. 在监听器的回调 onMentionedInput() 里跳转到您自定义的 @ 成员选择界面,并返回 true 。

c. 在成员选择界面,选择成员后,调用下面的方法返回所选成员信息。

RongMentionManager.getInstance().mentionMember(item.userInfo);

d. IMentionedInputListener 说明:

public interface IMentionedInputListener { /** * 当启动@功能,即在rc_config.xml中设置rc_enable_mentioned_message 为true后,该方法用于设置在群组或者讨论组中,输入@时的监听。 * 若是{@link IMentionedInputListener#onMentionedInput(Conversation.ConversationType, String)}返回true, 则您本身处理显示@成员 * 的选择界面;若是返回false, 则会显示融云SDK默认@成员选择界面。 * * @param conversationType 会话类型 * @param targetId 会话 id * @return 返回true, 则您本身处理显示 @ 成员的选择界面;若是返回false, 则会显示融云SDK默认@成员选择界面。 */ boolean onMentionedInput(Conversation.ConversationType conversationType, String targetId); } 

四、@ 全部人功能

@ 全部人时须要新建一个 MentionedType 为 MentionedType.ALL的MentionedInfo ,并把它设置到 MessageContent中,例:

MentionedInfo mentionedInfo = new MentionedInfo(MentionedInfo.MentionedType.ALL, null, null); textMessage.setMentionedInfo(mentionedInfo); RongIM.getInstance().sendMessage(…); 

您也能够参考 SealTalk 中的 GroupNoticeActivity 来实现。

@ 消息推送会越过全部免打扰逻辑,给用户推送 Push 通知。

若是您使用的是 IMLib SDK 集成,可参考 IMLib @ 功能文档

消息撤回

从 2.6.8 版本开始 IMKit 中集成了消息撤回功能,默认为关闭状态。开启后,用户在消息发送成功后的有效时间内长按消息,在弹出菜单中选择“撤回消息”来将这条消息撤回。这条消息将在发送端删除,并提示“你撤回了一条消息”,同时发送撤回指令给接收端,接收端收到撤回指令后,也会把同一条消息删除,提示“XX撤回了一条消息”。

请在 rc_config.xml 中将 rc_enable_message_recall 置为 true 来开启消息撤回功能。

rc_message_recall_interval 用来设置撤回消息的有效时间,以秒为单位。当消息发送成功后,只有在有效时间内方能撤回,超过有效时间将不能再执行撤回操做。

<!-- 设置是否支持消息撤回-->
<bool name="rc_enable_message_recall">true</bool>
<!-- 消息撤回有效时间(单位:秒)-->
<integer name="rc_message_recall_interval">120</integer>

红包

注意事项:融云 SDK 的 IM 红包功能是由一路魔方科技提供的服务,若您的 App 以前已集成过一路魔方的红包 SDK,为了保证两个平台数据兼容和一致性,请 提交工单咨询帮助,感谢您的配合。 
点击查看 红包使用说明书红包业务常见问题。 
您能够在 开发者后台-数据统计-红包统计中查看红包的数据统计状况。

一、 融云官网提供 RedPacket Module 下载,开发者须要在本身应用的 build.gradle 文件中添加依赖 compile project(':RedPacket')。

二、 SDK 会默认加载红包模块,并在私人、群组会话 "+" 号区域出现红包插件(暂不支持其余会话类型)。

三、 开发者须要实现 RongIM#setGroupMembersProvider(IGroupMembersProvider) 方法,用于红包功能中展现群组成员信息。

四、 红包模块提供以下接口,进入"个人钱包"界面:

/** * 进入个人钱包页面 * @param activity :从哪一个activity的跳转 */ JrmfClient.intentWallet(Activity activity); 

多端阅读消息数同步

您能够经过 rc_config.xml 里的开关,开启多端同步阅读状态功能。默认 false 为关闭状态,设置成 true 为开启。

<!-- 开启以后,用户在其余端上阅读过的消息,当前客户端会清掉该消息的未读数。目前仅支持单聊、群聊、讨论组。-->
<bool name="rc_enable_sync_read_status">true</bool>

其余

Fragment 使用

分别介绍这三个 fragment 的使用方式:

  • 会话列表:ConversationListFragment
  • 聚合后的会话列表:SubConversationListFragment
  • 会话页面:ConversationFragment

一、会话列表

静态集成:

在 AndroidManifest.xml 会话列表Activity 下面配置 intent-filter。此处会话列表 Activity 以 ConversationListActivity 为例,包名以 io.rong.fast 为例:

<activity android:name="io.rong.fast.activity.ConversationListActivity"
          android:screenOrientation="portrait"
          android:windowSoftInputMode="stateHidden|adjustResize">

      <intent-filter>
          <action android:name="android.intent.action.VIEW" />

          <category android:name="android.intent.category.DEFAULT" />

          <data
              android:host="io.rong.fast"
              android:pathPrefix="/conversationlist"
              android:scheme="rong" />
      </intent-filter>
  </activity>

在 ConversationActivity 的布局文件 conversationlis.xml 中静态集成 ConversationListFragment :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <fragment
        android:id="@+id/conversationlist"
        android:name="io.rong.imkit.fragment.ConversationListFragment"  //静态方式集成 ConversationListFragment
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

会话列表 Activity 配置对应的布局文件。

public class ConversationListActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.conversationlist); } } 

启动会话列表 Activity :

/** * 启动会话列表界面。 * * @param context 应用上下文。 * @param supportedConversation 定义会话列表支持显示的会话类型,及对应的会话类型是否聚合显示。 * 例如:supportedConversation.put(Conversation.ConversationType.PRIVATE.getName(), false) 非聚合式显示 private 类型的会话。 */ public void startConversationList(Context context, Map<String, Boolean> supportedConversation) 

注意,这个方法里的参数 supportedConversation 是指您的会话列表须要显示的会话类型,以及对应的会话是否聚合显示属性。示例:

private void startConversationList() { Map<String, Boolean> map = new HashMap<>(); map.put(Conversation.ConversationType.PRIVATE.getName(), true); // 会话列表须要显示私聊会话, 第二个参数 true 表明私聊会话须要聚合显示 map.put(Conversation.ConversationType.GROUP.getName(), false); // 会话列表须要显示群组会话, 第二个参数 false 表明群组会话不须要聚合显示 RongIM.getInstance().startConversationList(this.getApplicationContext(), map); } 

动态集成:

在 AndroidManifest.xml 中会话列表 Activity 下面配置 intent-filter,以 ConversationListDynamicActivtiy 为例,包名以 io.rong.fast 为例:

<!--会话列表-->
 <activity
     android:name="io.rong.fast.test.ConversationListDynamicActivtiy"
     android:screenOrientation="portrait"
     android:windowSoftInputMode="stateHidden|adjustResize">

     <intent-filter>
         <action android:name="android.intent.action.VIEW" />

         <category android:name="android.intent.category.DEFAULT" />

         <data
             android:host="io.rong.fast"
             android:pathPrefix="/conversationlist"
             android:scheme="rong" />
     </intent-filter>
 </activity>

会话列表布局文件 rong_activity.xml,代码示例:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/rong_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>

动态加载 ConversationListFragment,并配置其显示属性

注意: 动态方式加载 ConversationListFragment 的时候,必须调用 setUri() 方法设置 Fragment 的显示属性,好比须要显示哪些类型的会话,会话是否聚合显示等。 具体的使用方法请参考下面示例:

public class ConversationListDynamicActivtiy extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.rong_activity); ConversationListFragment fragment = new ConversationListFragment(); Uri uri = Uri.parse("rong://" + getApplicationInfo().packageName).buildUpon() .appendPath("conversationlist") .appendQueryParameter(Conversation.ConversationType.PRIVATE.getName(), "true") //设置私聊会话,该会话聚合显示 .appendQueryParameter(Conversation.ConversationType.GROUP.getName(), "false")//设置群组会话,该会话非聚合显示 .build(); fragment.setUri(uri); //设置 ConverssationListFragment 的显示属性 FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.add(R.id.rong_content, fragment); transaction.commit(); } } 

启动包含会话列表页的 Activity :

startActivity(new Intent(MainActivity.this, ConversationListDynamicActivtiy.class)); 

二、聚合会话列表

2.一、Activity 集成调用方式

静态集成:

在 AndroidManifest.xml 聚合会话列表 Activity 下面配置 intent-filter,以 SubConversationListActivtiy 为例,包名以 io.rong.fast 为例:

<activity
            android:name="io.rong.fast.activity.SubConversationListActivtiy"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="stateHidden|adjustResize">

    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />

        <data
            android:host="io.rong.fast"
            android:pathPrefix="/subconversationlist"
            android:scheme="rong" />
    </intent-filter>
</activity>

在 subconversationlist.xml 中集成 fragment,subconversationlist.xml 代码示例:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <fragment
        android:id="@+id/subconversationlist"
        android:name="io.rong.imkit.fragment.SubConversationListFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

在 SubConversationListActivtiy 中加载 subconversationlist.xml 便可:

public class SubConversationListActivtiy extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.subconversationlist); } } 

启动聚合会话列表 Activity:

/** * 启动聚合后的某类型的会话列表。<br> 例如:若是设置了单聊会话为聚合,则经过该方法能够打开包含全部的单聊会话的列表。 * * @param context 应用上下文。 * @param conversationType 会话类型。 */ public void startSubConversationList(Context context, Conversation.ConversationType conversationType) 

动态集成:

在 AndroidManifest.xml 聚合会话列表 Activity 下面配置 intent-filter,以 SubConversationListDynamicActivtiy 为例,包名以 io.rong.fast 为例:

<activity
           android:name="io.rong.fast.test.subconversationlist.SubConversationListDynamicActivtiy"
           android:screenOrientation="portrait"
           android:windowSoftInputMode="stateHidden|adjustResize">

           <intent-filter>
               <action android:name="android.intent.action.VIEW" />

               <category android:name="android.intent.category.DEFAULT" />

               <data
                   android:host="io.rong.fast"
                   android:pathPrefix="/subconversationlist"
                   android:scheme="rong" />
           </intent-filter>
       </activity>

加载 subconversationlist.xml 配置文件,代码示例:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/rong_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</FrameLayout>
public class SubConversationListDynamicActivtiy extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.rong_activity); SubConversationListFragment fragment = new SubConversationListFragment(); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.add(R.id.rong_content, fragment); transaction.commit(); } } 

三、会话页面

3.一、Activity 集成调用方式

静态集成:

在 AndroidManifest.xml 会话 Activity 下面配置 intent-filter,以 ConversationActivity 为例,包名以 io.rong.fast 为例:

<activity
    android:name="io.rong.fast.activity.ConversationActivity"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateHidden|adjustResize">

    <intent-filter>
        <action android:name="android.intent.action.VIEW" />

        <category android:name="android.intent.category.DEFAULT" />

        <data
            android:host="io.rong.fast"
            android:pathPrefix="/conversation/"
            android:scheme="rong" />
    </intent-filter>
</activity>

在会话 Activity 的布局文件 conversation.xml 中静态集成 ConversationFragment. 代码示例:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <fragment
        android:id="@+id/conversation"
        android:name="io.rong.imkit.fragment.ConversationFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

您的会话界面 Activity。

public class ConversationActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.conversation); } } 

启动会话页面:

/** * <p>启动会话界面。</p> * <p>使用时,能够传入多种会话类型 {@link io.rong.imlib.model.Conversation.ConversationType} 对应不一样的会话类型,开启不一样的会话界面。 * 若是传入的是 {@link io.rong.imlib.model.Conversation.ConversationType#CHATROOM},sdk 会默认调用 * {@link RongIMClient#joinChatRoom(String, int, RongIMClient.OperationCallback)} 加入聊天室。 * 若是你的逻辑是,只容许加入已存在的聊天室,请使用接口 {@link #startChatRoomChat(Context, String, boolean)} 而且第三个参数为 true</p> * * @param context 应用上下文。 * @param conversationType 会话类型。 * @param targetId 根据不一样的 conversationType,多是用户 Id、讨论组 Id、群组 Id 或聊天室 Id。 * @param title 聊天的标题,开发者能够在聊天界面经过 intent.getData().getQueryParameter("title") 获取该值, 再手动设置为标题。 */ public void startConversation(Context context, Conversation.ConversationType conversationType, String targetId, String title) 

动态集成:

在 AndroidManifest.xml 会话 Activity 下面配置 intent-filter,以 ConversationDynamicActivity 为例,包名以 io.rong.fast 为例:

<!--会话页面-->
 <activity
     android:name="io.rong.fast.test.conversation.ConversationDynamicActivity"
     android:screenOrientation="portrait"
     android:windowSoftInputMode="stateHidden|adjustResize">

     <intent-filter>
         <action android:name="android.intent.action.VIEW" />

         <category android:name="android.intent.category.DEFAULT" />

         <data
             android:host="io.rong.fast"
             android:pathPrefix="/conversation/"
             android:scheme="rong" />
     </intent-filter>
 </activity>

动态加载 ConversationFragment,根据 intent 里面传来的参数,经过 setUri() 设置 ConversationFragment 相关属性。 示例:

public class ConversationDynamicActivity extends FragmentActivity { private String mTargetId; //目标 Id private Conversation.ConversationType mConversationType; //会话类型 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.rong_activity); /* 从 intent 携带的数据里获取 targetId 和会话类型*/ Intent intent = getIntent(); mTargetId = intent.getData().getQueryParameter("targetId"); mTargetIds = intent.getData().getQueryParameter("targetIds"); mConversationType = Conversation.ConversationType.valueOf(intent.getData().getLastPathSegment().toUpperCase(Locale.US())); /* 新建 ConversationFragment 实例,经过 setUri() 设置相关属性*/ ConversationFragment fragment = new ConversationFragment(); Uri uri = Uri.parse("rong://" + getApplicationInfo().packageName).buildUpon() .appendPath("conversation").appendPath(mConversationType.getName().toLowerCase()) .appendQueryParameter("targetId", mTargetId).build(); fragment.setUri(uri); /* 加载 ConversationFragment */ FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.add(R.id.rong_content, fragment); transaction.commit(); } } 

intent-filter 配置

融云 IMKit SDK 使用 Fragment 方式实现组件的自定义和嵌入功能,提供 Fragment 能力的组件包括:

  • 会话列表 ConversationListFragment
  • 聊天会话 ConversationFragment
  • 聚合会话列表 SubConversationListFragment

Fragment 的启动参数是经过获取所在 Activity 开启时候所携带的 Intent 中的 Data(即 Uri )来实现的。

以会话页面的启动 Uri 为例说明:

rong://{packagename:应用包名}/conversation/[private|discussion|group]?targetId={目标Id}&[title={开启会话名称}] 

若是您的包名为 io.rong.imkit.demo,Id 为 12345 的讨论组的 Uri 就是 rong://io.rong.imkit.demo/conversation/discussion?targetId=12345,那么配置 AndroidManifest.xml 文件以下:

<intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
    <data
          android:host="io.rong.imkit.demo"
          android:pathPrefix="/conversation/"
          android:scheme="rong" />
</intent-filter>

而后,在配置的 Activity 所属的 Layout 布局文件上加入相应的 ConversationFragment。 这样在 Intent 带有如上 Uri 后就会唤起 Activity 且 Layout 中的 ConversationFragment 就能够启动并得到参数。 各个 Fragment 的开启 Uri 和 Intent-filter 参数配置以下:

会话列表 ConversationListFragment

<intent-filter>
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.DEFAULT" />

    <data
        android:host="你的包名"
        android:pathPrefix="/conversationlist"
        android:scheme="rong" />
</intent-filter>

聚合后的会话列表 SubConversationListFragment

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <data
        android:host="你的包名"
        android:path="/subconversationlist"
        android:scheme="rong" />
</intent-filter>

会话页面 ConversationFragment

<intent-filter>
    <action android:name="android.intent.action.VIEW" />

    <category android:name="android.intent.category.DEFAULT" />

    <data
        android:host="你的包名"
        android:pathPrefix="/conversation/"
        android:scheme="rong" />
</intent-filter>

公众帐号页面

<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <data
      android:host="你的包名"
      android:pathPrefix="/publicServiceProfile"
      android:scheme="rong" />
</intent-filter>

断网重连机制

融云 SDK 中已经为开发者作了断网重连的机制处理,开发者没必要在断网后作连融云服务器的操做。

在网络链接断开后,融云会尝试 5 次从新链接服务器,首次断网 2 秒后会从新链接,若是仍然链接不成功,会在 4 秒后(重连间隔时间为上次重连间隔时间乘 2 )尝度从新链接服务器,以此类推当尝试重连 5 次后,仍然连不上服务器将不在尝试从新链接,只有在网络状况发生变化或从新打开应用时才会再次尝试重连。

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

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 超时。

好友关系

融云为了客户隐私考虑,既不一样步又不保存用户的好友关系。因此,全部用户的好友关系都须要开发者自已实现、管理维护,会话及好友列表中显示好友的昵称及头像信息,须要 App 设置一个用户信息提供者给 IMKit,以便 IMKit 经过用户信息提供者, 来实如今聊天界面和会话列表页中显示好友的昵称和头像。详细请参见用户信息提供者参考文档好友关系实现示例,视频教程以下:

 

陌生人发送加好友邀请,可经过 ContactNotificationMessage 消息类实现。详情请参见 内置通知类消息 中的联系人(好友)通知消息

对于不需好友关系的 APP 来讲(如:陌生人交友、医疗咨询等),可直接经过  startPrivateChat 方法启动会话界面。传入要与之聊天的  targetUserId 后便可进行陌生人会话。

应用标识

应用标识是为了咱们的 API 可以正确识别并验证您的应用请求而所必要的信息,对于防止帐户盗用和滥用有着重要的做用。针对 Android 平台,须要填写包名即 Package Name,就是在 AndroidManifest.xml 中的 package 属性值,如图所示。

image
Package Name 位置
若是您只是采用开发环境 App Key / Secret 进行测试开发,暂时不须要填写相关信息;可是您在提请应用上线前必须完善应用配置信息,不然没法提请上线。
请务必确保您填写的包名即 Package Name 信息和您应用程序包中的信息一致。上线后,每次链接咱们都将会验证这个信息,若是信息不一致,服务端将会拒绝接受链接,您的 App 将没法使用融云的相关服务。

打包混淆

-keepattributes Exceptions,InnerClasses

-keepattributes Signature

# RongCloud SDK -keep class io.rong.** {*;} -keep class * implements io.rong.imlib.model.MessageContent {*;} -dontwarn io.rong.push.** -dontnote com.xiaomi.** -dontnote com.google.android.gms.gcm.** -dontnote io.rong.** # VoIP -keep class io.agora.rtc.** {*;} # Location -keep class com.amap.api.**{*;} -keep class com.amap.api.services.**{*;} # 红包 -keep class com.google.gson.** { *; } -keep class com.uuhelper.Application.** {*;} -keep class net.sourceforge.zbar.** { *; } -keep class com.google.android.gms.** { *; } -keep class com.alipay.** {*;} -keep class com.jrmf360.rylib.** {*;} -ignorewarnings 

另外,您须要 keep 自定义的 BroadcastReceiver 。自定义的 BroadcastReceiver 继承PushMessageReceiver,使用下面的代码是不行的。

-keep public class * extends android.content.BroadcastReceiver 

您须要使用下面的代码 keep 自定义的 BroadcastReceiver。

这里 io.rong.app.DemoNotificationReceiver 改为您的应用自定义的完整类名

-keep class io.rong.app.DemoNotificationReceiver {*;}

参考资料

常见状态码及处理

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

相关文章
相关标签/搜索