Android SDK 開發指南
視頻詳解
以下視頻是對融雲 Android 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 |
融雲紅包相關組件 | —— |
IMLib 提供了基礎的通信能力,較輕量,適用於對 UI 有較高訂制需求的開發者,但您需要自己去實現大量的界面和功能。
CallKit 融雲音視頻通話的界面組件,包含了單人、多人音視頻通話的界面的各種場景和功能。您可以通過集成該組件來實現豐富的音視頻通話界面,並進行自己的 UI 定制開發。同時我們開源了 CallKit,您可以根據您的需要去使用。
CallLib 融雲音視頻通話核心能力組件。
LocationLib 位置相關庫文件
PushLib 融雲支持第三方推送(小米),您可以從這里下載對應的第三方推送 jar 包。
RedPacket 融雲紅包相關組件,通過集成該組件,即可快速實現紅包功能。
創建應用
您要進行應用開發之前,需要先在融雲開發者平台創建應用。如果您已經注冊了融雲開發者帳號,請前往融雲開發者平台創建應用。
您創建完應用后,首先需要了解的是 App Key / Secret,它們是融雲 SDK 連接服務器所必須的標識,每一個 App 對應一套 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 方法小節。
- userId : 每一個用戶對應一個 userId,這個 userId 是您維護的,所以您可以直接賦值,兩個您的的用戶通信,對於融雲來說就是兩個 userId 間通訊。
- name : 用戶的顯示名稱,用來在 Push 推送時,或者您沒有傳入用戶信息時,默認顯示的用戶名稱。
- portraitUri : 用戶頭像,用來當您沒有傳入用戶信息時作為默認頭像,如果圖片不存在,IMKit 會顯示默認頭像。
通過 API 調試,您可以得到一個 Token 返回值。您就可以直接使用這個 Token 為這位用戶進行發送和接受消息。
SDK 集成
環境要求
在您集成融雲 SDK 前環境要求如下:
- Android SDK Build-tools 請升級到 21 及以上版本。
- JAVA 編譯版本 JDK 1.7 及以上版本。
- 使用 IMKit 需要 Android Support V4 21 及以上版本。
我們建議初次集成 SDK 的用戶,先創建一個空項目來集成融雲的 SDK,然后再考慮加入您的工程。
導入 SDK
以 Module 形式導入前面下載的融雲 SDK 里面的各個組件。
打開您的工程, File -> New -> Import Module

打開您從官網下載的融雲 SDK,選擇 IMLib。如圖:

根據您的需要,以同樣的步驟導入SDK里的其它組件: IMKit, CallKit, CallLib, RedPacket。
將 PushLib 中的 jar 包 和 pushDaemon -> libs 目錄下應用所支持平台的 so 拷貝到您應用的 libs 目錄下,另外還需要將 pushDaemon -> executable 目錄下各平台的可執行文件 push_daemon 拷貝到您應用 Module 的 assets 目錄下。如圖:

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

將 LocationLib 里的 jar 包拷貝到您應用的 libs 目錄下(如果不需要位置功能,可跳過此步驟)。

注意
音視頻通話組件 CallLib 僅支持 armeabi-v7a 和 x86 架構 CPU (組件功能),如果您使用了我們的音視頻通話功能,注意需要把 IMLib 和 PushLib 組件中其它 CPU 架構的 so 刪除。或者您也可以在應用的 build.gradle 文件中增加如下配置來過濾 so :
defaultConfig {
applicationId "XXX" ... ndk { abiFilters "armeabi-v7a", "x86" } }
添加配置
打開應用的 build.gradle,在 dependencies 中添加相應模塊的依賴。如圖:

打開 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 后您會發現以下三個進程: 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 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>
配置聚合會話列表
融雲支持在會話列表頁面自定義某種類型的會話以聚合形式展示,比如,定義所有私聊會話聚合顯示,則在會話列表頁所有私聊會話聚合顯示為“我的私人會話”,點擊“我的私人會話”,會進入所有私聊會話的展示頁面,這個頁面即為聚合會話列表,如圖:

