请选择 进入手机版 | 继续访问电脑版
帖子
帖子
用户
博客
课程

apicloud+融云实现即时通讯的心血历程

YonBuilder移动开发 2021-11-2 09:57 3445人浏览 0人回复
原作者: 周枫 收藏 邀请
摘要

  请尊重作者的辛勤劳动!!! 好多人都问我,为什么不直接把项目打包传上来,我想说:这是不可能的,不是我怕项目被别人用,而是那样就失去了你自己的思考和交流的意义,我不会那么做的。 帖子发出后,有好 ...

 
      请尊重作者的辛勤劳动!!!  
        好多人都问我,为什么不直接把项目打包传上来,我想说:这是不可能的,不是我怕项目被别人用,而是那样就失去了你自己的思考和交流的意义,我不会那么做的。
        帖子发出后,有好多朋友问我QQ号,交流QQ官方群:398827124,192967653;
        白天因为我也要上班工作,可能不能及时回复,请谅解~~


2015-12-25补充:
上传项目相关图片素材,在附件列表位置

PS:图片你们也找我要,自己找点不好嘛~~~

重大更新 12-24:
apicloud+rongcloud2 实现即时通讯的心血历程重大更新 01.26

apicloud+rongcloud2+sqlite 实现即时通讯的心血历程(三)

更新2016.10.25
                                                    apicloud+rongcloud2+sqlite  实现即时通讯的心血历程——汇总
2015-12-23补充:
好多人问我开发思路,今天我把开发思路文档方式贴出,在 附件 融云会话处理方案.rar ,整理的很详细了,大家自己下载看吧,我正在做本地化处理,完成优化之后再更新。
2015-10-29补充:
1. 上代码 date.js,需要的去下载,作用:转换时间类型
2. 说一下群组的思路:
我只说我的思路,其他实现的方式也可以:
原理:当前人的所有群组信息同步到融云,你说话的时候是你的id对群组的id说话,融云会对当前群组的所有人员发消息,道理就是这样的
1. 我用的是rongcloud1,在同步数据到融云服务器的时候那个方法有错误,因此我选择的是融云提供的java-sdk中的 ApiHttpClient.syncGroup 这个方法
2. 我是把当前登录人员点击“群聊”菜单时,提交个人person_id到java服务器端
3. java服务器端查询当前人员所在的全部群组,形成数组,利用  ApiHttpClient.syncGroup同步到融云服务器
4. 发送群组消息的时候,就是当前人的id对群组的id说了内容,然后融云会告诉这个群组下所有的人员id发送消息

2015-09-19补充:图片发送和获取逻辑:
1.  图片来源一般有2种方式,一是相册选择,可以使用UIMediaScanner 这个模块,数据是个数组,需要循环发送,二是直接照相,api.getPicture,传过去就是图片的在app的fs地址路径
2. 接收的时候融云返回有2个属性,一个是缩略图地址,一个是图片真实地址,这两个地址是融云服务器的,页面显示缩略图,点击打开显示真实地址


使 用apicloud开发已经快2个月了,起初的目的就是为了实现安卓和苹果的兼容,属于一个试验项目,究竟apicloud是否能够满足公司的要求?最 终看来还是不错的,使用apicloud+融云实现了类似微信即时通讯的功能。看到有很多后来的人依然在这块挣扎,我就把自己的实现思路和成果分享出来和大家一起交流一下,我也是第一次做手机开发,有很多经验不足的地方,希望大家能够直接指出来,我也不断完善自己的产品。
    这次没有使用本地数据库,所有数据都是从融云和服务器获取,会影响性能,下一步会把数据本地化处理,再将优化后的代码和大家交流。
    具体实现的思路,说的可能会有些混乱,希望大家能谅解~
    一、功能说明:
    1. 登录功能:类似微信,登录后记住当前人账号和密码,记在了Storage里,可能会有安全性问题,想在第二版优化时保存在数据库中;
    2. 通讯录功能:类似微信,包括群组及好友列表
    3. 历史会话列表:类似微信,包括群组及个人的历史会话列表
    4. 发送内容:包括文本、语音和图片
    二、使用的模块
        包括:fs、imageBrowser、bubbleMenu、listContact、UIMediaScanner、rongCloud、UIChatBox
    三、实现思路:
    PS:这里借鉴了 “流浪男” 的一篇文章,感谢他的对我实现思路的重大启发,原文:https://community.apicloud.com/bb ...viewthread&tid=8715
           使用论坛中的aui.css样式
            感谢技术客服  技术支持-M 的辛勤帮助
            感谢  吴勇  兄弟的帮助
    1.  登录操作,登录时访问服务器(自己的云服务器)获取token,服务器使用的是java的sdk获取token,组装token和人员的所有信息json返回到app,保存在storage里,后期会存到本地数据库中;
    2. 主界面,包括4个菜单,分别为会话历史页面、通讯录页面、应用页面和个人设置页面,所有的和融云相关的业务逻辑都在hh_index_window里面初始化,其他页面获取数据时,都是采取监听模式获取数据;
    3. 会话历史页面:hh_index_window.html
