距离上次极光征文不知不觉已通过了将近一年的时间,先感谢上次的征文比赛,经过 《我和 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 服务,其推送服务作得仍是蛮不错的,并且还在不断的维护迭代中,有时间不妨尝试一波吧!
本文为极光征文参赛文章