環信即時通訊整合過程
最近一直挺忙,使用了一些第三方的東西,也遇見了不少的問題,前面使用的一些還好,比如推送,分享這些第三方都比較容易整合,這次整合環信的即時通訊還是費了一些周折,剛弄完,趕緊記錄一下。
一.前期需要注意的地方
總的來說環信的開發文件和SDK做的已經很簡單了,但是畢竟是第一次整合,使用別人的東西難免有點摸不著頭。這次使用環信3.0版本來整合。基本上前面的操作都可以按著文件的說明進行了,這裡感覺新增sdk前需要注意幾個地方。
1.先對文件進行一個全面的閱讀
我剛開始在做其他的第三方整合時也很著急,想著怎麼趕緊找到一個入口。最後發現著急沒用,所以先閱讀以下文件,知道自己需要的功能大體怎麼處理,需要整合哪一些jar包等。這次我開始就沒有注意,閱讀文件時就把獨立的sdk的jar和so包都複製到了專案中,最後發現,有一個更好用一些的東西EaseUI 這個module,直接匯入這個module就可以不用再去新增各種jar和so檔案了。所以,我們有一個整體的把握很重要。
2.瞭解easeUI包
easeUI這個包下包含了好些jar還有百度地圖的包,在【Android SDK 介紹和匯入】這個地方說明的包基本都是這裡的。
瞭解這些方便我們處理後邊的衝突等問題。比如我的專案之前放入了百度sdk的jar,這裡也有,但是版本不同可能引發問題,也可能由於重複引入jar導致問題。
二.新增整合
1.整合easeUI
我使用了easeUI這個module直接整合的,這樣我們可以使用環信提供的一些UI,比如EaseChatFragment ,這是一個聊天介面,一般來說自己處理這個頁面還是有一些困難或者問題。整合出現的問題。
這個也是官方提出的,首先我們要處理這個,我覺得還是把這個module的v4包版本號增加大這個方式好一些,例如使用:把
v4 包的版本號加大,譬如 compile 'com.android.support:support-v4:23.2.1這樣編譯就可以了。下面就是按照文件找到自己需要的API集成了。從註冊,到登入,然後獲取好友列等操作
2.API整合出現的問題
1).一些異常比如出現:unknow server exception(異常資訊沒有截圖),這個問題其實是我們沒有按照文件說明去做,
//群主加人呼叫此方法
EMClient.getInstance().groupManager().addUsersToGroup(groupId, newmembers);//需非同步處理
上面介面說了使用非同步處理,我沒有使用非同步也就出現了異常。
2).
3.使用easeUI
我們在環信註冊了使用者之後就會有一個環信的id,通過這個id我們就可以和對方進行簡答的通訊了。使用EaseChatFragment。
按照文件說明建立一個Activity,然後寫一下的程式碼:
EaseChatFragment chatFragment = new EaseChatFragment();
Bundle args = new Bundle();
args.putInt(EaseConstant.EXTRA_CHAT_TYPE, EaseConstant.CHATTYPE_SINGLE);
args.putString(EaseConstant.EXTRA_USER_ID, getIntent().getStringExtra("userID"));
chatFragment.setArguments(args);
FragmentManager supportFragmentManager = getSupportFragmentManager();
getSupportFragmentManager().beginTransaction().add(R.id.container, chatFragment).commit();
//container是你建立的activity的根佈局的id
/**
* 發起聊天 這個是從MainActivty或者其他頁面發起聊天,傳入一個你註冊的環信id
* @param input
*/
private void startChat(String input) {
//new出EaseChatFragment或其子類的例項
if(!TextUtils.isEmpty(input)){
Intent intent = new Intent(MainActivity.this, ChatActivity.class);
intent.putExtra("userID",input);
startActivity(intent);
}else{
Toast.makeText(this, "請輸入一個使用者id", Toast.LENGTH_SHORT).show();
}
}
完成上述的註冊,登入和EaseChatFragment後通訊功能基本上就可以實現了。如圖:
到此環信的整合主要功能也就是完成的,其他的可能會用到聊天列表,通訊錄這些按照文件整合就可以,不過環信不對通訊錄進行維護,也就是說要是儲存使用者資訊什麼的東西,需要我們自己的伺服器來儲存,然後在使用時根據環信id去伺服器獲取這個使用者的其他資訊。
4.修改使用者頭像和使用者名稱
上面的那個圖我們看到了使用者頭像是預設的沒有圖片,這個怎麼處理?環信只是給出了一個思路,demo中有實現的邏輯,但是找出來還是不太容易。
環信給出的兩個方案:
1).從app伺服器獲取使用者資料頭像
2).從訊息擴充套件中獲取使用者資料
最後我選了第二重方案,我也不知道怎麼就選了第二種方法,剛開始對這個問題很暈,沒有一點思路,在網上找了幾個相關的,所以兩個方法弄的有點暈,然後就沒辦法,按照一個方式嘗試,最後逐漸明白,其實這個方式相對來聽容易實現,就是要知道從什麼地方下手。看看最後結果如圖:
圖片中已經有了頭像了。
我們在使用整合的過程中可能需要對EaseChatFragment進行一個重寫,就像上圖圖右上角是一個垃圾桶圖示,我們自己需要一個點選進入使用者資訊的頁面,所以從寫這個EaseChatFragment的一個方法:
@Override
protected void setUpView() {
super.setUpView();
//messageList.init(toChatUsername, chatType, new CustomChatRowProvider());//messageList初始化??
titleBar.setRightImageResource(R.mipmap.user);
titleBar.getRightLayout().setOnClickListener(new View.OnClickListener() {//處理點選
@Override
public void onClick(View v) {
if (chatType == EaseConstant.CHATTYPE_GROUP ) {//群聊,傳遞當前的 emGroup
Intent intent = new Intent(getActivity(), IMDiscussInfoActivity.class);//群組,需要一個id
intent.putExtra("conversationID", toChatUsername);
startActivity(intent);
} else{// 單聊EaseConstant.CHATTYPE_SINGLE
Intent intent = new Intent(getActivity(), IMPersonalInfoActivity.class);//個人
intent.putExtra("conversationID", toChatUsername);//回話id就是手機號碼
startActivity(intent);
}
}
});
}
我們在 EaseChatFragment找上述方法重寫的過程可能會發現有一個介面:EaseChatFragmentHelper,如果你有了這個印象後邊可能就容易了,網上的其他資料讓你能快速想起來然後處理他。這個介面就是文件說的傳送擴擴充套件訊息要使用的,所以按照文件說明從寫介面的方法:
/**
* 實現EaseChatFragmentHelper介面方法
* 希望通過設定附加訊息實現頭像傳遞
* @param message
*/
@Override
public void onSetMessageAttributes(EMMessage message) {
//傳送訊息時附加引數p
LogUtils.e("TAG","onSetMessageAttributes");
Preferences preferences = new Preferences(getActivity());
message.setAttribute(ConstantValue.IM_USER_ID, preferences.getUserPhoneNumber());//標識使用者的手機號
message.setAttribute(ConstantValue.IM_NICK_NAME, preferences.getUserName());
message.setAttribute(ConstantValue.IM_USER_IMAGE, preferences.getString("userImage")) ;
//這裡用是圖片的完整連結地址,如果要取縮圖,需要服務端配合;
LogUtils.e("TAG","fasong使用者頭像:"+preferences.getString("userImage"));
}
寫完不要忘記了在你的這個Fragment中在重寫一個方法比如:onCreate().因為我們要註冊這個介面的實現。
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setChatFragmentListener(this);//註冊介面,EaseChatFragment提供的方法
}
這樣看,基本上完成了擴充套件訊息的傳送。接下來就是訊息的接收和儲存了。
在最初閱讀文件按照步驟做的時候有沒有注意到demo的Application中註冊了這樣一句:
//init demo helper
DemoHelper.getInstance().init(applicationContext);
文件說我們要這樣註冊:
EMOptions options = new EMOptions();
// 預設新增好友時,是不需要驗證的,改成需要驗證
options.setAcceptInvitationAlways(false);
...
//初始化
EMClient.getInstance().init(applicationContext, options);
//在做打包混淆時,關閉debug模式,避免消耗不必要的資源
EMClient.getInstance().setDebugMode(true);
這就導致了我當初沒有看清楚demo中的那句話。現在我們點選進去看看:
/** * init helper * @param context application context */ public void init(Context context) { demoModel = new DemoModel(context); EMOptions options = initChatOptions(); //use default options if options is null if (EaseUI.getInstance().init(context, options)) { appContext = context; //debug mode, you'd better set it to false, if you want release your App officially. EMClient.getInstance().setDebugMode(true); //get easeui instance easeUI = EaseUI.getInstance(); //to set user's profile and avatar setEaseUIProviders(); //initialize preference manager PreferenceManager.init(context); //initialize profile manager getUserProfileManager().init(context); // TODO: set Call options 此處省略中間若干剛... setGlobalListeners(); //broadcastManager = LocalBroadcastManager.getInstance(appContext); // initDbDao(); } }
這裡完成了我們的註冊和其他的操作。
這裡我們需要知道的就是除了EaseUI註冊的那幾行之外的程式碼:
setEaseUIProviders();
setGlobalListeners();
下面是我修改後的專案中的程式碼:
*
* @param context application context
*/
public void init(Context context) {
//demoModel = new DemoModel(context);
EMOptions options = new EMOptions();
options.setAcceptInvitationAlways(false);//新增好友不需要驗證
//use default options if options is null
if (EaseUI.getInstance().init(context, options)) {
appContext = context;
//debug mode, you'd better set it to false, if you want release your App officially.
EMClient.getInstance().setDebugMode(true);
//get easeui instance
easeUI = EaseUI.getInstance();
//to set user's profile and avatar
preferences = new Preferences(context);
setEaseUIProviders();
}
}
對比發現除了註冊的之外關鍵的就是
setEaseUIProviders();這句話
你可以自己在demo中看看這,其實最主要的就是他。進入這個方法發現有一段程式碼:
easeUI.setUserProfileProvider(new EaseUserProfileProvider() { @Override public EaseUser getUser(String username) { return getUserInfo(username); } });突然明白了getUserInfo(username)就是返回最後使用者訊息的那個方法,他返回一個EaseUser物件。我重寫後的getUserInfo(username)如下:
private EaseUser getUserInfo(String username) {
EaseUser user = null;
if (username.equals(EMClient.getInstance().getCurrentUser())) {
//如果使用者是本人,就設定自己的頭像
user = new EaseUser(username);
user.setAvatar(preferences.getString(ConstantValue.USER_IMAGE));
user.setNick(preferences.getUserName());
return user;
}else if(!username.equals(EMClient.getInstance().getCurrentUser())){
DbManager dbManager = x.getDb(MainApplication.getInstance().initDB());
try {
IMContract imContract = dbManager.findById(IMContract.class, username);
if(imContract!=null){
LogUtils.e(TAG,"資料庫查詢結果:"+imContract.getContraactPhone());
user = new EaseUser(username);
user.setAvatar(imContract.getImageUrl());
user.setNick(imContract.getNickName());
return user;
}
} catch (DbException e) {
e.printStackTrace();
}
}
這個方法給EaseUser物件賦值了。這裡還有一點沒有說明。前面在
EaseChatFragmentHelper 介面中添加了擴充套件訊息,我們還沒有取出來呢。
現在看看環信demo中和我寫的不一樣的地方:就是有一個
setGlobalListeners();
這個方法,這個就是環信接收訊息的地方。當時點選進去發現一大片。我們在這個方法的最後發現了這麼一句:
registerMessageListener();
這才是真正接收訊息的地方。在回憶一下當初看文件的時候,在“訊息”這個模組中有這個藉口:
EMClient.getInstance().chatManager().addMessageListener(msgListener);
EMMessageListener msgListener = new EMMessageListener(){...}
現在需要做的就是在這裡實現介面方法,我研究後重寫的:
@Override
public void onMessageReceived(List<EMMessage> list) {
LogUtils.e(TAG, "onMessageReceived執行訊息監聽..");
receivedListener.onMessageReceived(list);
for (EMMessage message : list) {//儲存下資料
String chatUserId = message.getStringAttribute(ConstantValue.IM_USER_ID, "");
String avatarUrl = message.getStringAttribute(ConstantValue.IM_USER_IMAGE, "");
String nickName = message.getStringAttribute(ConstantValue.IM_NICK_NAME, "");
LogUtils.e("TAG", "appjieshou訊息獲取的資料是chatUserId:" + chatUserId);
DbManager db = x.getDb(initDB());
IMContract imContract = new IMContract();
imContract.setContraactPhone(chatUserId);
imContract.setImageUrl(avatarUrl);
imContract.setNickName(nickName);
try {
db.saveOrUpdate(imContract);
} catch (DbException e) {
e.printStackTrace();
LogUtils.e(TAG,"資料庫操作異常:"+e.getMessage());
}
ChatHelper.getInstance().getNotifier().onNewMsg(message);
}
}
這裡獲取當初傳送的訊息並儲存在資料庫中,就好了,我們在使用的時候根據環信的id去查資料庫就可以拿到使用者資訊了。這裡我使用的是xUtils3中的資料庫操作。
ChatHelper.getInstance().getNotifier().onNewMsg(message);//ChatHelper就是demo中的DemoHelper這個是接收到訊息後傳送一個通知的.
現在回到前面的getUserInfo(username)方法中,可以看到這裡只是根據username進行了資料庫查詢,然後返回一個EsaseUser物件。這樣我們就完成了使用者頭像和其他資訊的傳遞。在一次聊天就會發現有頭像和使用者名稱資訊了。
這裡需要注意,頭像這裡直接傳遞一個圖片的url就好了,環信已經封裝好了對他的處理。
如果你在研究的過程發現了EaseUserUtils這個你就知道了:
/** * set user avatar * @param username */ public static void setUserAvatar(Context context, String username, ImageView imageView){ Log.e("TAG","setUserAvatar設定頭像返回:"+username); EaseUser user = getUserInfo(username); if(user != null && user.getAvatar() != null){ try { int avatarResId = Integer.parseInt(user.getAvatar()); Glide.with(context).load(avatarResId).into(imageView); } catch (Exception e) { //use default avatar Glide.with(context).load(user.getAvatar()).diskCacheStrategy(DiskCacheStrategy.ALL).placeholder(R.drawable.ease_default_avatar).into(imageView); } }else{ Glide.with(context).load(R.drawable.ease_default_avatar).into(imageView); } }
可以看到在這裡使用了Glide來載入圖片,沒有圖片的url時使用本地的這個替代。
參考資料:
1..http://www.cnblogs.com/zhang-cb/p/6292254.html