<!DOCTYPE html>
<html>
        <head>
                <metacharset="utf-8">
                <!-- html5:在创建html时为了防止页面缩放等不兼容效果,要创建个viewport  -->

                <metaname="viewport"
content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,width=device-width,initial-scale=1.0"/>
                <!-- 在IOS设备上,有时会将数字转为手机号,这里也要禁止下 -->
                <metaname="format-detection" content="telephone=no"/>
                <title>会话列表</title>
                <linkrel="stylesheet" type="text/css"href="../../css/aui.css" />
                <style>
                .span_name {
                       width: 20%;
                       /*font-size: 18px;*/
                       /*text-align: center;*/
                       display: inline-block;
                       /*word-break: keep-all;*/
                       white-space: nowrap;
                       overflow: hidden;
                       text-overflow: ellipsis;
                }
               </style>
        </head>
        <body>
               <!--<div class="aui-content"><inputtype="button" value="为了测试,点击这里清空会话"onclick="clearConversations();"/>-->
                       <ul class="aui-user-view">
                              <!--<li class="aui-user-view-cell aui-img"onclick="openNewsList();">
                                      <img class="aui-img-object aui-pull-left"src="../../image/person/demo1.png">
                                      <div class="aui-img-body">
                                              <span>系统消息1<em>10:22</em></span>
                                              <pclass='aui-ellipsis-1'>
                                                     理想家校通上线啦~~~
                                              </p>
                                      </div>-->
                                      <!--<div id="notify"style="height:0px;">
                                          <divclass="circle">
                                                  <pid="messages" class="circle_p"></p>
                                          </div>
                                  </div>-->
                              <!--</li>-->
                               <!--会话列表-->
                               <div id="hhlist_div"></div>
                              <script type="text/html"id="hhlist_script">
                                      <% if(result.length == 0){ %>

                               <div
style="text-align:center;color:#666;"><span>您还没有会话记录,快去找小伙伴们聊天
吧~~</span></div>
                   <% }else{ %>
                                              <%for(var i=0;i<result.length; i++) {%>
                                                            

                                                             <li id="<%=result.targetId%>"
alt="<%=result.conversationType %>"class="aui-user-view-cellaui-img"  onclick="openHhList('<%=result.targetId
%>','<%=result.latestMessageId
%>','<%=result.person_name
%>','<%=result.conversationType %>','hh_index');">
                                                                    <img class="aui-img-object aui-pull-left"src="<%=result.avatar_url %>">
                                                                    <div class="aui-img-body">

                                                                            <span><span
class="span_name"><%=result.person_name
%></span><em><%=g_time.getTime(result.receivedTime,1)
%></em></span>
                                                                            <% if(result.objectName =='RC:VcMsg') { %>
                                                                                    <pclass='aui-ellipsis-1'>[语音]</p>
                                                                            <% } %>
                                                                            <% if(result.objectName =='RC:TxtMsg') { %>
                                                                                    <pclass='aui-ellipsis-1'><%=result.latestMessage.text %></p>
                                                                            <% } %>
                                                                            <% if(result.objectName =='RC:ImgMsg') { %>
                                                                                    <pclass='aui-ellipsis-1'>[图片]</p>
                                                                            <% } %>
                                                                    </div>
                                                                    <% if(result.unreadMessageCount > 0) { %>
                                                                            <divstyle="height:0px;">
                                                                                <divclass="circle">
                                                                                       <pclass="circle_p"><%=result.unreadMessageCount%></p>
                                                                                       <input type="hidden"class="unread_count" value="<%=result.unreadMessageCount%>"/>
                                                                                </div>
                                                                        </div>
                                                                    <% } %>
                                                             </li>
                           <%}%>
                   <% } %>
                                      
                              </script>
                       </ul>
               <!--</div>-->
               
                <scripttype="text/javascript"src="../../script/api.js"></script>
                <scripttype="text/javascript"src="../../script/template.js"></script>
                <scripttype="text/javascript" src="../../script/date.js"></script>
                <!-- 长按控件周枫 2015.08.05 -->
                <scripttype="text/javascript"src="../../script/hammer.min.js"></script>
                <scripttype="text/javascript"src="../../script/base_config.js"></script>
                <scripttype="text/javascript"src="../../script/huihua/hh_index_window.js"></script>
        </body>
