公司要求Ionic App提供基本的成员聊天功能,在比较几家即时通讯服务提供商后,选择了融云,很大一部分原因是因为融云提供了Cordova插件,降低了开发的成本和周期。
融云基础
优势与缺点
- Cordova插件,使用JS便可以使用全部功能。
- Cordova Demo代码不清晰,文档不够详细。Android文档详细很多。
- 社区不够活跃,相比之前集成极光推送,社区活跃度没法比。
连接与重连机制
connect失败
- 很多时候出现connect融云服务器失败的情况,其实也不是失败,就是回调函数不执行,融云服务器没有给我返回结果,因此不知道是成功还是失败。这种情况下,调用融云的其他Api就会报错。
- connect() 方法在整个应用只需要调用一次,且必须在主进程调用。如果连接失败, SDK 会自动启动重连机制,进行最多10次重连,分别是1, 2, 4, 8, 16, 32, 64, 128, 256, 512秒后。如果仍然没有连接成功,还会在检测网络状态变化时再次重连。应用不需要做额外的重连操作。
- connect() 方法的回调仅在调用时回调一次,后续 SDK 的连接状态发生变化时,不会再通过 connect() 的回调返回,而是通过您设置的连接状态监听器获得。
reconnect & disconnect
- reconnect:不需要传入token(必须在connect之后才能执行触发),token已在初次connect缓存了 。
- 连接成功之后断开连接的方法,正如您所说和connect匹配使用,但是也可以在reconnect成功后,执行disconnect,总之要保证是连接状态下来执行disconnect
- 融云SDK在断开后有自动重连机制,reconnect是需要强制重连的时候调用的。
掉线问题
- 如果用户出现网络波动,有网-无网-有网,会重新建立连接吗?
融云 SDK 中已经为开发者做了断网重连的机制处理,开发者不必在断网后做连融云服务器的操作。 在网络连接断开后,融云会尝试 5 次重新连接服务器,首次断网 2 秒后会重新连接,如果仍然连接不成功,会在 4 秒后(重连间隔时间为上次重连间隔时间乘 2 )尝度重新连接服务器,以此类推当尝试重连 5 次后,仍然连不上服务器将不在尝试重新连接,只有在网络情况发生变化或重新打开应用时才会再次尝试重连。 - 是否需要自己编写掉线重连机制呢?
一般情况下不建议这么做,融云SDK自带重连机制,融云服务器如果频繁连接,可能会拒绝连接!
应用标识
- 应用标识是为了我们的 API 能够正确识别并验证您的应用请求而所必要的信息,对于防止账户盗用和滥用有着重要的作用。针对 Android 平台,需要填写包名即 Package Name,就是在 AndroidManifest.xml 中的 package 属性值。
- 如果您只是采用开发环境 App Key / Secret 进行测试开发,暂时不需要填写相关信息;但是您在提请应用上线前必须完善应用配置信息,否则无法提请上线。
- 请务必确保您填写的包名即 Package Name 信息和您应用程序包中的信息一致。上线后,每次连接我们都将会验证这个信息,如果信息不一致,服务端将会拒绝接受连接,您的 App 将无法使用融云的相关服务。
发布正式版
如果项目没有发布到正式版,会有人数的限制,项目上线必须也将融云发布到正式版才不会有这种问题,发布到正式版时注意事项如下:
- 必须修改插件下plugin.xml下的RONG_CLOUD_APP_KEY的值修改为融云提供的key;记住直接在项目下修改必须重新rm and add platform,或者重新安装插件。
- 客户端和服务端都换成生产环境的 appkey 和 appsecret 。
- 所有的之前测试项目生成的token,必须删除重新生成。
- platform有些开发环境需要配置,具体见:https://github.com/rongcloud/cordova-plugin-rongcloud-im-demo
融云初始化
如果没有初始化完成就调用connect的话,那么就会报-10000的错误,最保险的做法就是在成功init的回调函数中进行connect连接。
初始化一般有4个执行步骤。
- RongCloudLibPlugin.init
- RongCloudLibPlugin.setConnectionStatusListener
- RongCloudLibPlugin.connect
- RongCloudLibPlugin.setOnReceiveMessageListener
init和connect是异步执行的,而setConnectionStatusListener和setOnReceiveMessageListener设置监听是同步的,回调函数时用来在监听被触发时进行处理,因此我们在init的回调中执行setConnectionStatusListener和connect,状态监听要在连接之前,这样才有效果,而设置消息监听要在connect成功的回调函数中处理。
IMKit VS IMLib
- IMKit:集成简单,不需要您去重新绘制会话列表、会话界面,输入法等。也不需要您去处理各种业务了解。适合于对会话聊天定制需求很规范的产品。
- IMLib:不含界面的基础 IM 通讯能力库,封装了通信能力和会话、消息等对象。引用到 App 工程中后,需要开发者自己实现 UI 界面,相对较轻量,适用于对 UI 有较高订制需求的开发者。
常见问题
官方不维护导致问题
编译报错 initWithWebView
很难受,刚夸它提供Cordova开发的支持,最近重新研究时,却发现他doc没有cordova的入口了,github插件也不更新维护了,Cordova模块的工单都不受理了,由于Cordova-ios版本的更新,编译报错。
查阅资料得到在cordova-ios版本4.0以后,插件的初始化方法initWithWebView便遭到抛弃,需要使用pluginInitialze方法,无奈对object-c完全小白,参考极光推送插件,修改RongCloudLibPlugin.m,注释本身initWithWebView方法,添加如下代码:
ifdef __CORDOVA_4_0_0
- (void)pluginInitialize {
NSLog(@"### pluginInitialize ");
[self init];
if (self) {
self.appEventReceiver = [[RongCloudAppEventReceiver alloc] init];
}
}
#else
- (CDVPlugin*)initWithWebView:(UIWebView*)theWebView{
NSLog(@"### initWithWebView ");
if (self=[super initWithWebView:theWebView]) {
}
self = [super init];
if (self) {
self.appEventReceiver = [[RongCloudAppEventReceiver alloc] init];
}
return self;
}
#endif
Android 7.0奔溃
奔溃的原因是7.0以后,Andorid不允许直接访问系统的私有so文件了。由于融云官方不维护了,不然不会出现此问题。
解决办法:配置libsqlite.so文件
其他问题
得到回话
connect是一个异步操作,在没有连接成功的情况下,使用得到回话的API结果为NULL。
安卓正常,IOS报-10002错误
解决办法:由于IOS对数据要求比较严格,targetId需要转换成String类型才可以。
推送的标题是用户ID
在应用处于后台时,融云会采用的推送的方式,但是推送的标题是用户的ID,这对于应用体验来说很不好,查询融云server文档,发送消息的时候携带用户信息,这样通知的标题也就可以自定义了。
media插件修改
- 发送语音信息需要用到了 cordova-plugin-media ,这个插件需要在 android 和 ios 的源码中修改几个参数 ,具体 前往这里:media参数修改。
- 每次重新添加平台都要修改,因此直接修改media插件源码,但是如果更新此插件需要注意修改!
头像问题
本不该属于此处内容,但由于头像问题,用户自主上传非正方形图片,导致聊天界面头像长宽比不一致,从而影响美观,那么如何限制头像为正方形呢,通过cordova-plugin-camera
插件设置allowEdit
为true,可以允许用户自主裁剪,但是实际操作碰到如下问题:
- 在魅族手机上从图库选择图片会导致裁剪调用失败,从文件管理选择却是OK的。
- 研究魅族手机时,发现网友存在华为从图库选择图片失败的问题,但经测试,自己不存在这个问题,不知道是插件还是手机系统迭代解决了。图库获取报错
录音报错code:1
在Android 6.0的机型上,会动态申请录音权限,申请完权限之后创建Media对象就会报错,但是App重启后不再动态请求权限时,却不存在这个问题。神奇就在这里,一度怀疑是插件本身问题或是插件冲突问题,但经理使用Ionic2写的Demo却没有这个问题,自己使用Ionic1将核心代码从项目抽离,仅安装media和file两个插件,却依旧存在问题,真是想破脑袋。
项目上使用on-hold事件开始录音,使用on-release事件结束录音并发送,意外的发现不调用on-release事件方法时,创建对象竟然不报错,对比项目经理的Demo,他使用的是Ionic2才有的press和pressup事件,那么怎么办呢?想到touchend事件,可以实现类似的功能。因此做了如下尝试:
- 使用touchstart和touchend事件,奇怪的是touchstart事件触发, 但touchend事件竟然没有触发。
- 使用hold和touchend事件,但是申请权限点击同意结束后,touchend事件不触发,导致录音进行时样式无法取消。
- 使用hold、touchend和release事件三者配合使用,因为release事件在同意权限时仍然会触发,在release事件中用来取消样式,结果竟然可以了!备注:touchend事件比release先触发。
虽然问题解决了,但是总觉得不放心,不知道问题产生的原因实在很恐怖,也不知道问题是不是真正解决了!
融云踢人
登录功能的重要性:每次init的时候必须确定当前用户没有已经登录成功,或者会持续报错,且不能连接上服务器,不要用同一个token连接多次。
在项目中,我们会出现如下两种情况会踢别人下线。
- 同一个账号登陆,第二次登录时会监听到重复登录的事件,但仅仅是事件,融云并不会将当前登录用户信息在服务器上清除,因此需要自己写逻辑。这里特别需要注意的事,并不能简单跳转至登录页面,必须 logout,否则当前客户端再次登录,融云就会init或者connect失败,同时在nodeJs中执行disconnect事件,移除用户。如果项目中加入了掉线重连操作,这种情况需要判断一下,防止互相挤。
- 一个用户已经登录,但是网络断开了,此时执行了disconnect的逻辑,但是融云服务器上的对象并没有清除,然后另一个用户在他断线期间登录了,之前用户网络恢复时,可以把新用户踢下线。这里有一个问题就是,强烈建议在用户网络断开的情况下执行logout函数,或者同一客户端再次连接很有可能不能初始化融云成功。
- 备注:融云的状态监听踢人下线,是执行init时才触发,而不是从服务器获取token时触发。
奇怪问题
在IOS中,获取会话的回调函数中异常会导致下一次回调函数不会被执行。