用户工具

android_sdk详解

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

android_sdk详解 [2017/08/23 08:44]
android_sdk详解 [2017/08/23 08:44] (当前版本)
行 1: 行 1:
 +======Android SDK详解 ======
 +云之讯建议开发者不仅要关心如何使用云之讯sdk,同时也需要理解云之讯sdk的架构设计和内部实现原理,这样方便开发者排查问题。要理解云之讯sdk,需要开发者具有一定的开发经验和编程基础。
 +===== 一、 架构设计 ​ =====
 +云之讯提供uikit sdk、im sdk、tcp sdk方便开发者调用,它们之间的关系可以用一幅图来表示:\\
 +{{  :​android_sdk_r.png?​nolink&​180 ​ }}
 +  * 1) TCP SDK:负责与服务器的交互,包括收发消息、断开与连接。
  
 +  * 2) IM SDK:负责消息的存储和转发。
 +
 +  * 3) UIKIT SDK:负责上层UI的展示和用户自定义界面。
 +这里以发送消息和收到消息为例,详解sdk之间的调用流程。\\
 +<​html><​span style="​font-size:​130%;">​发送消息流程:</​span></​html>​
 +{{  :​android_sendMessage_process.png?​nolink&​680 ​ }}
 +<​html><​span style="​font-size:​130%;">​接受消息流程:</​span></​html>​
 +{{  :​android_receiveMessage_process_01.png?​nolink&​680 ​ }}
 +===== 二、 会话与消息 ​ =====
 +会话与消息属于一对多关系,消息不可能脱离会话而单独存在。消息可以根据<​html><​font color = red>​targetId</​font></​html>​找到所属会话,会话也能通过<​html><​font color = red>​targetId</​font></​html>​获取到消息列表。会话记录的入库操作是<​html><​font color = red>​sdk</​font></​html>​自动完成的,当发送或者受到消息所属的会话不存在时会创建会话,否则只会更新会话。\\
 +对于发送消息来讲,只有<​html><​font color = red>​sendMessage</​font></​html>​函数返回成功之后才会将消息记录入库。如果该消息所属会话不存在会创建会话,否则只会更新会话。待收到发送结果之后,会更新消息发状态和会话,同时回调下面两个函数:
 +  * 1) <​html><​font color = red>​onSendMsgRespone</​font></​html>​:将已经更新好的消息回调给开发者。
 +
 +  * 2) <​html><​font color = red>​onUpdateConversation</​font></​html>​:将已经更新好的会话(该会话可能是创建也有可能是更新)回调给开发者。
 +对于接收消息来讲,<​html><​font color = red>​sdk</​font></​html>​收到新消息自动将消息记录入库,如果该消息所属会话不存在会创建会话,否则只会更新会话,同时回调下面两个函数:\\
 +  * 1) <​html><​font color = red>​onReceiveMessage</​font></​html>​:将收到的消息回调给开发者。
 +
 +  * 2) <​html><​font color = red>​onUpdateConversation</​font></​html>​:将已经更新好的会话(该会话可能是创建也有可能是更新)回调给开发者。
 +<​html><​span style="​font-size:​130%;">​会话与消息更新流程:</​span></​html>​
 +{{  :​messageAndCon_update_01.png?​nolink ​ }}
 +====  1、消息体系 ​ ====
 +消息与会话属于多对一关系,云之讯为了区分不同会话类型的消息,将消息又分为<​html><​font color = red>​SingleChat</​font></​html>​(单聊消息)、<​html><​font color = red>​DiscussionChat</​font></​html>​(讨论组消息)、<​html><​font color = red>​GroupChat</​font></​html>​(群组消息)。开发者在发送消息时,应该可以根据会话类型创建不同的消息发送,也可以创建<​html><​font color = red>​ChatMessage</​font></​html>​通过<​html><​font color = red>​setCategoryId</​font></​html>​标识消息类型再发送,关系图如下:
 +{{  :​messageAndCon_r_01.png?​nolink&​220 ​ }}
 +====  2、发送消息 ​ ====
 +在发送消息之前,开发者得新建一个消息对象,然后在调用云之讯<​html><​font color = red>​sdk</​font></​html>​的<​html><​font color = red>​sendMessage</​font></​html>​方法发送,以下是两种新建消息对象的方法:\\
 +<​html><​span style="​font-size:​130%;">​方法一:</​span></​html>​
 +<code java>
 +/**
 + * 根据会话类型创建不同的消息
 + */
 +ChatMessage msg = null;
 +switch (conversationinfo.getCategoryId()) {
 +case PERSONAL:
 +  /**
 +   * 创建单聊消息
 +   */
 +  msg = new SingleChat();​
 +  break;
 +case GROUP:
 +  /**
 +   * 创建群聊消息
 +   */
 +  msg = new GroupChat();​
 +  break;
 +case DISCUSSION:
 +  /**
 +   * 创建讨论组消息
 +   */
 +  msg = new DiscussionChat();​
 +break;
 +}
 +</​code>​
 +<​html><​span style="​font-size:​130%;">​方法二:</​span></​html>​
 +<code java>
 +/**
 + * 根据会话类型创建不同的消息
 + */
 +ChatMessage msg = new ChatMessage();​
 +switch (conversationinfo.getCategoryId()) {
 +case PERSONAL:
 +  /**
 +   * 设置消息类型为单聊
 +   */
 +  msg.setCategoryId(CategoryId.PERSONAL);​
 +  break;
 +case GROUP:
 +  /**
 +   * 设置消息类型为群聊
 +   */
 +  msg.setCategoryId(CategoryId.GROUP);​
 +  break;
 +case DISCUSSION:
 +  /**
 +   * 设置消息类型为讨论组
 +   */
 +  msg.setCategoryId(CategoryId.DISCUSSION);​
 +  break;
 +}
 +</​code>​
 +1) 发送文本消息
 +<code java>
 +msg.setTargetId("​接收方userId"​);​
 +msg.setNickName("​发送方昵称"​);​
 +msg.setSenderId("​发送方userId"​);​
 +msg.setMsgType(MSGTYPE.MSG_DATA_TEXT);​
 +msg.setContent("​消息内容"​);​
 +msg.setFromMyself(true);​
 +IMManager.getInstance(mContext).sendmessage(msg)
 +</​code>​
 +2) 发送语音消息
 +<code java>
 +msg.setTargetId("​接收方userId"​);​
 +msg.setNickName("​发送方昵称"​);​
 +msg.setSenderId("​发送方userId"​);​
 +msg.setMsgType(MSGTYPE.MSG_DATA_VOICE);​
 +msg.setContent("​语音时间(如30)"​);​
 +msg.setPath("​语音文件路径"​);​
 +IMManager.getInstance(mContext).sendmessage(msg)
 +</​code>​
 +3) 发送图片消息
 +<code java>
 +msg.setTargetId("​接收方userId"​);​
 +msg.setNickName("​发送方昵称"​);​
 +msg.setSenderId("​发送方userId"​);​
 +msg.setMsgType(MSGTYPE.MSG_DATA_IMAGE);​
 +msg.setContent("​要显示在页面的内容(如:图片)"​);​
 +msg.setPath("​图片文件路径"​);​
 +IMManager.getInstance(mContext).sendmessage(msg)
 +</​code>​
 +4) 发送地图消息
 +<code java>
 +/**
 + * 构造地图对象。
 + *
 + * @param latitude ​              ​地图经度。
 + * @param longitude ​             地图纬度。
 + * @param detailAddr ​            ​详细地址。
 + * @param thumbnailPath ​         地图截图路径。
 + */
 +LocationMapMsg locationMsg = new LocationMapMsg(latitude,​ longitude, detailAddr , thumbnailPath); ​
 +msg.setTargetId("​接收方userId"​);​
 +msg.setNickName("​发送方昵称"​);​
 +msg.setSenderId("​发送方userId"​);​
 +msg.setMsgType(MSGTYPE.MSG_DATA_LOCALMAP);​
 +msg.setContent("​要显示在页面的内容(如:地图)"​);​
 +msg.setLocationMapMsg(locationMsg);​
 +IMManager.getInstance(mContext).sendmessage(msg)
 +</​code>​
 +5) 发送自定义消息
 +<code java>
 +/**
 + * 构造自定义对象。
 + *
 + * @param data                要发送字节数组。
 + * @param length ​             字节数组长度。
 + */
 +CustomMsg customMsg = new CustomMsg(data,​ length);
 +msg.setTargetId("​接收方userId"​);​
 +msg.setNickName("​发送方昵称"​);​
 +msg.setSenderId("​发送方userId"​);​
 +msg.setMsgType(MSGTYPE.MSG_DATA_CUSTOMMSG);​
 +msg.setContent("​要显示在页面的内容(如:自定义消息)"​);​
 +msg.setCustomMsg(customMsg)
 +IMManager.getInstance(mContext).sendmessage(msg)
 +</​code>​
 +===== 三、 设置监听 ​ =====
 +云之讯为了方便开发者能随时监听<​html><​font color = red>​sdk</​font></​html>​的状态,提供了各式各样的监听回调,开发者需要根据自己的业务需求设置自己关心的回调事件,所有的设置监听事件都由<​html><​font color = red>​IMManager</​font></​html>​控制类完成,​这里需要注意的是:所有的监听回调都运行在<​html><​font color = red>​子线程</​font></​html>​,开发者不应该在回调里面直接更新UI。
 +====  1、设置发送回调 ​ ====
 +<code java>
 +IMManager.getInstance(context).setSendMsgListener(new MessageListener(){
 +        @Override
 + public void onSendMsgRespone(ChatMessage msg) {
 +          /**
 +           * 发送消息结果回调,开发者应该更新发送状态
 +           */
 +          if(msg.getSendStatus() == ChatMessage.MSG_STATUS_SUCCESS){
 +            Log.i("​YZX","​发送成功"​);​
 +   }else{
 +     Log.i("​YZX","​发送失败"​);​
 +          }
 + }
 + @Override
 + public void onReceiveMessage(List msgs) {
 +          /**
 +           * 接收到新消息回调,开发者应该将msgs添加到当前的消息集合,并刷新界面
 +           */
 + }
 + @Override
 + public void onDownloadAttachedProgress(String msgId, String path, int totalSize,​int currentProgress) {
 +          /**
 +           * 开发者调用了downloadAttached()接口下载后,sdk会回调该方法
 +           */
 + }
 +    })
 +</​code>​
 +====  2、设置会话回调 ​ ====
 +云之讯<​html><​font color = red>​sdk</​font></​html>​在发送消息和收到消息时会更新会话,开发者需要设置会话回调,监听会话的更新、创建、和删除事件。
 +<code java>
 +IMManager.getInstance(context).setConversationListener(new IConversationListener() {
 +        @Override
 + public void onUpdateConversation(List conversations) {
 +          /**
 +    * 需要更新的会话集合,会话有可能是新创建的,有可能是更新的。
 +           * 开发者需要根据targetId匹配上层应用会话集合。
 +           * 如果targetId相同,则是更新会话,需要将sdk回调的会话替换掉上层应用的会话。
 +           * 如果targetId不同,则是新创建的会话,添加到上层会话集合。
 +    */
 + }
 + @Override
 + public void onUpdateConversation(ConversationInfo conversationInfo) {
 +          /**
 +    * nothing to do(兼容使用,开发者不用关心)
 +    */
 + }
 + @Override
 + public void onCreateConversation(ConversationInfo conversationInfo) {
 +          /**
 +    * nothing to do(兼容使用,开发者不用关心)
 +    */
 + }
 +        @Override
 + public void onDeleteConversation(ConversationInfo conversationInfo) {
 +          /**
 +    * 当删除并退出讨论组的时候,sdk会删除会话,同时回调该事件
 +    */
 + }    ​
 +});
 +</​code>​
 +====  3、设置sdk状态回调 ​ ====
 +开发者如果想监听<​html><​font color = red>​sdk</​font></​html>​的状态可以设置该回调,当<​html><​font color = red>​sdk</​font></​html>​状态发生改变时会回调该方法。
 +<code java>
 +IMManager.getInstance(context).setISdkStatusListener(new ISdkStatusListener() {
 +        @Override
 + public void onSdkStatus(UcsReason reason) {
 +          /**
 +    * sdk状态改变时回调,开发者可以通过reason.getReason()区分各个事件,下面是几种常见事件监听
 +    */
 +          if(reason.getReason() == UcsErrorCode.NET_ERROR_KICKOUT) {
 +            Log.i("​YZX","​服务器强制下线通知,账号在别处登录"​);​
 +   } else if(reason.getReason() == UcsErrorCode.NET_ERROR_TCPCONNECTOK){
 +            Log.i("​YZX","​连接服务器成功"​);​
 +          } else if(reason.getReason() == UcsErrorCode.NET_ERROR_TCPCONNECTFAIL){
 +            Log.i("​YZX","​连接服务器失败"​);​
 +          } else if(reason.getReason() == UcsErrorCode.NET_ERROR_TCPCONNECTING){
 +            Log.i("​YZX","​正在连接服务器"​);​
 +          } else if(reason.getReason() == UcsErrorCode.PUBLIC_ERROR_NETUNCONNECT){
 +            Log.i("​YZX","​网络断开"​);​
 +          } else if(reason.getReason() == UcsErrorCode.PUBLIC_ERROR_NETCONNECTED){
 +            Log.i("​YZX","​网络连接上"​);​
 +          }
 + }
 +});
 +</​code>​
 +===== 四、 工具说明 ​ =====
 +云之讯提供图片压缩、录音和播放、下载接口,方便开发者使用,开发者可以选择性使用云之讯<​html><​font color = red>​sdk</​font></​html>​提供的工具。
 +====  1、图片压缩 ​ ====
 +云之讯<​html><​font color = red>​sdk</​font></​html>​默认发送的图片不能超过20M,为了降低用户的流量,开发者需要将图片压缩后发送,这里云之讯提供了压缩接口方便使用。在使用前,开发者需要将下载的压缩包中libs目录下<​html><​font color = red>​libjpegbither.so</​font></​html>​和<​html><​font color = red>​libbitherjni.so</​font></​html>​文件,拷贝到自己工程的libs/​armeabi/​目录。
 +<code java>
 +/**
 + * 压缩图片并保存。
 + *
 + * @param src                     ​要压缩的图片源。
 + * @param quality ​                ​压缩的图片质量(0-100),100表示不压缩。
 + * @param savePath ​               压缩后图片保存路径。
 +*/
 +IMManager.compressBitmap(src,​quality,​savePath)
 +</​code>​
 +
 +====  2、录音和播放 ​ ====
 +开发者可以通过云之讯<​html><​font color = red>​sdk</​font></​html>​完成音频的录制和播放,设置<​html><​font color = red>​RecordListener</​font></​html>​监听录音完成和和播放录音完成,这里需要注意的是:<​html><​font color = red>​RecordListener</​font></​html>​回调运行在<​html><​font color = red>​子线程</​font></​html>​,开发者不应该在回调里面直接更新UI。
 +<code java>
 +/**
 + * 开始录音。
 + *
 + * @param savePath ​           录音文件保存路径,不能为空。
 + * @param recordListener ​     录音回调事件,不能为空。
 + */
 +IMManager.getInstance(context).startVoiceRecord(savePath,​new RecordListener() {
 +        @Override
 +        public void onFinishedRecordingVoice(int time) {
 +          /**
 +           * 调用stopVoiceRecord()方法后停止录音,sdk回调该事件返回录音时长
 +           */
 +          Log.i("​YZX","​录音时长:"​+time+"​秒..."​)
 +        }
 +        public void onFinishedPlayingVoice() {
 +          /**
 +           * nothing to do(录音不需要关注该方法)
 +           */
 +        }
 +})
 +/**
 + * 停止录音。
 + *
 + * 停止录音后,sdk会回调RecordListener的onFinishedRecordingVoice方法。
 + * 一般录音时长不超过60秒,开发者应该在60秒前调用stopVoiceRecord()停止录音。
 + */
 +IMManager.getInstance(context).stopVoiceRecord()
 +/**
 + * 开始播放录音。
 + *
 + * @param srcPath ​            ​录音文件路径,不能为空。
 + * @param recordListener ​     录音回调事件,不能为空。
 + */
 +IMManager.getInstance(context).startPlayerVoice(srcPath,​new RecordListener() {
 +        @Override
 +        public void onFinishedRecordingVoice(int time) {
 +          /**
 +           * nothing to do(播放录音不需要关注该方法)
 +           */
 +        }
 +        public void onFinishedPlayingVoice() {
 +          /**
 +           * 播放录音完成之后回调该方法。
 +           */
 +          Log.i("​YZX","​play voice  onFinished..."​)
 +        }
 +})
 +/**
 + * 停止播放录音。
 + *
 + */
 +IMManager.getInstance(context).stopPlayerVoice()
 +</​code>​
 +====  3、下载 ​ ====
 +为了方便开发者下载图片消息的原图,云之讯<​html><​font color = red>​sdk</​font></​html>​提供下载接口方便调用,可以通过<​html><​font color = red>​MessageListener</​font></​html>​监听下载进度和完成。
 +<code java>
 +/**
 + * 下载指定消息的文件,如某图片消息的原图。
 + *
 + * @param url                      文件url。
 + * @param savePath ​                ​文件要保存的路径。
 + * @param msgId                    消息id。
 + * @param messageListener ​         下载消息监听。
 + */
 +IMManager.downloadAttached(url,​savePath,​msgId,​new MessageListener(){
 +        @Override
 + public void onSendMsgRespone(ChatMessage msg) {
 +          /**
 +           * nothing to do(发送消息回调该事件)
 +           */
 + }
 + @Override
 + public void onReceiveMessage(List msgs) {
 +   /**
 +           * nothing to do(收到新消息回调该事件)
 +           */
 + }
 + @Override
 + public void onDownloadAttachedProgress(String msgId, String path, int totalSize,​int currentProgress) {
 +          /**
 +           * 下载进度更新,当currentProgress >= totalSize,下载完毕
 +           * 如果currentProgress == 0或者totalSize == 0下载失败
 +           */
 +   Log.i("​YZX","​文件总大小:"​+totalSize+"​,当前下载进度:"​+currentProgress);​
 + }
 +})
 +</​code>​
 +===== 五、 断线重连 ​ =====
 +开发者成功登录之后,不需要关心与服务器连接和断开,<​html><​font color = red>​sdk</​font></​html>​会自动重连,以下是<​html><​font color = red>​sdk</​font></​html>​断线重连机制:
 +| 重连场景 ​   ^  描述 ​                              ^
 +^ 传输数据时,连接不可用 ​   | 与服务器交互时,如果socket抛异常将会重连 ​       |  ​
 +^ 服务器或者路由断开连接 ​   | 服务器或者路由器判断当前连接无效,断开连接,sdk将会重连 ​       |
 +^ 心跳回执超时 ​   | sdk发送心跳之后,30秒没有收到服务器回执,sdk将会重连 ​                |
 +^ 网络切换 ​   | 断开网络之后,sdk将主动断开连接;网络链接成功之后,sdk将会重连。网络类型变化(如:3G切换到4G,移动网络切换到wifi网络等...),sdk也会重连。 ​        |
 +^ 连接失败 ​   | 连接服务器失败之后,sdk默认会重连5次,重连间隔将会递增 ​        |

页面工具