</html>

/*
* 把所有的融云类的处理全部放在消息列表页,然后通过APICloud的api.sendEvent和api.addEventListener 来处理融云的一些事件。
记住除了消息列表页其他页面不要做融云的任何链接处理
*/
//定义融云
var rong;
//内容高度
var rect_h;
//header高度
var header_h;

apiready = function() {
        api.showProgress({
                               title : '加载中...',
                               modal :false
                       });
        rect_h = api.pageParam.rect_h;
        header_h = api.pageParam.header_h;

        //加载融云模块
        rong = api.require('rongCloud');
        //融云初始化
        rongCloud();

        //监听来自会话页面发送消息的事件
        api.addEventListener({
                name :'sendMessage'
        }, function(ret) {
                if (ret&& ret.value) {
                       var value = ret.value;
                       switch(value.type) {
                               case'text':

                                      sendMessage('' + value.type + '', '' + value.targetId + '','' +
value.content + '', '' + value.extra + '', '' + value.conversationType +
'');
                                      break;
                               case'pic':
                                      //判断是照相还是选择,选择是数组,照相是一个
                                      switch(value.pic_source) {
                                              case 'camera':
                                                     sendPicture('' + value.targetId + '', '' + value.imgSrc + '','' + value.extra + '', '' + value.conversationType + '');
                                                     break;
                                              case 'album':
                                                     //                                                     alert(JSON.stringify(value));
                                                     var img_list = value.img_list;
                                                     for (var i = 0; i < img_list.length; i++) {
                                                             //                                                     alert(value.img_list.image_list.path+'123123');
                                                             //图片真实地址
                                                             var img_temp = img_list.path;
                                                             var img_url;
                                                             //文件后缀名,如:png,jpg, mp4
                                                             var suffix = img_list.suffix;
                                                             var obj_scan =api.require('UIMediaScanner');
                                                             if (api.systemType == 'ios') {
                                                                    //虚拟路径转真实路径
                                                                    obj_scan.transPath({
                                                                            path : img_temp
                                                                    }, function(ret) {
                                                                            //发送图片格式
                                                                            if (suffix == 'png' || suffix =='jpg') {
                                                                                   sendPicture('' + value.targetId + '', '' + ret.path + '', '' + value.extra +'', '' + value.conversationType + '');
                                                                            }
                                                                    });
                                                             } else if (api.systemType ="android") {
                                                                    //                                                                    api.alert({
                                                                    //                                                                            msg:img_temp
                                                                    //                                },function(ret,err){
                                                                    //                                        //coding...
                                                                    //                                 });
                                                                    //发送图片格式
                                                                    if (suffix == 'png' || suffix == 'jpg') {
                                                                            sendPicture('' + value.targetId +'', '' + img_temp + '', '' + value.extra + '', '' + value.conversationType +'');
                                                                    }
                                                             }

                                                     }
                                                     break;
                                      }
                                      break;
                               case'voi':

                                      sendVoice('' + value.targetId + '', '' + value.voicePath +'', '' +
value.duration + '', '' + value.extra + '', '' + value.conversationType
+ '');
                                      break;
                       }
                }
        });

        //监听来自会话页面获取历史会话的事件
        api.addEventListener({
                name :'getHistory'
        }, function(ret) {
                if (ret&& ret.value) {
                       var value = ret.value;
                       getHistoryMessagesById(value.type,value.target_id, value.old_msg_id, value.msg_count);
                }
        });

        //监听来自通讯录页面获取最新会话id的事件
        api.addEventListener({
                name :'getOldMessageId'
        }, function(ret) {
                if (ret&& ret.value) {
                       var value = ret.value;
                       getLatestMessagesById(value.conver_type,value.target_id, value.count, function(mes_list) {
                               varold_msg_id = -1;
                               if(getJsonObjLength(mes_list) != 0) {
                                      old_msg_id = mes_list[0].messageId;
                               }
                               //发送target_id获取最新会话id
                               api.sendEvent({
                                      name : 'setOldMessageId',
                                      extra : {
                                              old_msg_id ld_msg_id
                                      }
                               });
                       });

                }
        });

        //监听来注销页面的事件
        api.addEventListener({
                name :'logout'
        }, function(ret) {
               rong.disconnect(false);
        });

        //系统消息未读使用
        //       var messages = Math.floor((Math.random()*10)+1);
        //       document.getElementById("messages").innerHTML =messages;
}
/*
* 打开会话页面
* 周枫
* 2015-08-03
*/
function openHhList(target_id, old_msg_id, person_name, conver_type, h_from) {
        //清除未读信息
        cleanMsg(target_id, conver_type);
        getCoversationList();
        //如果是群组,则获取群组人员姓名json
        if (conver_type == "GROUP") {
               getGroupInfoById(target_id);
        }

        api.openWin({
                name :'hh_chat_window',
                url :'hh_chat_window.html',
                bounces :true,
                animation :'push',
                delay : 1,
                scrollToTop :true,
                pageParam : {
                       'targetId' : target_id,
                       'old_msg_id' : old_msg_id + 1,
                       'conver_type' : conver_type,
                       'person_name' : person_name,
                       'header_h' : header_h,
                       'conver_type' : conver_type,
                       'h_from' : h_from
                },
                rect : {
                       x : 0,
                       y : 'auto',
                       w : 'auto',
                       h : 'auto'
                }
        });
        $api.addEvt($api.byId('back'), 'click',function() {
               api.closeWin();
        });
        //       });
}