如果您的應用定義了聚合會話,請按照下面的說明進行相應配置,否則可以直接跳過此步驟。
自定義聚合會話列表請參考會話列表自定義。
配置布局文件
這是您的聚合會話列表 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 的數據源顯示用戶昵稱和頭像
。
1、設置用戶信息提供者:
調用 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);
很多時候 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)
2、使用消息攜帶用戶信息
當 App 本身沒有用戶系統或者因為某些原因不方便使用上述用戶信息提供者的時候,可以使用消息攜帶用戶信息來發送給消息接收方。
請注意這種方式不要和用戶信息提供者混用。並且,這種方式會在每條發送的消息里都攜帶當前登陸用戶的信息,增加消息的長度。
首先,需要使用 setCurrentUserInfo
方法來設置當前的用戶信息。
/** * 設置當前用戶信息, * * @param userInfo 當前用戶信息 */ RongIM.getInstance().setCurrentUserInfo(userInfo);
接下來,在 init
之后調用下面方法設置消息攜帶用戶信息。
/** * 設置消息體內是否攜帶用戶信息。 * * @param state 是否攜帶用戶信息,true 攜帶,false 不攜帶。 */ RongIM.getInstance().setMessageAttachedUserInfo(true);
接收方在接收到消息后,SDK 會自動從消息中取出用戶信息,並顯示到 UI 上。
常見問題:
實現教程
以下視頻主要講解融雲 IMKit
中用戶信息的實現包括頭像及昵稱。
基礎功能
單聊
單聊是最基本的聊天界面,提供文字、表情、語音片段、圖片、VoIP 等多種輸入內容,解決 App 內用戶的溝通瓶頸。會話關系由融雲負責建立並保持,退出聊天界面或者離線后可以收到推送通知。
前提條件:
- RongIM.init(this),接口已經執行。
- RongIM.connect(....),接口已經執行且 onSuccess() 被回調。
- 會話 Activity 已經在 AndroidManifest.xml 文件中,配置了對應的 intent-filter,詳見配置說明文檔。
打開單聊窗口:
/** * 啟動單聊界面。 * * @param context 應用上下文。 * @param targetUserId 要與之聊天的用戶 Id。 * @param title 聊天的標題,開發者需要在聊天界面通過 intent.getData().getQueryParameter("title") * 獲取該值, 再手動設置為聊天界面的標題。 */ RongIM.getInstance().startPrivateChat(getActivity(), "9527", "標題");
常見問題:
討論組
討論組業務的描述,請參見新手指南中的說明。
前提條件:
- 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 讀取好友關系。
前提條件:
- RongIM.init(this),接口已經執行。
- RongIM.connect(....),接口已經執行且 onSuccess() 被回調。
- 會話 Activity 已經在 AndroidManifest.xml 文件中,配置了對應的 intent-filter,詳見配置說明文檔。
啟動群組聊天界面:
/** * 啟動群組聊天界面。 * * @param context 應用上下文。 * @param targetGroupId 要聊天的群組 Id。 * @param title 聊天的標題,開發者可以在聊天界面通過 intent.getData().getQueryParameter("title") 獲取該值, 再手動設置為標題。 */ RongIM.getInstance().startGroupChat(getActivity(), "9527", "標題");
客戶端的所有群組操作都需要請求您的 App Server, 您的 App Server 可以根據自己的邏輯進行管理和控制,然后通過 Server API 接口進行群組操作,並將結果返回給客戶端。
詳請見 Server API 群組服務接口。
以下展示了客戶端進行群組操作的流程:
創建群組
加入群組
退出群組
解散群組
設置群組信息
獲取群組成員列表
獲取群組列表
聊天室
聊天室業務的描述,請參見新手指南中的說明。
聊天室與群組最大的不同在於,聊天室的消息沒有 Push 通知,也沒有成員的概念。想參與聊天室聊天,接收聊天室消息,加入聊天室即可;不參與聊天室聊天,不接收消息,退出聊天室即可。IMKit 組件中已經內置了加入和退出聊天室的接口調用,您直接啟動即可:
前提條件:
- RongIM.init(this),接口已經執行。
- RongIM.connect(....),接口已經執行且 onSuccess() 被回調。
- 會話 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>
系統會話
前提條件:
- RongIM.init(this),接口已經執行。
- RongIM.connect(....),接口已經執行且 onSuccess() 被回調。
- 會話 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", "標題");
客服
IMKit 中提供封裝好的客服功能和 UI 界面,輕松的幾行代碼就能完成集成,為應用中用戶提供優質的客服服務。
前提條件:
- RongIM.init(this),接口已經執行。
- RongIM.connect(....),接口已經執行且 onSuccess() 被回調。
- 會話 Activity 已經在 AndroidManifest.xml 文件中,配置了對應的 intent-filter,詳見配置說明文檔。
- 已在 融雲開發者平台 開啟客服服務,並獲取
客服 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() 方法,如下圖:

機器人模式的評價和人工模式的評價,可以通過在自定義類中重寫 onCustomServiceEvaluation() 方法來自定義,如下圖:

公眾號
融雲公眾服務
是為應用開發者和公眾帳號運營者提供的連接服務產品,通過融雲公眾服務,App 可以具備為自己的用戶提供公眾帳號服務的能力和資源。
公眾服務包括
:應用公眾服務
和公眾服務平台
。
應用公眾服務
:是為應用開發者提供的 App 內建公眾服務能力,通過在融雲開發者站點創建 App 公眾號,實現應用內的公眾服務。
公眾服務平台
:是在應用開發者和公眾帳號運營者之間建立的對接平台,應用開發者可以通過平台引入公眾服務資源,幫助 App 快速覆蓋用戶需求,公眾帳號持有者通過平台可以有機會向所有集成融雲 SDK 的 App 提供服務,進而獲得更加精准更加豐富的受眾渠道。
開發者可在 融雲開發者平台 的公眾服務模塊中,通過添加公眾服務
或應用公眾服務
中的公眾號到自已的應用中。
IMKit
組件中已經內置了訂閱和取消訂閱公眾號的接口調用,您直接啟動即可:
前提條件:
- RongIM.init(this),接口已經執行。
- RongIM.connect(....),接口已經執行且 onSuccess() 被回調。
- 會話 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", "公眾帳號標題");
打開公眾服務號會話界面:
/** * 啟動公眾服務號會話界面。 * * @param context 應用上下文。 * @param conversationType 開啟會話類型。 * @param targetId 目標 Id。 * @param title 聊天的標題,開發者可以在聊天界面通過 intent.getData().getQueryParameter("title") 獲取該值, 再手動設置為標題。 */ RongIM.getInstance().startConversation(getActivity(), Conversation.ConversationType.PUBLIC_SERVICE, "9527", "公眾帳號標題");
打開應用公眾服務信息界面:
/** * 啟動應用公眾服務信息界面。 * * @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) { //發送進度 } });
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) { //消息發送失敗的回調 } });
圖文消息發送
生成圖文消息實例:
/** * 生成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)
接收消息監聽器的實現,所有接收到的消息、通知、狀態都經由此處設置的監聽器處理。包括私聊消息、討論組消息、群組消息、聊天室消息以及各種狀態。
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

b. 把自定義的 Uri 賦值給 ConversationListFragment
listFragment.setUri(uri);
頭像位置自定義
對於會話列表中每種會話類型的會話,開發者都可以自定義頭像位置的顯示方式,顯示方式有:靠左顯示、靠右顯示、不顯示。
自定義步驟:
1、新建一類繼承要改變的會話提供者類,然后重寫注解,修改 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 |
2、重新注冊該會話模板,注冊方法應在 init 后調用
RongIM.getInstance().registerConversationTemplate;
自定義示例:
如何在會話列表中讓所單聊會話頭像都靠右顯示?
第一步:
@ConversationProviderTag(conversationType = "private", portraitPosition = 2) public class MyPrivateConversationProvider extends PrivateConversationProvider { ... }
第二步:
RongIM.getInstance().registerConversationTemplate(new MyPrivateConversationProvider());
會話頁面自定義
會話頁面相關布局文件
rc_fr_conversation.xml 會話頁面布局
rc_item_message.xml 消息列表單個 item 對應的布局
您可以通過修改上述布局文件來更改字體大小顏色及背景色等。
消息展示自定義
融雲 IMKit SDK 中每一種消息類型(要在 UI 展示的)都對應一個 UI 展示的 Provider,開發者可以修改 Provider 的注解屬性來完成消息顯示的自定義。
自定義步驟:
1、新建一類並繼承要修改的消息提供者類,然后重寫注解。
- 注解說明:
注解名稱: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);//顯示未讀消息數目

新消息大於 1 條即展示,超過 99 條顯示為 "99+",未讀消息大於 10 條即展示,超過 150 條顯示為 "150+條新消息"。另外,控件的樣式可以在 layout/rc_fr_messagelist.xml
中進行調整。
適配器 adapter 自定義
可以通過自定義會話列表或者會話界面的適配器,來自定義界面的展示。
下面以自定義會話界面消息列表的適配器為例,說明如何自定義:
3.1 自定義會話 fragment 繼承自 ConversationFragment,復寫 onResolveAdapter() 方法,返回自定義的 adapter。
另外您的 activity 布局文件中也需要配置成自定義的 fragment。

3.2 自定義繼承 MessageListAdapter 的消息列表適配器,根據需要復寫其中的 newView() 或者 bindView() 方法

輸入區域自定義
輸入區域相關概念:
1、輸入區域擴展欄對外接口類為 RongExtension。如圖 1
2、Plugin 是開發者自定義 “+” 號區域展開后的 item,如圖 1

3、EmoticonTab 是開發者自定義 表情 tab 頁。如圖 2

一、布局自定義
部分布局文件如下,您可以通過修改對應的布局文件來調整界面布局,修改背景,更改字體等。
1、rc_ext_extension_bar.xml 輸入框布局文件。它是整個輸入框的容器,內部有對各部分組件功能描述。
2、rc_ext_input_edit_text.xml EditText 布局文件。如果想要替換背景,直接修改即可。
3、rc_ext_voice_input.xml 語音輸入布局文件。
4、輸入框模式自定義。
另外,在會界面中可以設置輸入框的模式。針對聊天會話的語音/文本切換功能、內容輸入功能、擴展功能,融雲目前提供了 5 種排列組合模式:
style | 組合模式 |
---|---|
SCE |
語音/文本切換功能+內容輸入功能+擴展功能 |
SC |
語音/文本切換功能+內容輸入功能 |
EC |
擴展功能+內容輸入功能 |
CE |
內容輸入功能+擴展功能 |
C |
內容輸入功能 |
用戶可以通過更改 rc_fr_conversation.xml
里 app:RCStyle="SCE"
,更改默認輸入顯示形式。
二、“+”號擴展區域自定義
自定義 Plugin
1、自定義 Plugin 並實現 IPluginModule。 如:
public class MyPlugin implements IPluginModule { … }
2、自定義一個 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; } }
3、在初始化之后,取消 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()); } } }
4、視頻講解如何在已默認支持照片、拍照、地理位置、語音通話等功能的情況下,新增自定義及減少默認功能項。
自定義 EmoticonTab
1、自定義 EmoticonTab 實現 IEmoticonTab。 如:
public class MyEmoticon implements IEmoticonTab { … }
2、自定義一個 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; } }
3、在初始化之后,取消 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()); } } }
三、輸入區事件監聽
自定義 fragment 繼承 ConversationFragment, 即可獲取或者復寫 ConversationFragment 里的各個事件,如輸入文本內容的變化,發送按鈕或者語音按鈕的點擊事件等。
詳細請參考融雲 Android Extension 開發文檔。
消息自定義
新建消息
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
后注冊,代碼如下:
RongIM.registerMessageType(CustomizeMessage.class);
消息展示
自定義消息在會話列表和會話頁面顯示。
步驟:
1、創建消息提供者
新建一個消息類繼承 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) { } }
2、注冊消息模板
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 均會進行自動重連,開發者無須處理。
-
App Key 錯誤,請檢查您使用的 App Key 是否正確。
RC_CONN_ID_REJECT = 31002
-
Token 無效
RC_CONN_USER_OR_PASSWD_ERROR = 31004
Token 無效一般有以下兩種原因。
1、Token 錯誤,請您檢查客戶端初始化使用的 App Key 和您服務器獲取 Token 使用的 App Key 是否一致;
2、Token 過期,是因為您在開發者后台設置了 Token 過期時間,您需要請求您的服務器重新獲取 Token 並再次用新的 Token 建立連接。
-
BundleID 不正確
RC_CONN_PACKAGE_NAME_INVALID = 31007
請檢查您 App 的 BundleID 是否正確。
-
App Key 被封禁或已刪除
RC_CONN_APP_BLOCKED_OR_DELETED = 31008
請檢查您使用的 App Key 是否正確。
-
用戶被封禁
RC_CONN_USER_BLOCKED = 31009
請檢查您使用的 Token 是否正確,以及對應的 UserId 是否被封禁。
-
當前用戶在其他設備上登錄,此設備被踢下線
RC_DISCONN_KICK = 31010
-
SDK 沒有初始化
BIZ_ERROR_CLIENT_NOT_INIT = 33001
在使用SDK任何功能之前,必須先 Init。
-
開發者接口調用時傳入的參數錯誤
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()
,回調里攜帶有當前正在輸入的用戶列表。對於單聊而言,當對方正在輸入時,監聽會觸發一次;當對方不處於輸入狀態時,該監聽還會觸發一次,但是回調里上來的輸入用戶列表為空,開發者需要在此時取消正在輸入的顯示,顯示原有的標題。
消息閱讀回執
您可以通過 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 類型的會話支持消息回執。
群組、討論組 @ 功能
從 2.6.8 版本開始支持在群組或者討論組中實現 @ 功能,您可以 @ 指定用戶或 @ 所有人。
1、開啟 @ 功能
@ 功能默認為關閉狀態,可以在 rc_config.xml 設置 rc_enable_mentioned_message 為 true 開啟 @ 功能。
2、設置 @ 成員信息提供者
在會話 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 回傳群組信息 } });
3、@ 成員列表界面自定義
經過第一步打開功能開關后,您就可以長按頭像 @ 某人或者輸入 @ 字符,彈出成員列表。該成員列表界面您可以自定義。
自定義步驟如下:
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); }
4、@ 所有人功能
@ 所有人時需要新建一個 MentionedType 為 MentionedType.ALL的MentionedInfo ,並把它設置到 MessageContent中,例:
MentionedInfo mentionedInfo = new MentionedInfo(MentionedInfo.MentionedType.ALL, null, null); textMessage.setMentionedInfo(mentionedInfo); RongIM.getInstance().sendMessage(…);
您也可以參考 SealTalk 中的 GroupNoticeActivity 來實現。
如果您使用的是 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>
紅包
點擊查看 紅包使用說明書及 紅包業務常見問題。
您可以在 開發者后台-數據統計-紅包統計中查看紅包的數據統計情況。
1、 融雲官網提供 RedPacket Module 下載,開發者需要在自己應用的 build.gradle 文件中添加依賴 compile project(':RedPacket')。
2、 SDK 會默認加載紅包模塊,並在私人、群組會話 "+" 號區域出現紅包插件(暫不支持其他會話類型)。
3、 開發者需要實現 RongIM#setGroupMembersProvider(IGroupMembersProvider) 方法,用於紅包功能中展示群組成員信息。
4、 紅包模塊提供如下接口,進入"我的錢包"界面:
/** * 進入我的錢包頁面 * @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
1、會話列表
靜態集成:
在 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、聚合會話列表
2.1、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、會話頁面
3.1、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
消息類實現。詳情請參見 內置通知類消息
中的聯系人(好友)通知消息。
startPrivateChat
方法啟動會話界面。傳入要與之聊天的
targetUserId
后即可進行陌生人會話。
應用標識
應用標識是為了我們的 API 能夠正確識別並驗證您的應用請求而所必要的信息,對於防止賬戶盜用和濫用有着重要的作用。針對 Android 平台,需要填寫包名即 Package Name,就是在 AndroidManifest.xml
中的 package
屬性值,如圖所示。

打包混淆
-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 {*;}
參考資料
- Xamarin 中使用融雲 SDK (感謝 @孫運天 的分享)。
常見狀態碼及處理
集成融雲 SDK 過程中,如遇到問題可查看常見狀態碼及處理表。