最近一直挺忙,使用了一些第三方的東西,也遇見了不少的問題,前面使用的一些還好,比如推送,分享這些第三方都比較容易集成,這次集成環信的即時通訊還是費了一些周折,剛弄完,趕緊記錄一下。
一.前期需要注意的地方
總的來說環信的開發文檔和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.html2.http://www.imgeek.org/article/825307856