距離上次極光徵文不知不覺已通過了將近一年的時間,先感謝上次的徵文比賽,經過 《我和 Android 推送的時間簡史》 這篇文章獲獎,此次又厚着臉皮再次參與,由於項目一直很忙,只得利用週末時間準備 demo 素材和寫文章,很差之處,多多見諒。java
上一篇文章主要講述了 我跟 極光推送 的關係,以及簡單的描述了其集成和使用,做爲三個項目都在使用極光推送的我,對其瞭解也是至關多的,固然坑也踩了很多,不得再也不次感謝大俠(極光技術人員)對個人幫助,雖然這一年沒有繼續接觸推送的業務,可是當我遇到困惑依然有問必答,服務態度無可置疑!android
在準備參加徵文時就在想應該從哪一個角度來寫呢,正好以前跟前同事一塊兒寫了一個開源項目 WeaponApp, 如今已經有 800+ 的 star 了。git
裏面涉及的技術我就不一一闡述了,感興趣的話能夠自行看一下,裏面有一個模塊由我單獨負責- IM模塊,由於已經集成了極光推送,考慮到成本和使用,最終選擇了極光IM,畢竟是以極光推送的大規模、高併發、穩定的推送爲技術基礎,並繼承這些特性。那這篇文章就以我集成的經歷和使用作個介紹,快速的實現具備 IM 功能的 APP。github
這裏只對 IM 模塊功能作簡單的演示,感興趣能夠點擊 連接 進行下載,以下 gif 圖:數據庫
基本的聊天功能已經實現,其中包括:服務器
後續會根據須要添加新的功能。微信
由於前項已經集成了極光推送服務,不少東西已經不須要重複操做,只須要將 JMessage 相關的組件集成到項目中便可,詳情的步驟可直接參考官網。併發
1. 導入jmessage jar 包 2. 在 AndroidManifest 中添加相應的事件app
沒了。。由此能夠看出,由推送到 IM 過渡是多麼流暢!ide
其實在使用的過程,無非是根據本身的業務需求,到 官網 查找 API 來實現本身想要的功能,那我就根據目前項目中有的功能進行介紹。
這實際上是用戶的信息管理,極光 IM 統一用 UserInfo
進行管理,內部包含了用戶的大部分信息:
protected long userID;
protected String userName;
protected String nickname = "";
protected String avatarMediaID;
protected String birthday = "";
protected String signature = "";
protected String gender = "";
protected String region = "";
protected String address = "";
protected String appkey = null;
protected String notename = null;
protected String noteText = null;
protected int mTime;
protected Map<String, String> extras = new ConcurrentHashMap();
複製代碼
1. 註冊
一開始打算本身寫用戶服務器,事實上倒是由另外一位開發者完成了,可是考慮到 IM 的集成,用戶數據的遷移和轉存過程繁瑣,就乾脆直接用極光的用戶接口,其實內部的數據也確實很詳細,還支持自定義字段,徹底知足平常需求。
JMessageClient.register(userName, password, new JMessageCallBack() {
@Override
public void onSuccess() {
registerSuccess(userName);
}
@Override
public void onFailed(int status, String desc) {
registerFailed(desc);
}
});
複製代碼
註冊須要用戶名和密碼,註冊成功後經過 setResult
的方法,將帳戶和密碼傳回登陸頁面。
2. 登陸
JMessageClient.login(userName, password, new JMessageCallBack() {
@Override
public void onSuccess() {
loginSuccess(userName);
}
@Override
public void onFailed(int status, String desc) {
loginFailed(desc);
}
});
複製代碼
同註冊同樣,登陸也須要用戶名和密碼進行登陸,若是格式有誤會直接觸發 onFailed
回調,彈出相應的提示。成功後本地便會保存一個 UserInfo
對象儲存用戶的信息。
3. 退登
極光支持主動退出帳號的功能,即:
JMessageClient.logout();
複製代碼
直接清除本地保存的用戶信息,一樣他支持多端同時在線:
若是不打開開關,另外一臺設備登陸,會用 EventBus
發送 LoginStateChangeEvent
,告知開發者改帳號已在另外一臺設備登陸,而且會攜帶三種狀態:
case user_password_change:
forcedExit("帳號密碼被修改");
break;
case user_logout:
forcedExit("帳號在另外一臺設備登陸");
break;
case user_deleted:
forcedExit("帳號被刪除");
break;
複製代碼
根據本身的須要進行處理。
1. 我的
本身的用戶信息實際上是保存在本地的數據庫中,經過調用:
mUserInfo = JMessageClient.getMyInfo();
複製代碼
獲取用戶信息,以前提過 UserInfo
裏面包含了用戶的全部數據。與之對應的:
JMessageClient.updateMyInfo(UserInfo.Field.gender, mUserInfo, new JMessageCallBack() {
@Override
public void onSuccess() {
}
@Override
public void onFailed(int status, String desc) {
}
});
複製代碼
這個就是修改本身信息的方法,經過傳入 UserInfo.Field
來區分修改屬性值。
2. 他人
若是須要查看好友的信息,可經過 userName
進行請求查詢:
JMessageClient.getUserInfo(userName, new GetUserInfoCallback() {
@Override
public void gotResult(int status, String desc, UserInfo userInfo) {
if (status == 0) {
getViewModel().setUserInfo(userInfo);
} else {
getViewModel().setError(desc);
}
}
});
複製代碼
具體的結果以下:
若是是我的信息,直接能夠修改和退登,若是是他人只能查看並與其進行聊天。
終於到了核心的聊天功能,其實實現起來並不複雜,極光 IM 已經給了豐富的 API 和使用說明,足夠完成基本的需求。
1. 發消息
發消息,前提是須要構建 Message
對象,以基礎文本爲例:
final Message message = mConversation.createSendTextMessage(sendContent);
message.setOnSendCompleteCallback(new BasicCallback() {
@Override
public void gotResult(int status, String desc) {
if (status == 0) {
// 消息發送成功
MobclickAgent.onEvent(getContext().getApplicationContext(), "send_message", sendContent);
addSendMessage(message);
++curCount;
setSendContent("");
getView().scrollToPosition(items.size() - 1);
} else {
// 消息發送失敗
Toast.makeText(getContext(), desc, Toast.LENGTH_SHORT).show();
}
}
});
JMessageClient.sendMessage(message);
複製代碼
最終經過 JmessageClient.sendMessage(message)
將消息發送出去。
2. 接收消息
他這裏比較簡單粗暴,直接使用 EventBus
進行消息接收的回調。
他 jar 裏集成了 EventBus,項目中也有了 EventBus,這一點仍是蠻坑的。換想一下,這裏也是爲了方便接收,否則會有不少相互應用,各類耦合,不過使用過 EventBus 的小夥伴,應該知道,若是維護很差 EventBus 會致使邏輯很是的混亂,維護和拓展異常困難。
* 接收消息事件
* 目前只支持文字消息,後面再進行優化
*
* @param event 消息事件
*/
public void onEventMainThread(MessageEvent event) {
Message message = event.getMessage();
switch (message.getContentType()) {
case text:
// 處理文字消息
String userName = ((UserInfo) message.getTargetInfo()).getUserName();
if (TextUtils.equals(userName, mUserName)) {
// 當收到的消息是官方消息才進行更新UI
getViewModel().receiveMessage(message);
}
default:
LogUtils.i("office", message.getFromType());
break;
}
}
複製代碼
根據 contentType
區分消息實體的類型,並作相應的處理。 在須要接收消息的地方進行事件的註冊和取消註冊。
JMessageClient.registerEventReceiver(this, 200);
JMessageClient.unRegisterEventReceiver(this);
複製代碼
3. 單聊
這裏引入一個 Conversation
概念,當你與他人聊天必然會創建會話,那會話的消息和聊天的對象都會存在這個會話中,那單聊則經過傳入 userName
進行聯繫,因而可知 userName
的惟一性和重要性。
由於剛進去須要獲取歷史信息,因此經過 conversion
獲取全部的消息,並展現在界面上。
mConversation = Conversation.createSingleConversation(userName);
JMessageClient.getUserInfo(userName, this);
if (mConversation == null) {
getView().finish();
}
// 獲取本地全部的消息
msgCount = mConversation.getAllMessage().size();
List<Message> messagesFromNewest = mConversation.getMessagesFromNewest(curCount, LIM_COUNT);
curCount = messagesFromNewest.size();
// 第一條消息是正序的,須要反轉一下
Collections.reverse(messagesFromNewest);
for (Message message : messagesFromNewest) {
MessageDirect direct = message.getDirect();
if (direct == MessageDirect.send) {
addSendMessage(message);
} else {
addReceiverMessage(message);
}
}
複製代碼
4. 羣聊
羣聊與單聊有點相似,不過創建會話的前提參數不是 userName
, 而是 groupId
羣的惟一標識 ID。
mConversation = Conversation.createGroupConversation(groupId);
if (mConversation == null) {
getView().finish();
return;
}
List<Message> messagesFromNewest = mConversation.getMessagesFromNewest(curCount, LIM_COUNT);
curCount = messagesFromNewest.size();
Collections.reverse(messagesFromNewest);
for (Message message : messagesFromNewest) {
MessageDirect direct = message.getDirect();
if (direct == MessageDirect.send) {
addSendMessage(message);
} else {
addReceiverMessage(message);
}
}
複製代碼
具體的代碼很類似,只是建立的過程不同,再也不贅述。
前段時間王欣、字節跳動等都推出社交軟件,不過在微信平臺被封殺,這點仍是蠻狠的,不過另外一方面反映出社交 聊天在各個行業應用的普遍,不管是金融、教育、銷售等軟件都須要一個 IM 做爲用戶與用戶、用戶和平臺之間的溝通橋樑,所以做爲開發者,仍是要多多學習一下 IM 相關的知識。固然本身能獨立完成最好,若是沒有經歷或者暫時能力不夠,又或者公司急切須要集成 IM 功能,建議你能夠考慮極光 IM 服務,其推送服務作得仍是蠻不錯的,並且還在不斷的維護迭代中,有時間不妨嘗試一波吧!
本文爲極光徵文參賽文章