请尊重作者的辛勤劳动!!! 好多人都问我,为什么不直接把项目打包传上来,我想说:这是不可能的,不是我怕项目被别人用,而是那样就失去了你自己的思考和交流的意义,我不会那么做的。 帖子发出后,有好 ...
请尊重作者的辛勤劳动!!! 好多人都问我,为什么不直接把项目打包传上来,我想说:这是不可能的,不是我怕项目被别人用,而是那样就失去了你自己的思考和交流的意义,我不会那么做的。 帖子发出后,有好多朋友问我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 ![]() } }); }); } }); //监听来注销页面的事件 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 方法进行初始化!", & |