/**
* 打开消息列表页面
* 周枫
* 2015.08.17
*/
function openNewsList() {
        api.openWin({
                name :'xx_index_window',
                url :'xx_index_window.html',
                bounces :true,
                animation :'push',
                delay : 1,
                scrollToTop :true,
                pageParam : {
                       'header_h' : header_h
                },
                rect : {
                       x : 0,
                       y : 'auto',
                       w : 'auto',
                       h : 'auto'
                }
        });
}

/*
* 融云初始化
* 周枫
* 2015-08-03
*/
function rongCloud() {
        var token = $api.getStorage('mytoken');
        //融云初始化
        rong.init(function(ret, err) {
                if(ret.status == "success") {
                       api.execScript({
                               name :'index',
                               script :'setTitle("会话");'
                       });
                } else {
                       api.execScript({
                               name :'index',
                               //                              frameName : 'hh_index',
                               script :'setTitle("连接失败");'
                       });
                }
        });
        //监听新消息
        receiveMessageListener();
        //连接
        rong.connect({
                token : '' +token + ''
        }, function(ret, err) {
                if(ret.status == 'success') {
                       //清空所有会话
                       //                                                                                   clearConversations();
                       //消息列表
                       getCoversationList();
                       //初始化当前人员群组信息
                       //                       initPersonGroup();
                       //                       quitGroup();
                } else {
                       var err_code = err.code;
                       switch(err_code) {
                               case"-1":
                                      api.toast({
                                              msg : "对不起,客户端发生未知错误!",
                                              location : 'middle'
                                      });
                                      break;
                               case"2002":
                                      api.toast({
                                              msg : "对不起,客户端数据包不完整,请求数据包有缺失!",
                                              location : 'middle'
                                      });
                                      break;
                               case"2003":
                                      api.toast({
                                              msg : "对不起,服务器不可用!",
                                              location : 'middle'
                                      });
                                      break;
                               case"2004":
                                      api.toast({
                                              msg : "对不起,请重新向身份认证服务器获取 Token!",
                                              location : 'middle'
                                      });
                                      break;
                               case"2005":
                                      api.toast({
                                              msg : "对不起,可能是错误的 App Key,或者 App Key 被服务器积极拒绝!",
                                              location : 'middle'
                                      });
                                      break;
                               case"2006":
                                      api.toast({
                                              msg : "对不起,服务端数据库错误!",
                                              location : 'middle'
                                      });
                                      break;
                               case"5004":
                                      api.toast({
                                              msg : "对不起,服务器超时!",
                                              location : 'middle'
                                      });
                                      break;
                               case"-10000":
                                      api.toast({
                                              msg : "对不起,未调用 init 方法进行初始化!",
           &
本文暂无评论,快来抢沙发!