扯淡下:
好久没有更新文章了,连续工作了9个小时,拖着疲惫的身体,对环信接入中遇到的一些坑以及经验做一个总结。
说到第三方你可能会想,那多简单啊?人家做好好的东西接入不就好了吗?比如像glide那样直接就可以使用了。 是的,一开始我也是这么认为的,但是没有一个第三方的东西是完全符合需求的。除非你的项目很赶不需要任何修改。然而任何第三方的东西包括glide4.0、dbflow都会面临着文档的升级以及部分api的修改,况且Android手机更新换代特别快,市场上的Android手机定制的特别多特别杂。我相信没有任何一家公司敢拍着胸脯说自己的东西兼容所有机型。
废话不说,我们进入正题。我们使用easyui 作为接入方式。个人认为这样有个好处:可以更加灵活的修改成我们想要的样式以及更加符合的需求但是文档讲述的东西比较少问题也有不少
总结下几个点:
1下载导入
可以去下载第二个包括一个demo以及easeui.然后我们的项目就可以依赖他的easeui作为库。
注意的是:easeui的module里面是不包含所需的jar包的,不过这些jar可以在demo里面拷贝出来
2初始化
这是官网的初始化的方式,然而不知道为什么对easeui的导入方式并没有做真正的介绍。所以需要修改一下的方式
可以看到初始化由 EMClient变成了EaseUI
3注册环信
注意点:环信注册的时候只看用户名,不管密码是否修改,都默认已经注册,错误码:203.所以在真实开发中一定要结合自己的登录接口做处理
4 Android6.0以上 权限动态申请
注意点:只要你是做开发的就一定记得这个坑。因为聊天中包涵了拍照,录音等都会用到权限。然后环信的api并没有说道这一点,所以在接入的时候一定是会出错的。
5 拍照闪退
我就纳闷了:没有做任何修改,聊天的页面一开始我也是没有经过重写的。为什么点击原版的拍照图标就给我闪退呢?
注意点:首先根据第四点,权限的申请者是一个坑,另外一个还是Android手机兼容性的问题。
没办法,谁让我们用的是别人的东西。只能去看源代码了。定位到代码的位置
EaseChatFragment类下的selectPicFromCamera方法中:
然而到了Android N (7.0)相关的api的修改了,所以代码要修改成
6 不能发送定位
这个其实不算是环信的坑,因为点击发送位置的时候很明显的提示我们
做过定位的都知道,这个时候我们需要去百度开发者中心注册应用并得到appkey,然后配置到AndroidMenifest.xml文件中
7 查看聊天记录中的图片大图的时候闪退
坑爹又一个闪退,不过Android studio很友好的提示我们相应的Activity没有注册。于是乎我们去查看了demo中的配置文件,把相应的Activity注册了。这还没完,查找的过程中发现其实还有几个相关类没有注册。
所以干脆都注册了,免得以后夜长梦多。
8 添加表情
原版中的表情丑的我力吐槽,不过环信2014年开始做,表情旧点可以理解。不过个人认为还是需要更新下吧?毕竟qq 微信都更新了很多了。
那么怎么在聊天界面中添加一组表情包呢?
通过官方文档我们可以看到。输入框及里面的表情等等都是属于 EaseChatInputMenu 而我们可以看到 EasEmojiconMenu正是我们想要的界面。
可以看到 源码中提供了一个添加表情组的方法。我们只需添加一个EaseEmojiconGroupEntity对象就行了。那么这个对象要怎么写呢? 方法还是有的。为什么呢? 很简单:源码中默认不是有表情吗? 我们去easeui的drawable包中就一定能找到相应的图片,然后找到他使用的类不就可以得到官方的表情包类了吗?
果然猜的没错,但是等下,这个东西返回的类型不一样啊。于是乎查看了 EaseEmojicon这个类,果然不出所料和EaseEmojiconGroupEntity一定存在关系。(别问为什么,我也不知道。代码研究多了可能会有种直觉吧。好了不装逼,如果非要说原因:因为他们都是表情包中使用的EaseEmojicon从名字上就 感觉是表情基本类,EaseEmojiconGroupEntity看起来是表情组类。所以他们存在对应关系)而源码中提现了他们确实是对象和集合的关系。
参考下其他代码,经过修改
然后在chatFragment中添加。
重点:如何设置头像和昵称
当你根据环信的官方文档做好接入使之可以正常的聊天,但是这个时候你会发现,聊天界面中并没有正确使用头像和昵称。无论是IOS还是安卓,集成环信SDK遇到的第一个问题,就是如何显示自有用户体系中的昵称和头像。运行环信的demo app,注册用户是直接使用环信ID(username)作为用户名,但是在我们实际应用中,需要将自有用户体系的UserId生成GUID作为环信ID(username)、这时候如果不经过处理,则会显示如下界面:
那么要怎么设置头像和昵称呢? 实际上官方文档也已经给出了方法:
方法一:从APP服务器获取昵称和头像
昵称和头像的获取:当收到一条消息(群消息)时,得到发送者的用户ID,然后查找手机本地数据库是否有此用户ID的昵称和头像,如没有则调用APP服务器接口通过用户ID查询出昵称和头像,然后保存到本地数据库和缓存,下次此用户发来信息即可直接查询缓存或者本地数据库,不需要再次向APP服务器发起请求。
昵称和头像的更新:当点击发送者头像时加载用户详情时从APP服务器查询此用户的具体信息然后更新本地数据库和缓存。当用户自己更新昵称或头像时,也可以发送一条透传消息到其他用户和用户所在的群,来更新该用户的昵称和头像。
方法二:从消息扩展中获取昵称和头像
昵称和头像的获取:把用户基本的昵称和头像的URL放到消息的扩展中,通过消息传递给接收方,当收到一条消息时,则能通过消息的扩展得到发送者的昵称和头像URL,然后保存到本地数据库和缓存。当显示昵称和头像时,请从本地或者缓存中读取,不要直接从消息中把赋值拿给界面(否则当用户昵称改变后,同一个人会显示不同的昵称)。
昵称和头像的更新:当扩展消息中的昵称和头像 URI 与当前本地数据库和缓存中的相应数据不同的时候,需要把新的昵称保存到本地数据库和缓存,并下载新的头像并保存到本地数据库和缓存。
详细文档参考:http://docs.easemob.com/im/490integrationcases/10nickname
鉴于实际情况,我使用第一种方式。
第一种设置方式参考:http://www.imgeek.org/article/825308757
那么好,我们就开始跟他一步一步做:
1、将简版demo里的cache包(5个java文件)复制到自己项目里。
下载环信android简版Demo:
昵称头像用到的工具类、model都在这个cache包里。
类介绍:
拷贝进去,好吧一堆错误。忍了,继续往下。
2.增加第三方依赖库。根目录下的 build.gradle 下:
compile 'com.j256.ormlite:ormlite-android:5.0'
compile 'com.google.code.gson:gson:2.8.0'
ormlite:操作sqlite数据库
gson:json对象转换
好吧,看到这个我就知道要蛋疼了。数据库使用的是 ormlite 而我使用的是性能相对更好的 dbflow.。不过继续忍了。
3.设置用户信息提供者:
在DemoHelper.java的getUserInfo函数里(第824行)增加如下代码:
环信头像昵称显示使用的是提供者模式(EaseUserProfileProvider),只要设置了用户信息提供者(setUserProfileProvider),EaseUI界面里显示用户昵称和头像时,就会调用这个getUserInfo函数。
并且注释之前获取昵称头像的方法:
然后,根据不同的方案,开发者可以选择不同步骤:
从开发者自己的APP服务器获取的步骤:
将UserCacheManager.java中第54行-62行代码,换成:通过okhttp(或者retrofit、volley)调用api接口,根据用户环信ID,从开发app服务器获取用户昵称头像。下面两张图是改之前和改之后的效果:
改之前(用第三方云存储):
改之后(用开发者自己服务器):
通过以上的介绍我们可以知道,除了一开始是5个类,最最重要的就是DemoHelper这个类。好吧一起copy进去。
这个时候估计你我都疯了,因为没有一类是对的。都是报红,这个时候怎么办呢?这个时候我们就应该研究源码了。前面我们也说了,第三方的东西需要根据具体的需求做修改。
暂时先不修改那些代码,细心的你也许发现了一句话:环信头像昵称显示使用的是提供者模式(EaseUserProfileProvider),只要设置了用户信息提供者(setUserProfileProvider),EaseUI界面里显示用户昵称和头像时,就会调用这个getUserInfo函数。
重点就在这个EaseUserProfileProvider. 我们将代码定位
上文也说了:环信头像昵称显示使用的是提供者模式EaseUserProfileProvider。所以此时我们将代码定位到getUserProfileProvider的调用者。
咦,我们惊喜的发现了设置头像和昵称的方法,以设置头像为例:
通过getUserInfo的方法获取对象然后设置头像。
所以正如官方文档说的我们只要设置setUserProfileProvider这个方法就可以在聊天的时候设置进去头像和昵称。
所以我们在demo中可以看到DemoHelper设置了setUserProfileProvider这个方法。然后我们继续定位 getUserInfo(username)的方法,一步步进去。(这里我就不一一截图了)
你会发现原来这里做的实际就是缓存用户信息,如果数据不存在或者过期了则就去服务器获取,所以一开始它使用了 ormlite数据库做数据的缓存,用第三方云存储做为服务器。
那么好!知道了他的原理,老子再也不会被牵着鼻子走了。
这五个类,真正使用到的
1 UserCacheInfo类作为数据表类
改为
2 UserCacheManager数据库操作
这里打个岔:从代码量以及真正的功能点上,个人强烈推荐使用dbflow作为数据库框架。关于dbflow的详细介绍与使用请查看本人的另一篇日志。传送门:https://www.jianshu.com/p/431f12648da0
而对于DemoHelper这个类,实际上我可以删除大部分的代码,只要添加一个设置内容提供者的代码就行了
getUserInfo(username)就是返回的我们的缓存数据。
这里提一个严重而又低级的错误。 接口中的方法没人调用,那么这个方法是一定不会走的。因为文档中没有体现,我以为他的某些地方已经设置了,所以就没再去调用。然后一直调试断点结果死活不跑,就自然没有数据了。
针对以上的问题,我暂时使用的是自定义的联系人界面(使用recyclerview作为列表),所以只要在adapter中设置没个username的getUser方法即可
有人这个时候也许会说,说好的调用呢? 别急,都封装到相关的utils类里面。
自此,设置头像和昵称就已经做好了,网上的例子真的太多了,但是你也知道,百度上基本都是抄来抄去,而且好一点的也基本都是来之官方文档的代码。但是我的修改完全是一个精简版,将一些无用的代码完全删除,搞清楚他的原理之后做自己的修改。
总结:
环信的坑还是挺多的,但是功能都基本可以,并且收费标准也不是特别高。我们不能说他不好,这和Android本身的兼容性也有很大关系。如果是ios开发,我相信坑不会这么多。我们归咎于它的文档写得不好,希望有所改进吧。
任何第三方的东西如果想要改成自己想要的东西就一定要研究源码,而不是一味的按部就班,实行拿来主义。实际上,我完全可以不用研究这么多,既然demo中的代码都可以我为什么不能直接copy过来使用呢?这样做问题有二:1无用代码添加一堆会使项目显得庞大冗余, 2不利于自己的学习。