【环信编程大赛开源优秀项目展示】图忆--一款基于位置信息的分享与社交应用
1.软件介绍
图忆是一款基于位置信息的分享与社交应用。实现了将用户记录的不同类型的事件标刻于地图之上,查看自己的记录足迹,同时用户可以轻松查看附近分享的记事,添加好友聊天,建立兴趣圈子,发现志趣相投的好友,并且用户记事可以分享到公共社区平台,分享乐趣的同时也发现了更多的乐趣,社区推荐策略让用户发现更多有价值的乐趣。
2.功能介绍
【记录记忆】你可以记录自己的生活点滴在地图之上,可以公开给别人看,也可以保存为自己的私有记忆。
【离线记录】没有网络也可以轻松保存离线记录,WIFI连接后直接批量上传,省心
【地图附近】你将通过地图查看到附近用户公开的说有分享记录,当然是直接在地图上展示的哟,很直观的说,还有五个标签分类查询哟,就等你来发现了。
【雷达】发现同时在附近开启雷达的小伙伴,自定义雷达显示的内容,让小伙伴更容易发现你
【聊天圈子】与TA尽情畅聊,兴趣小伙伴建圈子一起聊。
【图忆社区】点赞,评论,分享,收藏Ta的分享
3.使用技术
环信IM
百度地图API
有盟API
4.作者心得
IM正越来越得到开发者重视,也逐渐成为APP标配,绝大部分App中都集成了即时通讯功能。将APP的核心功能紧密与即时通讯良好结合,将更有利于APP的用户体验和留存。
APP的多元发展中需要使用多功能的有机结合。而作为一个完整的SDK需要越少的干涉APP原本的逻辑,而不降低功能与体验,这些方面环信的IM SDK都做的挺好。
该项目为环信编程大赛参赛项目,报名参加颁奖典礼,这里有一群有时间,熟悉环信集成,开源项目的大牛,还有数十家环信企业级服务器小伙伴和金牌投资人,报名连接http://www.easemob.com/event/hackathon_party/
git源码下载https://github.com/donlan/Tuyi
作者演讲PPT下载↓↓↓ 收起阅读 »
【环信编程大赛优秀开源项目展示】高仿微信--基于环信sdk高仿微信
实现功能点:
消息:订阅号、列表滑动删除、TitleBar弹出菜单
单聊,群聊(发送文字,语音,位置,视频,文件,语音电话,视频通话)
微信表情、
通讯录:按字母索引排序、添加手机通讯录好友、
发现:二维码扫描添加好友、二维码扫描加入群聊、扫码微信支付、生成自己二维码图片
朋友圈、发布朋友圈信息、购物、游戏、设置
WebView与Javascript交互、播放视频、加载HTML5页面
FastJson Json转换神器、Imageloader图片加载库、android-async-http 网络请求库、图片缩放查看、加密解密
技术心得
本项目基本实现了微信的核心功能,对微信UI设计进行Redesign,提高用户体验
另外在对接环信sdk的时候,没有直接采用官方的demo,而是基于环信官方文档,对聊天模块的功能自己来处理业务逻辑,对接起来比较麻烦,工作量也挺大。
对于想要基于环信sdk进行二次开发时,前期还是要把官方demo和官方文档给摸熟,后面再进行功能扩展的时候,才能够得心应手。
该项目为环信编程大赛参赛项目,报名参加颁奖典礼,这里有一群有时间,熟悉环信集成,开源项目的大牛,还有数十家环信企业级服务器小伙伴和金牌投资人,报名连接http://www.easemob.com/event/hackathon_party/
git源码下载https://github.com/motianhuo/wechat 收起阅读 »
【环信编程大赛开源优秀项目展示】美肤GO--一款专注于个人海外代购及护肤咨询分享的APP
功能介绍
其中主要功能包含个人海外代购、美妆美肤课程、社区分享互动等,希望给爱美向往美的你一个全方位的秘密基地,也希望给想要做全职代购或者兼职代购甚至只是旅游顺便想代购挣回机票钱的我一个平台,源于这个初衷,美肤GO提供高品质的代购机制和最亲民线下般体验的护肤资讯,只为让你更美丽!
技术方面
android端使用的dileber框架,由我们大学的DrCoSu社团几位成员共同研发,达到了快速开发的效果。
界面部分交互采用原生androidJava编写,MVP设计模式,整体结构清晰耦合度低。
在用户交流处直接调用环信SDK,提供较好的社交聊天体验。
兼容各个机型,不会出现拉伸或缩放问题。
服务端采用Java实现,额外配置了redis,使持久层得到保障并有较好的接口响应速度。 心得方面,环信SDK还是一款很方便的IM体系,可以帮助小的开发者或小公司快速集成这方面的功能。
心得建议
如果进一步拓展开发类似于微信红包这样的功能,能吸引到更广泛的客户群 慢慢努力做最好的轻量护肤应用~
该项目为环信编程大赛参赛项目,报名参加颁奖典礼,这里有一群有时间,熟悉环信集成,开源项目的大牛,还有数十家环信企业级服务器小伙伴和金牌投资人,报名连接http://www.easemob.com/event/hackathon_party/
git源码下载:https://github.com/Rabbit00/MeifuGO
源码 APK 下载↓↓↓ 收起阅读 »
【环信编程大赛优秀开源项目展示】宅不住--发现城市精彩运动,认识周边潮人
项目简介:
宅不住,发现城市精彩运动,认识周边潮人。类似与周末去哪儿 app, 同时加入了社交模块,即时聊天功能
主要功能模块有:
1.主页、附近的活动、附近的潮人
2. 发布活动、搜索活动
3. 专题、及时通讯(环信SDK)
4. 登陆(个人主页)、设置模块
技术介绍
聊天页类: HKChatViewController
聊天列表类: HKChatListViewController
该项目为环信编程大赛参赛项目,报名参加颁奖典礼,这里有一群有时间,熟悉环信集成,开源项目的大牛,还有数十家环信企业级服务器小伙伴和金牌投资人,报名连接http://www.easemob.com/event/hackathon_party/
源码下载↓↓↓
http://pan.baidu.com/s/1sl7oSnN 收起阅读 »
【环信编程大赛优秀项目展示】咚咚--一款高效团队沟通的移动客户端
基于环信平台进行开发,旨在打造的高效团队沟通的移动客户端,供企业内部协作使用、适应移动办公需要,提升企业沟通协同效率,增强企业办公管理效率。(当前仅实现了用户登入登出功能、通讯功能、投票功能。)
具体功能说明
一、用户登录注册功能
1.系统登录界面
2系统注册界面
注册功能实现:限制账号长度必须为11位,出生日期选择,头像选择(从系统自带头像中选择)
3.系统首页
登陆成功,即进入系统主页面
4.个人信息查看及修改
进入主页面后点击个人信息查看,即可查看相关信息,并对其进行修改
主界面
(1)头像修改功能实现
(2)名字修改功能实现
(3)部门修改功能实现
(4)性别选择功能实现
(5)个性签名修改功能实现
二、通讯功能
主界面
功能实现:群组聊天,单对单私人聊天,查看好友列表,查看好友详情,查看群组详情
三、投票功能
主界面
功能实现:展示用户发起的投票列表,新增投票,投票提交
总结与心得
基于环信平台的开发,使得项目的难点得于轻松解决,例如在平台上可以使用即时通讯功能以及用户好友管理、群组管理功能。让项目得于快速开发成型。
该项目为环信编程大赛参赛项目,报名参加颁奖典礼,这里有一群有时间,熟悉环信集成,开源项目的大牛,还有数十家环信企业级服务器小伙伴和金牌投资人,报名连接http://www.easemob.com/event/hackathon_party/
git源码地址:https://github.com/caisiyi/SYTeamApp 收起阅读 »
环信助力传统商业转型电商的客服升级之路:从产品上网到服务上网
从产品上网到服务上网
传统行业触网电子商务,要解决的第一个问题,便是平台搭建。对垂直类电商而言,贯通上下游的供应链管理是运营重点,而天猫、京东这类以流量运营为主的综合电商平台显然不适合。因此自己搭建独立网店或交易平台,成为垂直类电商的首选。目前,国内提供电商平台解决方案的服务商已为数不少。例如,APP端有有赞、微店、微盟萌店、微猫,PC端有Shopex、ECShop、Shop++、Javashop、千米、筑云等等,这些厂商的模块化解决方案帮助传统行业快速实现了产品上网和在线交易,完成了“触网”的第一步。
但我们看到,很多垂直电商虽然实现了“产品”上网,“服务”却迟迟没有上网。由于存在技术门槛,当前电商平台解决方案中,均没有集成客服功能,这导致很多垂直电商仍延用传统的客服方式。即使是规模较大的垂直电商,客户服务的渠道最多也就是营销QQ再加上400电话,这与电商的商业理念背道而驰。效率是电子商务对传统商业的重要革命,电商的本质即在于通过信息流动实现对供需关系的高效率匹配。电商的服务也应当像产品一样,进行效率革命。这也是“SaaS客服”、“全媒体服务”在互联网经济中蓬勃发展的重要原因。传统行业触网垂直电商,继产品上网之后,服务上网将是迈出的第二步。本文围绕服务效率和用户体验,为转型电子商务的传统行业商家介绍移动互联网下的客服形态——全媒体客服。
什么是全媒体客服?
全媒体客服是指通过SaaS服务平台,客服人员可同时为来自各种渠道的用户提供实时和一致的服务,服务渠道包括APP、微信、微博、Web,以及传统呼叫中心等。用户和客服之间采用文字、图片、音视频等多媒体消息或是电话语音进行交互。通过覆盖多种渠道媒体,全媒体服务的理念是“用户在哪,服务在哪”。和传统客服相比,全媒体客服的核心价值在于能够大幅提高商家的服务效率,并且实现服务式营销,同时也为商家的客户带来了更好的体验。
从部署角度来看,基于云端SaaS平台的全媒体客服是一种极轻量部署模式。用户无需采购任何专用硬件设备,只需要普通PC,通过浏览器即可提供专业客户服务。实现的方式也极其简单,对于APP,只需要集成厂商提供的SDK,对于网页,微信或微博,更是一行代码即可开启全媒体客服。
环信是国内最早进军全媒体客服的厂商,根据易观智库的市场数据,在移动端SaaS客服市场,环信市场占有率高达77.4%(数据来源:易观智库《2015中国SaaS客服市场专题研究报告》)。本文即是基于市场发展趋势和环信的技术研究,介绍全媒体客服在提升效率和用户体验上的一些优势和关键技术。
1:1 vs 1:N,集约化客户服务
传统企业的客户服务通常以呼叫中心为主。用户需要服务时,拨打企业400/800电话,再由客服人员提供服务。由于一名客服同一时间只能服务于一名客户,因此这是一种1:1独占式服务方式。转型电商后,客户来的渠道多样化,有从网页端来的,有从APP端来的,或是从社交媒体,如微博、微信来的。这时候显然无法按呼叫中心1:1的配置方式,为不同渠道的客户提供单独服务。全媒体客服则是通过云端系统,打通不同渠道,对所有渠道来的用户进行统一排队和会话分配。每一位客服,都可同时服务于多个渠道来的客户,这是一种1:N式的集约化服务。在环信的案例——学而思的客户服务中心,每位客服人员最多时可同时服务20余名客户。在当前人口红利逐渐消失,人力成本急剧上升之时,任何对人力资源的高效率、集约化运用,都是在为企业创造效益。
从IVR到ITR,可触摸的服务
Gartner在3月份发布的《2020年前用户关系中心应关注的5项技术》中,把ITR(Interactive Touch Response,交互式触摸响应)技术列为关键技术之一。ITR是移动互联网时代,触摸化的IVR。客户不再需要听完所有的服务菜单,只需要在手机屏幕上,直接选择需要的服务内容,即可获得服务。例如,神州专车在给司机端提供的“微客服”服务,司机直接在手机屏幕上选择需要的服务内容,不需要打电话听完漫长的语音提示,再选择服务内容联系相应的客服。通过移动客服和ITR技术,整个服务过程时间节约了80%,既提升了用户体验,同时也降低了客服压力。
自助式服务,让用户自己解决问题
对于一些形式标准化,内容单一化的服务,可以通过自助式服务的方式,让用户自己解决问题。例如密码更改、订单管理、物流跟踪等等。自助式服务满足了用户碎片化的使用习惯。用户可以在车上闲暇时间,或是不方便电话沟通的场合即可完成服务,同时也降低了人工客服的需求量。
提供自助式服务,需要企业将IT系统前置,通过一些开放式接口,让用户在商城应用程序的客户端中,直接调用相应接口,完成服务过程。这是和传统呼叫中心封闭式系统部署的不同之处。
随着智能技术的成熟,在开放接口上还可进一步增加智能客服插件。客户通过自然语言,例如“我想修改订单送达地址”,经过自然语言处理技术进行语义分析后,客服机器人返回订单修改入口,用户完成自服务。这个过程,结合人机融合,可以提供无差错的高质量服务。
人机融合,用智能提高服务效率
虽然当前机器学习算法飞速发展,在客服领域也得到了广泛应用。但在自然语言处理,特别是中文语义的识别上,距离完全替代客服还有差距。用人机配合的方式,对于复杂问题,借助智能客服答复,辅以人工核验,既能提高效率,同时又保证了用户体验。
环信在坐席工作台界面中,增加了一个推荐答案窗口。当用户发出客服请求时,智能机器人在推荐窗口提供了若干个备选答案。坐席人员从中选择一个最合适的答案,只需要点击“发送”,用户立刻就可得到回复。如果需要修改,也只需要在推荐答案的基础上经过少量编辑即可。通过人机配合,在保证准确度的情况下,大幅提高了坐席的工作效率。
服务式营销,从成本中心到利润中心
在传统行业,客户服务中心通常是一个成本中心,以解决售后问题为主,难以和营销挂钩。以信息流动为基础的电子商务则为服务式营销提供了机会,客服人员可以接触到客户资料、历史购买商品以及消费习惯等关键信息。但要实现营销,关键之处在于如何利用这些信息。
服务式营销的关键技术之一是大数据分析能力,通过数据挖掘找到热门商品和潜在客户的最佳匹配关系。为此环信在全媒体客服产品提供了客户标签和热词分析功能。通过客户购买历史纪录、访问轨迹、基础资料等信息为客户打上标签,依靠热词分析及时发现热门商品,两者之间的匹配程度越高,商品销售的成功率越高。
服务式营销的另一关键技术是无干扰的消息推送技术。电话外呼之所以日渐淘汰,除了缺乏精准性外,对用户干扰大、体验差也是重要原因。环信全媒体客服采用基于长连接的消息通知方式。客服人员的营销信息,以后台通知的方式发送到用户端。用户可以在闲暇时间打开,这种方式给客户充分的主动权,不会对客户体验带来影响。此外,长连接技术的另一优势是不会丢失消息。通过大数据分析和无干扰的消息推送,客服能前置到销售链前端,实施主动的服务式营销,从成本中心转变为利润中心。
传统呼叫中心的升级之路
转型电商的传统行业商家升级至全媒体客服,根据不同情况有两种可行解决方案。对于当前没有大规模呼叫中心的中小企业,可以采用直接切换的方式,一步到位,用全媒体客服替代传统电话客服。这种方案成本低廉,简单易行。
对于已经建设了大规模呼叫中心的大型企业,以增量部署的方式,使全媒体客服嵌入呼叫中心,保护用户既有投资。这种方案通过开放式接口,可以实现“三统一”:
- 统一排队与路由分配。不论何种渠道来的客户,统一进行排队,共享客服资源;
- 统一话单记录。同一个客户,不论从哪种渠道访问,话单记录都只有一份,客服人员可查看完整历史会话信息;
- 统一后台数据。通过开放式接口,可以对接现有CRM、工单系统、知识库,打通后台数据,消除数据壁垒。
更加高效、更好体验、服务营销,这是全媒体客服对于传统呼叫中心的核心竞争力。转型全媒体客服,是传统呼叫中心的必然趋势。在这个过程中,既需要传统行业商家转变思路,拥抱移动互联网,更需要行业生态链的共建共赢。
收起阅读 »
Android V3.1.2 release
1.视频通话增加切换摄像头API:EMClient.getInstance().callManager().switchCamera();
2.新增消息搜索API:conversation.searchMsgFromDB();
3.支持设置和获取long类型的扩展字段;
4.加快app从后台切到前台时的重连速度;
5.优化GCM推送;
Bug fix:
1.修复某些手机发送系统表情时对方接到为乱码或空白的bug;
2.修复上一个版本发送图片消息时,如果是小图会删除原图的bug;
版本历史:Android sdk 更新日志
下载地址:SDK下载 收起阅读 »
iOS sdk 3.1.2 release
增加消息搜索功能,可以根据消息类型或者关键字搜索
优化绑定deviceToken逻辑
bug fix:
Fix 修复发送系统表情时对方接到为乱码或空白的问题
SDK下载http://www.easemob.com/download
3.0 Demo ,单聊 ,群聊
还有的细节需要自己慢慢修改3.0 - (NSArray *)loadMoreMessagesFromId:(NSString *)aMessageId
limit:(int)aLimit
direction:(EMMessageSearchDirection)aDirection;
这个方法和以前不一样,若进去聊天界面获取历史消息EMMessageSearchDirectionUp 用这个
moreMessages = [weakSelf.conversation loadMoreMessagesFromId:messageId limit:(int)count direction:EMMessageSearchDirectionUp];
http://community.easemob.com/article/825307736
进入这个连接就是单聊的Demo
如果需要改为群聊,
- (void)creatpUsh
{
EMError *error = nil;
EMGroupOptions *setting = [[EMGroupOptions alloc] init];
setting.maxUsersCount = 500;
setting.style = EMGroupStylePublicOpenJoin;// 创建不同类型的群组,这里需要才传入不同的类型
EMGroup *group = [[EMClient sharedClient].groupManager createGroupWithSubject:@"老鸭粉丝汤2" description:@"想吃的来来来2" invitees:nil message:@"邀请您加入群组" setting:setting error:&error];
if(!error){
NSLog(@"创建成功 -- %@",group.groupId);
self.grouldID = group.groupId;
}
}
这里创建一个群组/*!
self.grouldID = group.groupId; 获取群组的ID,
首先加入群组,不同的方法加入不同群组
EMError *error = nil;
[[EMClient sharedClient].groupManager joinPublicGroup:@"1461034891668" error:&error];
我这里就一EMGroupStylePublicOpenJoin这个类型,其他的看文档有,
在跳转页面的时候传入
ChatViewController *chatVC = [[ChatViewController alloc]initWithConversationChatter:@"1461034891668" conversationType:EMConversationTypeGroupChat];
chatVC.title = @"老鸭粉丝汤";
[self.navigationController pushViewController:chatVC animated:YES];
这样跳转过去就基本可以聊天了
更多问题可以加环信群 :165331879 收起阅读 »
企业即时通讯系统二次开发
即时通讯系统的出现让企业感受到了现代化信息管理的力量,可真正解决企业的问题。
其实企业即时通讯系统也是通过延伸统一通信的理念研发而来的,溯本追源,企业即时通讯也是属于统一通信的范畴,只不过它更有针对性、具体性的解决了企业的信息堵塞和效率低下的问题。
企业即时通讯系统具备文字、语音、视频、文件共享等多样化沟通方式,用户可以通过最合适的媒体实现通信和业务协作。不要质疑信息传递的及时性和安全性,节约时间和降低成本的同时,提高了生产率和竞争实力。
信贸通即时通讯软件。专为企事业单位和政__府部门设计,通过对政企机构内部现有信息和应用系统的一体化集成整合,快速实现企业内部即时通讯、分权限组织架构管理、一站式协同办公等功能,能够有效的缩短内部沟通距离,快速提高政企内部工作效率。
企业在发布公告的时候可以通过电子公告或者实时消息广播实现,这种方式样式新颖能吸引大家的注意力,有助于企业信息的传播。另外,通过组织架构树或者模糊查询,能够迅速查找到联系人,通过文字会话、语音视频、等方式企业内外通讯完全统一无障碍,可以帮助企业加快信息流转。
收起阅读 »
有关昨天在集成EasseUI报错问题解决
在集成EaseUI环信的时候回出现各种不同的错误,当导入的时候,最基本的报错就是头文件的报错,这种的报错是非常常见,所以这个时候,我们需要静下心来,进行报错的排除和检查,当然你需要,这个时候需要的是耐心.
1.在你集成环信的时候,新建的工程项目我就不说了,最关键的就是你集成到成型的app中的时候,估计报错会比较多一点.
2.你要先将你想要的demo里面的东西集成好了,这是最重要的的前提,下面就是我遇到报错:
"_OBJC_CLASS_$_SKPayment", referenced from:
objc-class-ref in Parse(PFPurchase.o)
"_OBJC_CLASS_$_SKPaymentQueue", referenced from:
objc-class-ref in Parse(PFPurchase.o)
"_OBJC_CLASS_$_SKProductsRequest", referenced from:
objc-class-ref in Parse(PFPurchase.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
错误截图:
解决的方法:
一:在http:stackoverflow.com上面也有很多遇到过,你也可以将错误进行贴上去,上面说是少了Accounts,Social库,还有一个就是parse库,这个在parse库在xcode里面没有,最近也在研究这个parse,希望有啥好的东西,贴出来,期待!
二:删除在你的工程有关parse,在demo中3rdparty中parse文件,在这里需要建议的是,我们在删除的时候,该删的就删,不该删不要删除,
三:当然在不同的工程中,报错会有不同新的报错,这个时候我们需要,有耐心查找排错,希望有新的方法进行交流互动,建议和解决的思路贴上去,当然在这里也得感谢环信的技术的提醒.
收起阅读 »
环信直播课堂第八期--3.xSDK头像昵称的实现
持续时间:半小时
描述:集成环信即时通讯的时候,相信大家都有问过这个问题,昵称头像怎么实现?
本期环信直播课堂将由环信IOS工程师FUccc给大家详细讲解ios3.xSDK头像昵称的实现
直播观看地址: http://www.imgeek.org/video/15
视频回放地址:http://www.imgeek.org/video/25 收起阅读 »
Android开发集成环信SDK3.x教程
环信已经发部了SDK3.x版本,SDK3.x相对于SDK2.x来说是整个进行了重写,API变化还是比较大的,已经熟悉SDK2.x的开发者在使用新的SDK3.x还是会遇到不少问题的,不过还好官方给出了SDK2.x升级SDK3.x指南,已经熟悉SDK2.x开发者可以根据文档了解SDK3.x的变化,新集成的开发者可以直接参考SDK3.x进行集成;
这里简单的实现了sdk的初始化以及注册登录和收发消息,不过ui上没有没有去做很好的处理
先看效果图
提供一些地址
当前项目地址,可以直接 clone 运行
EaseChat Github
AndroidStudio下载
Android官方下载
国内提供 AndroidDevTools
模拟器 Genymotion下载
Genymotion 官网
环信官方文档
SDK3.x 文档
SDK3.x API 文档
SDK2.x 升级 SDK3.x 文档
###说下我当前开发环境
这里并不是一定要按照我的配置来,只是说下当前项目开发运行的环境,如果你的开发环境不同可能需要自己修改下项目配置build.gradle文件
AndroidStudio 2.0
Gradle 2.10(跟随AndroidStudio 一起更新)
Android SDK Tool 25.1.1
Android Build-tools 23.0.2
Android Support 最新
Genymotion 2.6
如果你还是用的Eclipse,可以下载AndroidStudio尝试下,如果你上不了Android官网,不懂怎么翻墙可以找下国内开发提供的一些地址
开始集成
这次要实现 SDK的初始化、SDK端的注册登录、消息的发送和监听这三步
SDK的初始化
这个初始化时在Application里进行的,这里定义了一个方法去初始化环信的SDK,并在其中进行了一些设置
package net.melove.demo.easechat;
import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageManager;
import com.hyphenate.chat.EMClient;
import com.hyphenate.chat.EMOptions;
import java.util.Iterator;
import java.util.List;
/**
* Created by lz on 2016/4/16.
* 项目的 Application类,做一些项目的初始化操作,比如sdk的初始化等
*/
public class ECApplication extends Application {
// 上下文菜单
private Context mContext;
// 记录是否已经初始化
private boolean isInit = false;
@Override
public void onCreate() {
super.onCreate();
mContext = this;
// 初始化环信SDK
initEasemob();
}
/**
*
*/
private void initEasemob() {
// 获取当前进程 id 并取得进程名
int pid = android.os.Process.myPid();
String processAppName = getAppName(pid);
/**
* 如果app启用了远程的service,此application:onCreate会被调用2次
* 为了防止环信SDK被初始化2次,加此判断会保证SDK被初始化1次
* 默认的app会在以包名为默认的process name下运行,如果查到的process name不是app的process name就立即返回
*/
if (processAppName == null || !processAppName.equalsIgnoreCase(mContext.getPackageName())) {
// 则此application的onCreate 是被service 调用的,直接返回
return;
}
if (isInit) {
return;
}
/**
* SDK初始化的一些配置
* 关于 EMOptions 可以参考官方的 API 文档
* http://www.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1chat_1_1_e_m_options.html
*/
EMOptions options = new EMOptions();
// 设置Appkey,如果配置文件已经配置,这里可以不用设置
// options.setAppKey("lzan13#hxsdkdemo");
// 设置自动登录
options.setAutoLogin(true);
// 设置是否需要发送已读回执
options.setRequireAck(true);
// 设置是否需要发送回执,TODO 这个暂时有bug,上层收不到发送回执
options.setRequireDeliveryAck(true);
// 设置是否需要服务器收到消息确认
options.setRequireServerAck(true);
// 收到好友申请是否自动同意,如果是自动同意就不会收到好友请求的回调,因为sdk会自动处理,默认为true
options.setAcceptInvitationAlways(false);
// 设置是否自动接收加群邀请,如果设置了当收到群邀请会自动同意加入
options.setAutoAcceptGroupInvitation(false);
// 设置(主动或被动)退出群组时,是否删除群聊聊天记录
options.setDeleteMessagesAsExitGroup(false);
// 设置是否允许聊天室的Owner 离开并删除聊天室的会话
options.allowChatroomOwnerLeave(true);
// 设置google GCM推送id,国内可以不用设置
// options.setGCMNumber(MLConstants.ML_GCM_NUMBER);
// 设置集成小米推送的appid和appkey
// options.setMipushConfig(MLConstants.ML_MI_APP_ID, MLConstants.ML_MI_APP_KEY);
// 调用初始化方法初始化sdk
EMClient.getInstance().init(mContext, options);
// 设置开启debug模式
EMClient.getInstance().setDebugMode(true);
// 设置初始化已经完成
isInit = true;
}
/**
* 根据Pid获取当前进程的名字,一般就是当前app的包名
*
* @param pid 进程的id
* @return 返回进程的名字
*/
private String getAppName(int pid) {
String processName = null;
ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
List list = activityManager.getRunningAppProcesses();
Iterator i = list.iterator();
while (i.hasNext()) {
ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) (i.next());
try {
if (info.pid == pid) {
// 根据进程的信息获取当前进程的名字
processName = info.processName;
// 返回当前进程名
return processName;
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 没有匹配的项,返回为null
return null;
}
}
主界面
app启动后默认会进入到ECMainActivity,不过在主界面会先判断一下是否登录成功过,如果没有,就会跳转到登录几面,然后我们调用登录的时候,在登录方法的onSuccess()回调中我们进行了界面的跳转,跳转到主界面,在主界面我们可以发起回话;
看下主界面的详细代码实现:
package net.melove.demo.easechat;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.hyphenate.EMCallBack;
import com.hyphenate.chat.EMClient;
public class ECMainActivity extends AppCompatActivity {
// 发起聊天 username 输入框
private EditText mChatIdEdit;
// 发起聊天
private Button mStartChatBtn;
// 退出登录
private Button mSignOutBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 判断sdk是否登录成功过,并没有退出和被踢,否则跳转到登陆界面
if (!EMClient.getInstance().isLoggedInBefore()) {
Intent intent = new Intent(ECMainActivity.this, ECLoginActivity.class);
startActivity(intent);
finish();
return;
}
setContentView(R.layout.activity_main);
initView();
}
/**
* 初始化界面
*/
private void initView() {
mChatIdEdit = (EditText) findViewById(R.id.ec_edit_chat_id);
mStartChatBtn = (Button) findViewById(R.id.ec_btn_start_chat);
mStartChatBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 获取我们发起聊天的者的username
String chatId = mChatIdEdit.getText().toString().trim();
if (!TextUtils.isEmpty(chatId)) {
// 获取当前登录用户的 username
String currUsername = EMClient.getInstance().getCurrentUser();
if (chatId.equals(currUsername)) {
Toast.makeText(ECMainActivity.this, "不能和自己聊天", Toast.LENGTH_SHORT).show();
return;
}
// 跳转到聊天界面,开始聊天
Intent intent = new Intent(ECMainActivity.this, ECChatActivity.class);
intent.putExtra("ec_chat_id", chatId);
startActivity(intent);
} else {
Toast.makeText(ECMainActivity.this, "Username 不能为空", Toast.LENGTH_LONG).show();
}
}
});
mSignOutBtn = (Button) findViewById(R.id.ec_btn_sign_out);
mSignOutBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
signOut();
}
});
}
/**
* 退出登录
*/
private void signOut() {
// 调用sdk的退出登录方法,第一个参数表示是否解绑推送的token,没有使用推送或者被踢都要传false
EMClient.getInstance().logout(false, new EMCallBack() {
@Override
public void onSuccess() {
Log.i("lzan13", "logout success");
// 调用退出成功,结束app
finish();
}
@Override
public void onError(int i, String s) {
Log.i("lzan13", "logout error " + i + " - " + s);
}
@Override
public void onProgress(int i, String s) {
}
});
}
}
SDK端的注册登录
SDK初始化做完之后,就是需要进行环信的登录了,登录了才能使用环信的功能,才能收发消息,有不少人经常问,不注册账户能使用么,这是聊天sdk,不注册账户你拿什么聊天呢!
登录调用EMClient.getInstance().login(username, password, callback);此方法是一个异步方法,所以需要设置EMCallback回调来接收登录结果;
注册调用EMClient.getInstance().createAccount(username, password);此方法是同步方法,需要自己创建新线程去调用,不能放在UI线程直接调用;
因为只是个简单的demo,这边把登录和注册都卸载了LoginActivity类里,这个方法中对调用环信sdk的方法返回错误值做了一些判断,具体错误信息可以参考官方文档:
环信SDK3.x EMError
package net.melove.demo.easechat;
import android.app.ProgressDialog;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.hyphenate.EMCallBack;
import com.hyphenate.EMError;
import com.hyphenate.chat.EMClient;
import com.hyphenate.exceptions.HyphenateException;
public class ECLoginActivity extends AppCompatActivity {
// 弹出框
private ProgressDialog mDialog;
// username 输入框
private EditText mUsernameEdit;
// 密码输入框
private EditText mPasswordEdit;
// 注册按钮
private Button mSignUpBtn;
// 登录按钮
private Button mSignInBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
}
/**
* 初始化界面控件
*/
private void initView() {
mUsernameEdit = (EditText) findViewById(R.id.ec_edit_username);
mPasswordEdit = (EditText) findViewById(R.id.ec_edit_password);
mSignUpBtn = (Button) findViewById(R.id.ec_btn_sign_up);
mSignUpBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
signUp();
}
});
mSignInBtn = (Button) findViewById(R.id.ec_btn_sign_in);
mSignInBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
signIn();
}
});
}
/**
* 注册方法
*/
private void signUp() {
// 注册是耗时过程,所以要显示一个dialog来提示下用户
mDialog = new ProgressDialog(this);
mDialog.setMessage("注册中,请稍后...");
mDialog.show();
new Thread(new Runnable() {
@Override
public void run() {
try {
String username = mUsernameEdit.getText().toString().trim();
String password = mPasswordEdit.getText().toString().trim();
EMClient.getInstance().createAccount(username, password);
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!ECLoginActivity.this.isFinishing()) {
mDialog.dismiss();
}
Toast.makeText(ECLoginActivity.this, "注册成功", Toast.LENGTH_LONG).show();
}
});
} catch (final HyphenateException e) {
e.printStackTrace();
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!ECLoginActivity.this.isFinishing()) {
mDialog.dismiss();
}
/**
* 关于错误码可以参考官方api详细说明
* http://www.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1_e_m_error.html
*/
int errorCode = e.getErrorCode();
String message = e.getMessage();
Log.d("lzan13", String.format("sign up - errorCode:%d, errorMsg:%s", errorCode, e.getMessage()));
switch (errorCode) {
// 网络错误
case EMError.NETWORK_ERROR:
Toast.makeText(ECLoginActivity.this, "网络错误 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
break;
// 用户已存在
case EMError.USER_ALREADY_EXIST:
Toast.makeText(ECLoginActivity.this, "用户已存在 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
break;
// 参数不合法,一般情况是username 使用了uuid导致,不能使用uuid注册
case EMError.USER_ILLEGAL_ARGUMENT:
Toast.makeText(ECLoginActivity.this, "参数不合法,一般情况是username 使用了uuid导致,不能使用uuid注册 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
break;
// 服务器未知错误
case EMError.SERVER_UNKNOWN_ERROR:
Toast.makeText(ECLoginActivity.this, "服务器未知错误 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
break;
case EMError.USER_REG_FAILED:
Toast.makeText(ECLoginActivity.this, "账户注册失败 code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
break;
default:
Toast.makeText(ECLoginActivity.this, "ml_sign_up_failed code: " + errorCode + ", message:" + message, Toast.LENGTH_LONG).show();
break;
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
/**
* 登录方法
*/
private void signIn() {
mDialog = new ProgressDialog(this);
mDialog.setMessage("正在登陆,请稍后...");
mDialog.show();
String username = mUsernameEdit.getText().toString().trim();
String password = mPasswordEdit.getText().toString().trim();
EMClient.getInstance().login(username, password, new EMCallBack() {
/**
* 登陆成功的回调
*/
@Override
public void onSuccess() {
runOnUiThread(new Runnable() {
@Override
public void run() {
mDialog.dismiss();
// 加载所有会话到内存
EMClient.getInstance().chatManager().loadAllConversations();
// 加载所有群组到内存,如果使用了群组的话
// EMClient.getInstance().groupManager().loadAllGroups();
// 登录成功跳转界面
Intent intent = new Intent(ECLoginActivity.this, ECMainActivity.class);
startActivity(intent);
finish();
}
});
}
/**
* 登陆错误的回调
* @param i
* @param s
*/
@Override
public void onError(final int i, final String s) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mDialog.dismiss();
Log.d("lzan13", "登录失败 Error code:" + i + ", message:" + s);
/**
* 关于错误码可以参考官方api详细说明
* http://www.easemob.com/apidoc/android/chat3.0/classcom_1_1hyphenate_1_1_e_m_error.html
*/
switch (i) {
// 网络异常 2
case EMError.NETWORK_ERROR:
Toast.makeText(ECLoginActivity.this, "网络错误 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 无效的用户名 101
case EMError.INVALID_USER_NAME:
Toast.makeText(ECLoginActivity.this, "无效的用户名 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 无效的密码 102
case EMError.INVALID_PASSWORD:
Toast.makeText(ECLoginActivity.this, "无效的密码 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 用户认证失败,用户名或密码错误 202
case EMError.USER_AUTHENTICATION_FAILED:
Toast.makeText(ECLoginActivity.this, "用户认证失败,用户名或密码错误 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 用户不存在 204
case EMError.USER_NOT_FOUND:
Toast.makeText(ECLoginActivity.this, "用户不存在 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 无法访问到服务器 300
case EMError.SERVER_NOT_REACHABLE:
Toast.makeText(ECLoginActivity.this, "无法访问到服务器 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 等待服务器响应超时 301
case EMError.SERVER_TIMEOUT:
Toast.makeText(ECLoginActivity.this, "等待服务器响应超时 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 服务器繁忙 302
case EMError.SERVER_BUSY:
Toast.makeText(ECLoginActivity.this, "服务器繁忙 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
// 未知 Server 异常 303 一般断网会出现这个错误
case EMError.SERVER_UNKNOWN_ERROR:
Toast.makeText(ECLoginActivity.this, "未知的服务器异常 code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
default:
Toast.makeText(ECLoginActivity.this, "ml_sign_in_failed code: " + i + ", message:" + s, Toast.LENGTH_LONG).show();
break;
}
}
});
}
@Override
public void onProgress(int i, String s) {
}
});
}
}
消息的发送和监听
实现消息的接收需要添加EMMessageListener消息监听接口,我们在需要监听的地方要实现这个接口,并实现接口里边的几个回调方法:
onMessageReceived(List list)新消息的回调
onCmdMessageReceived(List list)新的透传消息回调
onMessageReadAckReceived(List list)消息已读回调
onMessageDeliveryAckReceived(List list)消息已发送回调
onMessageChanged(EMMessage message, Object object)消息状态改变回调
下边是聊天界面消息监听与发送的完整实现,代码注释比较详细,不再一一解释
package net.melove.demo.easechat;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextUtils;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.hyphenate.EMCallBack;
import com.hyphenate.EMMessageListener;
import com.hyphenate.chat.EMClient;
import com.hyphenate.chat.EMCmdMessageBody;
import com.hyphenate.chat.EMConversation;
import com.hyphenate.chat.EMMessage;
import com.hyphenate.chat.EMTextMessageBody;
import java.util.List;
public class ECChatActivity extends AppCompatActivity implements EMMessageListener {
// 聊天信息输入框
private EditText mInputEdit;
// 发送按钮
private Button mSendBtn;
// 显示内容的 TextView
private TextView mContentText;
// 消息监听器
private EMMessageListener mMessageListener;
// 当前聊天的 ID
private String mChatId;
// 当前会话对象
private EMConversation mConversation;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
// 获取当前会话的username(如果是群聊就是群id)
mChatId = getIntent().getStringExtra("ec_chat_id");
mMessageListener = this;
initView();
initConversation();
}
/**
* 初始化界面
*/
private void initView() {
mInputEdit = (EditText) findViewById(R.id.ec_edit_message_input);
mSendBtn = (Button) findViewById(R.id.ec_btn_send);
mContentText = (TextView) findViewById(R.id.ec_text_content);
// 设置textview可滚动,需配合xml布局设置
mContentText.setMovementMethod(new ScrollingMovementMethod());
// 设置发送按钮的点击事件
mSendBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String content = mInputEdit.getText().toString().trim();
if (!TextUtils.isEmpty(content)) {
mInputEdit.setText("");
// 创建一条新消息,第一个参数为消息内容,第二个为接受者username
EMMessage message = EMMessage.createTxtSendMessage(content, mChatId);
// 将新的消息内容和时间加入到下边
mContentText.setText(mContentText.getText() + "\n" + content + " -> " + message.getMsgTime());
// 调用发送消息的方法
EMClient.getInstance().chatManager().sendMessage(message);
// 为消息设置回调
message.setMessageStatusCallback(new EMCallBack() {
@Override
public void onSuccess() {
// 消息发送成功,打印下日志,正常操作应该去刷新ui
Log.i("lzan13", "send message on success");
}
@Override
public void onError(int i, String s) {
// 消息发送失败,打印下失败的信息,正常操作应该去刷新ui
Log.i("lzan13", "send message on error " + i + " - " + s);
}
@Override
public void onProgress(int i, String s) {
// 消息发送进度,一般只有在发送图片和文件等消息才会有回调,txt不回调
}
});
}
}
});
}
/**
* 初始化会话对象,并且根据需要加载更多消息
*/
private void initConversation() {
/**
* 初始化会话对象,这里有三个参数么,
* 第一个表示会话的当前聊天的 useranme 或者 groupid
* 第二个是绘画类型可以为空
* 第三个表示如果会话不存在是否创建
*/
mConversation = EMClient.getInstance().chatManager().getConversation(mChatId, null, true);
// 设置当前会话未读数为 0
mConversation.markAllMessagesAsRead();
int count = mConversation.getAllMessages().size();
if (count < mConversation.getAllMsgCount() && count < 20) {
// 获取已经在列表中的最上边的一条消息id
String msgId = mConversation.getAllMessages().get(0).getMsgId();
// 分页加载更多消息,需要传递已经加载的消息的最上边一条消息的id,以及需要加载的消息的条数
mConversation.loadMoreMsgFromDB(msgId, 20 - count);
}
// 打开聊天界面获取最后一条消息内容并显示
if (mConversation.getAllMessages().size() > 0) {
EMMessage messge = mConversation.getLastMessage();
EMTextMessageBody body = (EMTextMessageBody) messge.getBody();
// 将消息内容和时间显示出来
mContentText.setText(body.getMessage() + " - " + mConversation.getLastMessage().getMsgTime());
}
}
/**
* 自定义实现Handler,主要用于刷新UI操作
*/
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0:
EMMessage message = (EMMessage) msg.obj;
// 这里只是简单的demo,也只是测试文字消息的收发,所以直接将body转为EMTextMessageBody去获取内容
EMTextMessageBody body = (EMTextMessageBody) message.getBody();
// 将新的消息内容和时间加入到下边
mContentText.setText(mContentText.getText() + "\n" + body.getMessage() + " <- " + message.getMsgTime());
break;
}
}
};
@Override
protected void onResume() {
super.onResume();
// 添加消息监听
EMClient.getInstance().chatManager().addMessageListener(mMessageListener);
}
@Override
protected void onStop() {
super.onStop();
// 移除消息监听
EMClient.getInstance().chatManager().removeMessageListener(mMessageListener);
}
/**
* --------------------------------- Message Listener -------------------------------------
* 环信消息监听主要方法
*/
/**
* 收到新消息
*
* @param list 收到的新消息集合
*/
@Override
public void onMessageReceived(List<EMMessage> list) {
// 循环遍历当前收到的消息
for (EMMessage message : list) {
if (message.getFrom().equals(mChatId)) {
// 设置消息为已读
mConversation.markMessageAsRead(message.getMsgId());
// 因为消息监听回调这里是非ui线程,所以要用handler去更新ui
Message msg = mHandler.obtainMessage();
msg.what = 0;
msg.obj = message;
mHandler.sendMessage(msg);
} else {
// 如果消息不是当前会话的消息发送通知栏通知
}
}
}
/**
* 收到新的 CMD 消息
*
* @param list
*/
@Override
public void onCmdMessageReceived(List<EMMessage> list) {
for (int i = 0; i < list.size(); i++) {
// 透传消息
EMMessage cmdMessage = list.get(i);
EMCmdMessageBody body = (EMCmdMessageBody) cmdMessage.getBody();
Log.i("lzan13", body.action());
}
}
/**
* 收到新的已读回执
*
* @param list 收到消息已读回执
*/
@Override
public void onMessageReadAckReceived(List<EMMessage> list) {
}
/**
* 收到新的发送回执
* TODO 无效 暂时有bug
*
* @param list 收到发送回执的消息集合
*/
@Override
public void onMessageDeliveryAckReceived(List<EMMessage> list) {
}
/**
* 消息的状态改变
*
* @param message 发生改变的消息
* @param object 包含改变的消息
*/
@Override
public void onMessageChanged(EMMessage message, Object object) {
}
}
界面布局
界面的实现也是非常简单,这里直接贴一下:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>activity_login.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="net.melove.demo.easechat.ECMainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/ec_edit_chat_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="对方的username"/>
<Button
android:id="@+id/ec_btn_start_chat"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="发起聊天"/>
<Button
android:id="@+id/ec_btn_sign_out"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="退出登录"/>
</LinearLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>activity_chat.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="net.melove.demo.easechat.ECLoginActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/ec_edit_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="username"/>
<EditText
android:id="@+id/ec_edit_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="password"/>
<Button
android:id="@+id/ec_btn_sign_up"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="注册"/>
<Button
android:id="@+id/ec_btn_sign_in"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="登录"/>
</LinearLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>结语
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="net.melove.demo.easechat.ECChatActivity">
<!--输入框-->
<RelativeLayout
android:id="@+id/ec_layout_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true">
<Button
android:id="@+id/ec_btn_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="Send"/>
<EditText
android:id="@+id/ec_edit_message_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@id/ec_btn_send"/>
</RelativeLayout>
<!--展示消息内容-->
<TextView
android:id="@+id/ec_text_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/ec_layout_input"
android:maxLines="15"
android:scrollbars="vertical"/>
</RelativeLayout>
代码结束,Coding不止!Coding - Coding - Coding —
OK了,一个简单的注册登录以及收发消息的小demo就算完成了,可以用自己的环境编译运行下试试
本篇Android3.0集成教程由环信Android工程师lzan13编写,已同步发表到个人博客,博客地址lzan13 收起阅读 »
SDWebImage下载网络图片之提升用户体验
描述: 使用UIImage+ webImageCache下载网络图片, 自带内存缓存, 以及沙盒缓存;
基本方法:
[self.imageView sd_setImageWithURL: placeholderImage:];
方法描述:1.根据提供的url下载网络图片,并设置到imageView; 此时内存中会有一份缓存, 沙河中也会写入备份;
2. 当再次用到该图片时, 首先去内存中获取该图片, 内存中没有则去沙盒中加载, 如果都没有就会去网络下载;
注意:该方法底层会首先取消imageView之前的任务, 防止数据错乱.
// 取消iamgeView之前的下载任务方法总结
[self.imageView sd_cancelCurrentImageLoad];
解析: 因为该方法有一个完成回调block, 当有网络延时时,
下载图片太慢, imageview循环利用显示其他图片, 但此时前面的下载任务下载好了,
就会拿到imageView直接设置图片, 会导致数据错乱;
故在之前调用该方法, 可以防止数据引用;
1.0 取消当前imageView之前关联的请求
2.0 设置占位图片到当前的imageview
3.0 如果缓存(内存, 沙盒)中有图片则直接设置, 不使用占位图片
4.0 如果没有,则发送请求下载图片
Number two
怎么实现缓存,以及获取对应的图片
无论是内存缓存, 还是沙盒缓存都是以字典的形式保存图片, 因为SDImageCache使用了NSCache类
key : 图片的url; value: 下载的图片
Number three
代码实现:
核心概念:
根据不同网络,下载不同图片(省流量)
内存缓存中, 只保存当前显示的图片
其他只保存到沙盒, 用到时才会缓存到内存 (提高内存性能)
1.0 监听用户网络状态
AFNetworkReachabilityManager
// 程序启动的时候调用2.0 根据不同网络状态, 下载不同图片
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 监控网络状态
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
return YES;
}
// 占位图片3.0 处理缓存图片, 内存飙升问题
UIImage *placeholder = nil;
// 1.0 从缓存中获得原图
// 该方法会首先去内存找, 再去沙盒
UIImage *originalImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:originalImageUrl];
if (originalImage) { // 如果缓存有原图,那么就直接显示原图(不管现在是什么网络状态)
[self.imageView sd_setImageWithURL:[NSURL URLWithString:originalImageUrl] placeholderImage:placeholder];
} else {
// 2.0 缓存没有原图, 根据网络下载
AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager]
// 在使用Wifi, 下载原图
if (mgr.isReachableViaWiFi) {
[self.imageView sd_setImageWithURL:[NSURL URLWithString:originalImageUrl] placeholderImage:placeholder];
// 在使用手机自带网络
} else if (mgr.isReachableViaWWAN) {
// 下载小图
[self.imageView sd_setImageWithURL:[NSURL URLWithString:thumbnailmageUrl] placeholderImage:placeholder];
} else {
// 3.0 没有网络
UIImage *thumbnailImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:thumbnailImageUrl];
if (thumbnailImage) { // 缓存中有小图
[self.imageView sd_setImageWithURL:[NSURL URLWithString:thunmnailImage] placeholderImage:placeholder];
} else {// 没有小图
[self.imageView sd_setImageWithURL:nil placeholderImage:placeholder];
}
}
}
首先:
SDImageCache怎么处理内存问题?
// 清空沙盒过期图片 (七天为限)什么时候处理
- (void)cleanDisk;
// 清空沙盒内所有图片
- (void)clearDisk;
// 清空内存缓存所有图片
- (void)clearMemory;
// 获取自动清理缓存对象只有内存警告时才会处理?
_memCache = [[AutoPurgeCache alloc] init];
// 当接收到内存警告, 才会处理缓存
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(removeAllObjects) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
为了用户体验故需我们手动释放:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView解析: 为什么缓存中所有图片都清空了, imageView还能显示图片?
{
// 滚动时, 清除缓存
[[SDImageCache sharedImageCache] clearMemory];
}
图片字典的形式保存在缓存中, NSCache有保存所有的key, 每个key指向一个图片对象
[self.memCache removeAllObjects]会把指向图片的key清掉, 则没有强引用的图片会被释放;
但是当把图片设置到imageview上时, image指针会强引用图片, 故还能显示图片
图示:
另外一个问题:
由于使用模拟器测试,发现在滚动过程中, 释放内存造成有时卡顿效果, 故在具体使用时, 还得各自思量;
tips: 建议把该方法抽取为(UIImageView)一个分类, 以便代码复用;
有问题, 请留言... 收起阅读 »
JS区分浏览器中页面刷新与关闭标签页
文章摘要:js刷新当前页面,Web开发者在系统开发中经常要面对产品经理各式各样的需求,当然,大部分对产品体验还是有帮助的,例如我们今天提到的刷新页面,前进后退,关闭浏览器标签时,为了避免用户误操作,需给出二次确认提示框,这个相信大家都非常熟悉了,采用浏览器提供的BOM事件机制就可以...
Web开发者在系统开发中经常要面对产品经理各式各样的需求,当然,大部分对产品体验还是有帮助的,例如我们今天提到的刷新页面,前进后退,关闭浏览器标签时,为了避免用户误操作,需给出二次确认提示框,这个相信大家都非常熟悉了,采用浏览器提供的BOM事件机制就可以解决,使用window对象的onbeforeunload事件即可,如果产品经理只提出这样的需求,那确实无可厚非,然而其需要的不仅仅是这些...
例如,我们一次项目开发中,产品经理就针对我们的实现提出了“改进方案”:
- 你们这弹出框太丑了,跟系统整体风格不搭调啊,不能使用咱们自己组件库中的Dialog吗?很好的问题...我只想说,you can you up...
- 你们这刷新和关闭标签页中展示的文案一样啊,需要区分对待下,刷新提示XXX,关闭时提示SSS,这样用户才能更明确。恩,考虑到了用户的体验,很好,我还是想说,you can you up...其实,浏览器在关闭和刷新时,本身已经区别对待了,提示是不同的,只不过我们自定义的部分并不能显示不同的文案而已;当然,也有一些hack的方法,但是很难适应多个浏览器,各浏览器内部对于关闭标签页和刷新的实现机制会有所不同;
- 你们每次登录进来,为什么要延时10秒,才让坐席签入电话系统啊(我们做的是客服系统)?能不能把这个限制去掉啊,用户体验太不好了!我们也想去掉啊,但是电话系统频繁签入签出会有问题,用户刷新了浏览器,再次签入,如果相隔时间很短的话,电话系统会出现故障,为了避免这个问题,我们才加上了这个限制,但是回过头来思考,就可以进入我们今天讨论的主题了;
区分刷新与关闭标签页
我们无法根据浏览器事件区分刷新还是关闭标签页,进而在相应动作触发前,执行不同的动作,但是对于上文中产品提出的第三点意见,其实还是可以考虑优化一下的,就是只有在刷新的时候延时10秒,新登录或关闭标签页一段时间之后再进来时不延时;
要做到这点其实也很简单,使用浏览器的本地存储机制就可以实现,例如cookie,LocalStorage等,这里就不能使用SessionStorage了,因为本次回话结束后,该缓存就失效了;由于在cookie中存储会增加cookie的字节数,每次请求中相应的网络传输量会增加,因此,我们采用了LocalStorage;其操作很简单,我们使用的前端框架是AngularJS,具体如下:
const MAX_WAIT_TIME = 10;上面代码主要作用是,进入系统后,会先去LocalStorage中获取上次退出时的时间,再获取当前时间,两个时间进行减法,如果值小于10秒,我们就认为这是刷新,如果值大于10秒,我们认为是关闭标签页或新登录,进而可以执行不同的方法,让客服有更好的体验,不用每次进入系统都要等待10秒才能签入电话系统了,产品经理还是很重要的,吼吼,要不是他的疑问,可能我们也不会来优化这个地方了...当然,其实RD也要逐渐培养这种用户体验至上的思维,哪怕有一点可提升客服效率的地方,都值得我们花时间来优化;
const currentDate = new Date().getTime();
const lastestLeaveTime = parseInt(this.$window.localStorage.getItem('lastestLeaveTime'), 10) || currentDate;
this.secondCounter = Math.max(MAX_WAIT_TIME - Math.ceil((currentDate - lastestLeaveTime) / 1000), 0);
if (this.secondCounter > 0) {
this.logoutTimeInterval = this.$interval(()=> {
this.secondCounter--;
this.$scope.$digest();
}, 1000, this.secondCounter, false).then(() => {
this.updateByStatus(this.AvayaService.status.OFFLINE);
});
} else {
this.updateByStatus(this.AvayaService.status.OFFLINE);
}
下面把相关退出的代码也贴一下吧,前面忘说了,不管是刷新,还是关闭标签页,只要是页面销毁,我们都会去执行登出电话系统的操作,所以每次进来后需要重新签入;
//刷新页面或者关闭页面
$window.onbeforeunload = () => {
return '操作将会导致页面数据清空,请谨慎操作...';
};
//每次页面unload时,设置LocalStorage时间;我们可能还注意到一些问题,那就是刷新,关闭页面,前进后退,你需要跳出浏览器默认二次确认框,但是用户点击退出系统按钮,则必须弹出自己组件库中的Dialog了,还必须不能两个都弹出,具体代码如下:
$window.onunload = () => {
$window.localStorage.setItem('lastestLeaveTime', new Date().getTime());
};
onStatusClick(index, name) {收起阅读 »
if (name === '退出') {
this.mgDialog.openConfirm({
showClose: false,
template: 'app/header/logoutDialog.html',
controller: 'HeaderDialogController as dialog',
data: {
'title': '您确定要退出系统吗?'
}
}).then(() => {
this.$window.location.href = '/logout';
this.$window.onbeforeunload = null;
});
} else {
// 内部操作,大家不用管
...
}
}
一乐 :煎饼果子与架构模式
编者按:本文由一乐在高可用架构群分享,转载请注明来自高可用架构「 ArchNotes 」。
一乐是我,也是梁宇鹏。现任环信首席架构师兼 IM 技术总监,负责即时通讯云平台的整体研发和管理。曾任新浪微博通讯技术专家,负责微博通讯系统的设计与研发。一直专注在即时通讯领域,熟悉 XMPP 协议和相关的开源实现(包括 Jabberd2、EJabberd、Openfire)。关注分布式系统和高性能服务,关注 Erlang、Golang 和各种浪。
煎饼的故事
有一段时间住在花园路,最难忘的就是路边的煎饼果子。老板每天晚上出来,正好是我加班回去的时间。
一勺面糊洒在锅上,刮子转一圈,再打一个蛋,依然刮平。然后啪的一下反过来,涂上辣酱,撒上葱花。空出手来,剥一根火腿肠。最后放上薄脆,咔咔咔三铲子断成三边直的长方形,折起来正好握在手中。烫烫的,一口咬下去,蛋香、酱辣、肠鲜,加上薄脆的声音和葱花的惊喜,所有的疲劳都一扫而光。
这种幸福感让我如此迷恋,以至于会在深宅的周末,穿戴整齐跑出去,就为了吃上一个。也因为理工科的恶习,我也情不自禁地开始思考这份执迷的原因,直到最后,我发现了它的秘密。
作为街头小吃的杰出代表,能够经历众口的挑剔而长盛不衰的秘密是什么?
所有的一切全因为其模式。
而这模式与大多数互联网服务的架构如出一辙,那就是分层架构。
分层的设计意味着,每一层都独立承担单一的职责。
这在根本上降低了制作的难度。做饼的时候专心控制火候,做酱的时候专注在味道。每层职责的单一化也让优化变得简单,因为它是自然可伸缩的。你要是想多吃点蛋就多加一个,你要多吃点肠就多加一根,完全取决于你的胃口。
它又是可以扩展的。你可以不要蛋,你可以加根肠,你可以不要薄脆,你可以加上辣酱。而且每一层又是可定制的。葱花可以少一点,辣酱可以多一点,肠可以要两根,鸡蛋可以加三个。
你也可以把面饼换成面包,把鸡蛋换成煎蛋,把辣酱换成甜酱。你已经知道这是什么了吧?是的,你好,这里是赛百味,请问你要什么口味的三明治?
煎饼果子和三明治,其实本质上是相通的。而加一个蛋更香,也不是因为对蛋的追求,在根本上是因为煎饼果子模式的强大。
因为这种模式,一千个人可以有一千种煎饼果子。
而有了对模式的理解,对小吃的评估也就变得更加容易。比如肉夹馍只有馍和肉,二维切换单调不可长久;比如烤冷面,干脆就是满嘴的热烈混在一起,没有煎饼这样的表现层,整个面都散发着原始的不讲究。
这种对比上的简化,也让我们有了新的选择,保存宝贵的精力,并且可以随时放弃对细节的追究。
就像在我们谈论女人时,
(抱歉博主是男人)
我们在意胸、
在意腿、
在意风情、
在意温柔,
因为女人是有区别的。
当我们欣赏电影的时候,
我们在意男人、
在意女人、
在意老人、
在意孩子,
因为角色是有区别的。
当我们走在路上的时候,
我们在意行人、
在意车辆、
在意商店、
在意餐厅,
因为物体是有区别的。
我们在设计和优化系统的时候,其中的每个服务都是自行运转,做着自己份内的事,但是在不同的维度里,作用却变得不尽相同。
这也是我们讲优化要分层次和级别,架构、算法、库和 OS,而讲架构的时候,我们首先讲的是整体的模式,然后是具体的权衡,实现的细节则是最不重要的。
架构的模式
谈起这个,是因为 Mark Richards 写了一本架构模式的书《Software Architecture Pattens》。
书中总结对比了五种模式的优缺点,包括了 Layered、Event-Driven、Microkernel、Microservices、Space-Based。
书写得简单精致,推荐大家去阅读,地址见文末。
还有一种模式,因为在越来越多的系统中用到,是书中没有的(与 Space-Based 有所区别),但我觉得也有必要专门介绍下。我们开始在群发系统中实现,后来的抢购、红包和火车票的场景中也屡屡看到它的身影。
2013 年的时候,我们在微博做粉丝服务平台,一个类似微信公众号的群发系统。然而比后者更困难的是,当时在产品设计上并没有像微信一样新建用户体系,而是直接基于微博的粉丝关系,这就意味着一篇文章要能能在很短时间内支持亿级的用户推送。这个数量级的订阅用户,即使看今天的微信公众号依然是难以想象的。
当时有一套老的群发系统,都是基于 MySQL 的收件箱设计,在更换了 SSD 硬盘,又批量化数据库操作之后,整体写入性能依然只在每秒几万的级别,这就意味着一亿用户只能在 17 分钟内发完,我们意识到这套系统需要进行重新设计。
最终我们我们使用了一种新的架构方式,达到了每秒百万级别的速度,而且还可以更高。这种模式就是单元化架构。
下文介绍我参照了架构模式的说明方式,希望能够让大家有个对比,喜欢你可一定要说好!
单元化架构
如前所述,我们选择单元化的一个重要目的是为了性能,为了极高的性能。这比起一般的分层架构来讲,会获得更经济的结果,但也因此,牺牲了分层架构的一些特性,因为它的容量取决于单元的大小(关于单元等名词介绍,我会在下文介绍)。
虽然它支持按照单元扩容,但在单元内基本上每层的性能都是固定的。这更适合容量可预期的场景,比如大多数已经趋于稳定的业务。像前面的粉丝服务平台,虽然他下发消息量级巨大,但是在整体层面,使用平台的用户由于是 VIP 用户,其规模基本在在数百万级别,而粉丝量级也不太可能过亿。
重要的是,基于当时的业务数据,我们已经知道平均粉丝数在什么量级。而业务数据是架构选型的重要依据。商品秒杀、火车抢票等等都是一样。
当然也有例外。因为单元化架构作为一种思想,它不会局限在一台机器,一个机架,它也适用一个机房。当它的层次变大时,单元内自然就可以有变化的空间。每一层服务都可以分开伸缩。而到了这个层面,它的追求可能就完全不一样了。像阿里的双十一服务改造,会为了流量的分离,像 QQ 的聊天,会为了接入的速度。它们的基本思想是一致的。
至于单元化架构和煎饼果子的关系,我会在文后回答。
核心概念 Key Concepts
分区(Shard)是整体数据集的一个子集。如果你用尾号来划分用户,那么相同尾号的用户可以认为是同一分区。
单元(Cell)是满足某个分区所有业务操作的自包含的安装。我们从并行计算领域里借鉴了这个思想,也就是计算机体系结构里的 Celluar Architecture,在那里一个 Cell 是一个包含了线程部件、内存以及通讯组件的计算节点。 https://en.m.wikipedia.org/wiki/Cellular_architecture
单元化(Cellize)这是我的自造词,描述一个服务改造成单元架构的过程。
模式描述 Patten Description
单元架构最重要的概念,就是单元和单元的自治。
你可以将其想象成细胞,如之前所述,每个细胞都是自成一体,功能明确。你也可以将其想象成小隔间,就像你去了一个按摩院,每个隔间里都有技师和所有设备。我没有用前面那个名字,因为其有太强的生物学含义,也没有用后者,因为其有太多的服务性暗示。但是如果你有足够的想象力,其实什么名字都可以的。
说到单元的自治,即单元的自我协调和之间的隔离。单元既然做到了自包含,那么其中的所有组件,不管是否在物理上分离成了独立的服务,都是在一个单元内互相支持的,也就是跟其他单元内的同类和非同类组件都不会有任何交流。这也是跟基于空间的架构的重要区别,后者的处理单元之间还是会互相通信并同步信息。
这里的挑战就在于分区的算法。一个单元内的组件会很多,如果业务复杂,涉及到的数据也会很多,为了隔离,每一个组件都要能按照同样的算法进行分区。
本质上每个单元都是相似的,单元之间的区别或者取决于请求,或者取决于数据。而且越到大的层面,区分度越低,用户甚至是可以在不同单元间漫游的。
模式动力学 Patten Dynamics
单元架构的最典型目的,还是为了极高的性能,为了获得经济的高速度。这里一方面,是因为我们发现其他架构实际上是浪费了很多资源,每一层服务都运行在单独的操作系统上,而且都要通过局域网或者城域网中转。
与此同时,传统的互联网服务还是希望用一堆计算能力普通的节点来服务大量用户,而随着摩尔定律的推进,单机性能越来越高,网络通讯的成本随之变得耗费显著。这使得我们有机会也有动力在垂直方向进行扩展。
当你把更多的组件放在同一个地方的时候,你也在物理上获得了计算本地化的优势。这是我们获得性能提升的根本原因。
服务分成了很多单元,但总要跟外界通讯,这个事情是交给协调者 Coordinator 的。你可以在内部增加存储、缓存,增加队列和处理机,这些所有不交互的组件,理论上都不是外部资源可以访问的。
前面我们提到,单元化过程也是分区算法的应用过程。而这个分区算法放在哪里就是个问题。
我们可以封装运行库交给客户端,也可以做个代理层,内置算法。也有一些服务因为业务需要,请求需要复制到每个单元去。这就是典型的 Scatter-Gatter 模型,那么你还可能需要一个作业管理系统。这些都是可选择的使用方式。
模式分析 Patten Analysis
总体敏捷度低,易部署性低,可测试性高,性能高,伸缩性高,易开发性低。
基于篇幅原因,不再详述每一个方面,相信大家都能自行分析。唯一需要强调的是运维要求比较高。
单元化之后,所有的服务放在一起,在请求失败的情况下需要快速定位某个单元,这跟分层排除的思路是不一样的。如果运维团队不够高效,面对这样集群数量的暴涨(每个单元的服务数量相当于原来一个集群的服务数量),有可能是会被大量的工作压垮;如果运维团队分离比较明显,每种组件都是专门的团队来维护(这是我们在微博遇到的),那就会有排异反应的风险,因为每一个团队都有自己的权限和服务管理习惯,这里需要相当的协调工作来防止相互干扰。
后记
前面留的一个问题,煎饼果子跟单元化架构的关系。答案说起来很简单,你问问煎饼摊就知道了。
煎饼是分层的,煎饼摊是单元的。消息发送服务是单元的,但是索引维护是分层的。看模式要确定系统的范畴,从不同角度看,同样的东西是有不同意义的。这也是架构师要做的思考。
其实 IT 系统千百万,模式肯定不会止于这几种。但有了基础的模式,了解它们之间的相似和区别,对于我们设计自己的系统,思考其中的权衡都是有帮助的。
Q & A
1. 单元化设计与 Docker 的容器化思路是否相通?又有何差异呢?
一乐:应该是关注的点不一样,但不冲突。Docker 一般是在微服务架构下会使用的措施,但并不意味着不能用在其他架构上。一个单元内的各种组件,使用什么样的技术,都是新的选择。用 Docker 不错。
2. 对于分布式服务,单元化架构可能会带来数据一致性问题,这个一般如何解决?
一乐:可能我没有理解你场景,单元化一般不会带来一致性问题。因为 Sharding 之后,一块分区数据相当于完全属于一个单元,其他单元是被隔离访问的。
3. 单元化架构最小情况是单台机部署整体服务,资源方面如何规划?
一乐:这方面就要计算了,也就是进行容量规划,相信大家在这方面都很熟悉。一个需要注意的点是,单元化的架构应用在可预期的总体容量上时会省很多事。鉴于分区算法的固定,扩容方面,其实可以通过预先规划,在单机上再进行多单元混部的方式。
4. 单元与 app cluster(总服务器)之间是怎么进行关联的,是通过注册服务还是按照 hash 分派的,如果是 hash 分派,那么挂了怎么接回的,如果是注册服务,是怎么对应分派服务呢?
一乐:简单做就是 hash 分派,高级点就是注册服务,可以直接参照成熟的 Sharding 算法。任务只要到了单元内,就是单元自己的事了。如果你的 Job 有阶段性,可能要考虑 Job 状态记录以及请求处理的幂等性
5. 你觉得单元化架构的问题是什么?如果让你重新设计你会做哪些改进?
一乐:这个问题太聪明了,谢谢!单元化架构的问题,如之前所说,有一个扩容难题,有一个运维难题,有一个单点问题。扩容问题刚才说了,在三年前我们还没有 Docker 的时候,我们的服务隔离难度很大,现在已经今非昔比。一刀(Docker)在手,天下我有!单元的单点问题,你得考虑单元级别的主从同步,这方面常见的互联网技术就行。
6. 分布式架构经常讲究服务器无状态,这样可以单台服务器异常对整体服务无影响。但单元化意味着服务是有状态,如何保障高可用?
一乐:无状态只能是业务层,涉及到数据的不会无状态,因为数据就是状态的记录。保障高可用嘛,前面说了,先把主从做了吧。
7. 单元细胞内依然采用分层架构设计还是 ALL IN ONE 即可?
一乐:在讲单元化的时候,其实不要求单元内的组织模式,所以回答是都行。
8. “每秒百万级的推送” 除了采用这种单元化的架构模式使之成为可能对于基础的中间件如 队列 db 等的架构如何规划的?还要额外考虑哪些技术点或问题?
一乐:队列主要用来防峰,在高速服务里,如果再想扩容,肯定先走批量的路子。db 的规划其实是重点,单元化架构实际上算是以数据为中心的一种模式。额外的考虑其实跟之前都很像,不过要做一些特殊的处理,比如冷热数据的分离。
参考阅读
一个单元化架构的例子 http://t.cn/RqM5Ns0
Software Architecture Patterns http://www.oreilly.com/programming/free/software-architecture-patterns.csp
校长:技术成长四个阶段需要的架构知识
支撑微博千亿调用的轻量级RPC框架:Motan
Upsync:微博开源基于Nginx容器动态流量管理方案
小编:一乐最近也开了公众号,内容非常有特色,将复杂的道理说得如煎饼这么通透,所以别忘了识别二维码关注,错过这次小编琢磨最短都要再等一年。
本文策划庆丰,编辑王杰,想讨论更多架构设计,请关注公众号获取进群机会。转载请注明来自高可用架构「ArchNotes」微信公众号及包含以下二维码。
收起阅读 »
iOS 消息扩展
好友列表中通过自定义扩展消息来传好友的头像和昵称。
发送之前把头像和昵称通过EMMessage传递给对方(发送消息不光发给对方消息,并且把头像和昵称发给对方),接收的时候解析出来
EaseSDKHelper.m这个类里有一个发送方法 发送消息的时候通过消息扩展传给对方
#pragma mark - send message
+ (EMMessage *)sendTextMessage:(NSString *)text
to:(NSString *)toUser
messageType:(EMMessageType)messageType
requireEncryption:(BOOL)requireEncryption
messageExt:(NSDictionary *)messageExt{
....
message.ext = @{@"logo":@"头像",@"name":@"名字"};
....
}
消息页面的头像和昵称
EaseConversationCell.h
- (void)setModel:(id<IConversationModel>)model{
头像换成message.ext[@"logo"]
昵称换成message.ext[@"name"]
if (self.model.isSender) {
[self.avatarView sd_setImageWithURL:[NSURL URLWithString:@"http://img5.imgtn.bdimg.com/it/u=159694920,2166605543&fm=21&gp=0.jpg"] placeholderImage:model.avatarImage];
_nameLabel.text = @"自己的昵称";
}
else{
[self.avatarView sd_setImageWithURL:[NSURL URLWithString:@"对方头像地址"] placeholderImage:model.avatarImage];
_nameLabel.text = @"对方的昵称";
}
}
消息详情的头像和昵称(同理)
EaseMessageCell.h
- (void)setModel:(id<IMessageModel>)model{
头像换成message.ext[@"logo"]
昵称换成message.ext[@"name"]
}
做的时候花了好多时间研究 ,希望对后人有所帮助。 收起阅读 »
环信:全媒体智能客服时代的最佳实践
随着企业信息化需求的复杂多变,客户服务和体验理念的人性化和智能化,企业通信以及呼叫中心一直是ICT市场上不容忽视的领域。4月14日-15日,由CTI论坛主办的“2016中国呼叫中心及企业通信大会”在北京盛大召开,本次会议以“联络中心的数字化DNA”为主题,围绕企业通信、呼叫中心、下一代通信架构等内容为话题,继续推动ICT产业发展。包括环信等40余家领先的行业供应商展出了其最新产品和服务。同时,环信CEO刘俊彦受邀发表主题演讲,用环信的真实用户案例来诠释什么才是全媒体智能客服时代的最佳实践!
环信移动客服特装展台人头攒动,现场签约成功数单
环信CEO主题演讲,全程无尿点
随着云计算、大数据、移动互联网以及社交媒体的兴起,传统通信模式、企业和客户的交互方式和沟通形态,以及服务理念正面临着前所未有的问题和挑战,新的行业格局也正在形成。2015年作为中国企业级服务元年,同时也是SaaS服务元年,尤其在客服领域诞生了一大批以产品体验和技术创新驱动的SaaS公司,而以全媒体、智能化、移动化为主打的环信移动客服更是其中的翘楚,不到一年时间内服务了1万多家企业,并且在融资额和市场份额上也遥遥领先。
什么是全媒体客服?
环信CEO总结到:“来自不同媒体的服务请求均可以统一接入,一键回复,打造跨网、跨界、跨平台的极致客户服务体验。”链家自如客使用环信实现了全媒体客服,环信帮助链家自如客打通了来自App端的客服入口+网页端客服入口+微信端客服入口,不仅可以统一接入回复且后台数据打通共享。帮助链家自如客优化了客服团队,极大的提升了效率,节省了成本。
链家自如客使用环信实现全媒体客服
同时,环信还提供“一体化”客服工作台,支持从APP、微信公众号、微博、网页、呼叫中心等渠道接入,且每个不同渠道均有不同标识进行识别。
从传统呼叫中心到全媒体客服,一场“效率”革命
随着人口红利消失,呼叫中心的升级转型将越来越普遍,2015年中国劳动力规模由2012年的9.37亿降至9.11亿人。中国劳动力人口连续4年绝对值下降企业客服面临的“用工荒”将持续扩大,运营成本将越来越高,越来越多的企业将复制环信客户“学而思”的客服转型之路,从语音呼叫中心为主转而采用全媒体客服,拥抱移动互联网。
学而思以前部署有4套客服产品包括:1,呼叫中心。2,网页客服。3,新媒体客服。4,APP客服。同时对应4个客服团队支持,相互数据不打通,尤其自开通微信客服后,咨询量增长明显,由用户数据不打通带来的用户投诉增多。而且每年10—11月是教育行业的交费季,以前主要靠呼叫中心外呼,工作量巨大,效果不满意。学而思在2015年集成环信移动客服以后,服务模式改为APP内缴费,并在APP内提供客服支持。整个2015年缴费季,APP客服部门数十人完美解决了往年数百个语音客服的工作。环信CEO刘俊彦认为:“APP客服相比电话客服大幅度提供服务效率,全渠道客服也已经成为企业刚需。”
IVR进入触摸时代,自助服务的未来,智能机器人将大显神通
传统IVR,用户需要听完所有菜单再做选择。而现在主流的ITR导航,用户只需在手机上直接选择关注的问题,简单方便。其中神州租车就采购环信移动客服,其中的智能ITR大大缓解了人工客服压力。Gartner预测到2020年,ITR将完全取代IVR全面进入触摸时代。
神州租车使用环信智能ITR缓解人工客服压力
近期李世石1:4不敌AlphaGo的事件又将人工智能推上了风口浪尖。而环信是客服行业少数自主开发智能应答机器人产品的公司,环信知识库+智能聊天机器人可以帮助人工坐席挡住80%的常见问题。同时具有以下特性:1,灵活可定制的智能会话、自定义菜单导航功能。2,预置的行业知识库,行业相关的常见问答可以一键拥有。3,与现有知识库系统对接,机器学习,智能优化知识库。4,人机无缝配合,更少的成本,更好的客户体验 。
环信首推的人机混合服务极大提高客服应答效率
环信CEO表示“人机混合服务”将是现阶段最适合也是最具效率的客户服务方式。
服务式营销,从成本中心转向利润中心
随着客服中心不断的被新时代赋予新的含义,传统的客服中心也正逐渐从成本中心向营销中心和利润中心转化。其中移动电商标杆企业楚楚街就使用环信APP IM长连接技术实现了精准商品推荐。楚楚街精准营销四步走:1,通过“客户标签”功能+“大数据分析”找到目标群体。2,通过环信移动客服的精准营销推送接口,将富媒体商品信息定向推送给目标客户。3,只要APP没被卸载,哪怕APP在后台,用户手机都能收到消息推送。4,客户选择咨询或直接购买。
移动互联网的电话外呼——金融界为电话销售配置环信APP主动营销平台
近期,环信还上线了业界首个“客户声音”产品,可以通过热点话题分析发现新畅销商品,通过情感度分析发现服务问题,来帮助企业更好的来倾听客户的声音。
最后,环信CEO预测:“随着国内SaaS客服产品的逐渐成熟完善,中小企业将全面拥抱SaaS客服,建设全媒体客户关系中心。而传统大型企业也将增量部署全媒体客服,保护已有投资,拥抱移动互联网。”SaaS客服也将逐渐成长为一个千亿级市场。同时,环信CEO认为未来远程办公,移动办公和众包客服将解决客服行业人力资源不足的问题,而环信移动客服的手机端工作后台将提供很大的助力。
环信移动客服简介
环信移动客服是全球首创的全媒体智能云客服平台。支持全媒体接入,包括网页在线客服、社交媒体客服(微博、微信)、移动端客服和呼叫中心等多种渠道。环信移动客服基于环信业界领先的IM长连接技术保证消息必达,并通过强大的智能机器人技术极大降低人工客服工作量。
环信移动客服于2014年12月上线,截至2015年底,环信移动客服共服务了12000家企业用户,现已覆盖包括电商、O2O、互联网金融、在线教育、在线旅游、移动医疗、智能硬件、游戏等20大领域的Top10客户,典型用户包括国美在线、58到家、楚楚街、随手记、海尔、51talk,链家自如客等众多互联网和传统企业。根据易观国际发布的《中国SaaS客服市场专题研究报告2015》显示:截至2015年第三季度,环信移动客服在SaaS移动端客服用户覆盖占比为77.4%,以绝对优势稳居行业第一。
收起阅读 »
客户世界专访环信CEO:选择长赛道、主打全媒体、拥抱黑科技
SaaS(Software as a Service)技术在国内呼叫中心领域已兴起多年,但直到近两年才形成风暴式的发展。当前,不仅新型互联网企业愿意采用这种布署灵活、低成本、高效率的云端技术,大量传统企业也在服务升级的推动下向SaaS模式的客服系统过渡。据行业估测国内客服软件市场需求在200亿人民币左右,未来几年中国SaaS市场将保持30%以上的年复合增长率。2015年以来,随着2B市场被资本引爆,客服行业涌现出一批专注于多渠道、智能化一体的SaaS型企业,在激烈角逐的同时也为行业带来更多创新活力。
环信创立于2013年,经过不到三年的发展,其产品已从最初的即时通迅云平台,发展到智能移动客服系统、全渠道智能客服平台。2015年,环信的移动客服产品荣获工信部颁发“最具成长性APP应用奖”;同年10月,荣获第十一届“金耳唛杯”中国最佳客户中心技术产品奖。2015年底,在易观发布的《2015中国SaaS客服市场专题研究报告》中,环信移动客服在SaaS客服移动端用户覆盖占比77.4%,居国内市场第一。目前环信已经获得四轮,总计2200万美元的融资,成为即时通迅云和SaaS客服领域融资最快、资金最充裕的平台。
近期,《客户世界》杂志对环信即时通信云CEO刘俊彦进行了专访,刘俊彦先生畅谈了环信过去3年的成长历程及对未来市场的展望。
一、创造风口与把握机遇
2013年,现在已更名为中关村创业大街的海淀图书城里有一家远近闻名的“车库咖啡”,是当时IT创业者的聚集地,环信即起步于此。
2013年陌陌上市前后,社交软件的需求一时间变得非常之火,刘俊彦是这个领域的专家,当时找他咨询如何为APP开发聊天功能的人特别多,而单独开发一套APP聊天功能非常费时费力,于是他想到将即时通讯功能做成云服务的形式让用户自主集成,这样可以高效地帮助创业者发展。
“即时通迅云”作为即时通迅领域的创新概念由环信首次提出,产品推出后,随即获得了创业者和众多企业的认可和追捧,很短的时间内平台上就发展出上万家企业用户。“风口”的效应其实是无意间被创造出来的。
据刘俊彦介绍,环信的四位联合创始人都是技术出身,他本人曾就职于RedHat(红帽)公司,有着多年开源社区项目的开发经验。创业团队平均年龄在四十岁左右,算是中年创业,因为之前都在外企工作收入比较高,所以在创业之初没有太多经济压力,也非常清楚自己的优势。选择好了产品方向,大家就本着务实的原则向前努力,最初的办公地点就在“车库咖啡”,“七八个人占两张桌子,每天早晨来上班还要占座。”
2014年5月,车库咖啡对面开了一家叫“36氪”的孵化器。开业的前一天刘俊彦和伙伴儿们过去转了转,就碰到氪空间负责人,一番交流后对方马上邀请他们入驻“氪空间”。他们周一搬家刚入驻,下午就来了两拔VC,其中就有经纬的投资人,聊了两个小时后,第二天就签署了协议。
“第一次融资可以说是一个非常偶然、随意的过程,”刘俊彦说,“我们在创业的时候并没有融资的想法,也没想到以后要怎么挣钱,会有什么样的商业模式。唯一可以想象的是,如果有几万个APP在用我们的产品,每天有几亿人连接到我们的服务器上,用我们的聊天功能谈论社会热点,交友,购物,到那个时间点价值一定会显现出来。”
在资本的支持下,公司很快走上正轨。2014年10月起,环信投入大量资源开发移动客服产品,也即从原有的PasS(PlatformasaService)平台向上延伸,做SaaS产品。 “从即时通迅云上线的第一天起,就不断有用户来找我们,希望把聊天功能做成像淘宝旺旺那样的可以嵌入到APP里的客服工具。因此,移动端的客服产品可以说是在用户真实需求的趋动下自然而然地开发出来的。开始的时候你其实不知道商业模式,当你每天接触几百个用户,有几千个公司、几万个人在用你的产品的时候,商业模式自然而然就形成了。”
2015年4月环信移动客服上线,在当时的时间点上,APP中有内置客服的产品只有“淘宝旺旺”和京东的“叮咚”。通过把PaaS平台的老用户成功转化为SaaS平台的新客户,环信在自己创造的风口上再次成为了移动端客服软件的领跑者。2015年5月环信获得B轮1250万美金融资,签约付费客服席位4万个,典型用户包括国美在线、58到家、楚楚街9块9等上百家互联网知名企业。
2016年伊始,环信基于当前客服市场对统一解决方案的需求再次推出全渠道智能客服产品。
二.以机器人、大数据确立竞争优势
据2015年“双十一”天猫的销售统计数据,接近70%的订单来自移动客户端,这意味着客户服务未来会越来越多地向移动端倾斜。同时,社交媒体的发展不仅连接了人与人、人与商业,未来还将连接一切,因此这种连接的价值一定要在未来的客服软件中体现出来,而客户不仅仅是通过微博、微信等社交工具向企业寻求帮助,还会有更多的用户之间的互动与互助需求需要被满足。刘俊彦认为移动化、社交化、智能化与个性化是未来客服软件产品应该具备的特性。未来客服工具不仅要具备全渠道接入、质检、统计、知识库查询等基础功能,还需要智能化和大数据的能力来帮助客户更好地提升服务效率并进行精准的二次营销,帮助企业客服中心成为真正的利润中心和价值中心。此外,SaaS客服软件具有的定制化优势可以很好地满足客户个性化需求,企业用户可根据自己的特点和需求自定义设置系统模块。
针对未来客服产品的发展趋势,环信产品目前除了拥有完善的基础功能外,还在机器人研发及大数据分析方面做了大量的投入和部署。据刘俊彦介绍,目前人机混合的智能机器人问答、客户画像等先进技术已进入生产内测环节。未来环信产品的差异化优势除了原有IM长连接技术外,将更多体现在商业化智能分析、智能机器人问答、大数据分析与挖掘等方面。黑科技领域的技术优势将在下半年的竞争中逐渐显现出来。
“我们现在做人机混和,当机器人回答不了客户问题时,会转人工座席,人工座席回答的同时,我们会把会话同时‘喂’给机器人,机器人不断的自动学习人工坐席的回答,并根据知识库和以前的知识积累,自动提示座席回答内容,座席看到提示靠谱,只要点击一下就可以发送给客户,这对工作效率是极大的提高。”
刘俊彦说:“资本投入上的差异是非常关键的,研发上的投入一定能从产品上体现出来。我们花了大力气和大价钱找到最优秀的人才加入我们。像人工智能、机器学习领域的顶尖人才,说服他们加入,光靠好的待遇是不够的,更重要的是用愿景来打动他们。”环信目前拥有180名员工,其中90是研发人员,是一支技术导向型的团队。
统计资料显示,中国目前企业总数5000万家,而IT普及率不及5%。对标美国市场,美国的企业总数不及中国企业数量多,但IT普及率达到50%。在企业服务领域,美国有四五家几千亿美金市值的巨头公司,如微软、SAP、ORACLE等,但在中国SaaS领域还没有大型公司出现。当前中国大量的企业在做“互联网+” ,谁来满足这批用户的需求,就有可能成为中国企业级服务市场的巨头。“这是一个非常大的增量市场,我们能吃下十个亿就是一个很好的公司了。”刘俊彦对市场未来充满信心。
有人把未来世界的产业格局划分为三个维度,一维:传统产业;二维:互联网产业;三维:智能科技产业。而将二维产业升级为三维产业的关键力量是大数据的崛起。未来一切竞争归结到最后都是数据的竞争。当前,智能客服机器人和大数据技术是带动整个服务产业升极的核心技术。
从用户需求出发,选择长赛道、拥抱尖端技术,做市场的引领者是环信始终的选择。
三.访谈实录
Q:目前的很多大型传统型企业已经有了成型的传统呼叫中心平台,您如何看待他们对全渠道平台的引入?
A:这些企业之前自建投入非常大,我们的策略是让他们在继续保留这些投资的同时,帮助他们拥抱移动互联网。我们提供一套在线客服系统,让他们可以连接微博微信网页和APP,不仅有KPI考核、统计等常用功能,还有先进的机器人客服,可以和原有呼叫中心无缝打通,比如一个人以前通过电话找过你,再通过微信,网页等渠道进来,你依然可以识别他,并且知道之前的交互记录,数据是完全互通的。而且还能做统一排队,比如一个服务交互在微信上没有解决问题,客服人员提示客户电话接入,这时电话再次接入到的一定是刚才服务过你的那个座席。因此客户可以在投入不大的情况下就可完成“互联网+”的升级。
Q:您提到统一排队的概念,我想深入问一下,这也是我在很多客户那里遇到的问题 。因为在线渠道是即时的,语音渠道是实时的,比如一个提供三种服务的座席,也叫全技能座席,正在接听一通电话,这时有一个实时的微信推送过来。正常来讲排队系统应该能识别到座席的状态不能接入这个业务,对于这个问题,您是怎么解决的?
A:这是很多做客服软件的厂家遇到的一个特别大的困扰。我们针对大型用户的解决方案一般会把语音座席和即时座席分开,因为实时和即时不可能做到统一排队,这是两个互斥的行为。我们提供一种最佳解决方法,软件是一个全技能的座席软件,座席也是一个全技能的座席,但是状态可以切换,比如企业准备在晚上6点多做一个促销活动,预测6点半从微信、APP渠道会接入大量客户请求,那么这个企业6点25分把十个座席从语音状态全部切换到在线座席的状态,同一组人、同一台PC、同一个软件实现渠道间的切换。我们认为做到这点就很好了。
Q:您的 SaaS平台,如何保障客户的数据安全?
A:我们从以下几个层面保护:首先我们和每个用户都有签署严格的法律协议,公有云上客户的数据全部是客户自己的,我们不会碰,客户有完全的处理权。第二从技术架构上进行运维监控,我们内部的运维人员分层,公司里目前只有两个人,不包括我在内能进入到数据库,其他运维人员只有服务的运维权限没有数据权限。而他们也和公司签定了严格的法律协定,任何一举一动都会被系统监控。出了未经授权的问题会承担法律责任。第三,我们是一个多租户系统,租户间的数据都是完全隔离的。第四我们长期聘请第三方安全公司对公有云平台做扫描,进行服务升级,确保不出现任何安全上的漏洞。
Q:关于“客户画像”,你们在具体服务中是帮助客户做一些分析还只是把数据给到客户让他自己去分析?
A:用户画像是主动营销的核心技术,举个例子,我们有个规模很大的电商用户,在后台做了一个大数据挖掘,找到2万名妈妈,打上标签,然后再从中找到所有2-4岁小孩的妈妈2千名打上标签,通过我们客服软件的群发接口给目标用户推送儿童汽车坐椅的消息。客户点击后并不是进入一个广告页面,而是进入一个和真人对话的一对一的聊天页面。这种营销方式比企业之前毫无差异地群发广告提高了20多倍的客户转化率。这项技术有两个核心点,一是基于大数据的用户精准画像和标签;二是APP主动营销,这是对过去外呼时代呼叫中心主流营销模式一个质的改变。可以理解为它是一种APP的外呼技术,代替了以往的电话通道,但对用户干扰非常小。
Q:我们的产品可否满足运营人员对于管理工具的定制化需求?在使用中客制化是否方便、速度如何?
A:我理解这个问题的核心是报表和统计,再往上说是数据和挖掘。以前的软件产品会提供很多报表,但这个时代过去了,因为对于太多的报表客户经常会不知道怎么用,而且用户永远都有层出不穷的新报表需求,那种写死的报表无法与时俱进。我们现在所有的数据分析和报表都是基于发现式的BI和大数据挖掘。以前的报表改不了,而发现式BI则是根据大数据引擎不断挖掘出各种结果。用户可以自行灵活配制界面,你需要什么指标,什么图都可以自行配制。新时代的大数据公司全是做这种发现式的报表,这是一项非常核心的技术。
Q:我们能满足企业自建平台的需求吗?
A:会满足,因为中国现状是这样,尤其是投资、金融、印刷等行业有严格规定,数据就是不能出公司。我们也是可以做私有云。私有云客单价高。
Q:我看到环信经常发布一些交流活动信息,比如组织iGEEK GAMP沙龙、APP运营沙龙?这些活动举办的初衷是什么?影响如何?
A:我们的PaaS产品(即时通迅云)为我们的SaaS产品贡献了很多优质客户流量,我们需要用这种社区的方式来维护和构建深度的开发者关系。我们认为,未来客户管理产品将是一个生态体系中的产品,SaaS产品只是一个基础软件,上边会长出很多小的分支,比如一些定制化需求,由其它的第三方团队来做,我们给他们提供API接口,进行定制化开发。我们通过环信的这些社区活动聚集了一批开发者团队,这也是为我们未来生态圈的布局做积累,做蓄水池,这是其他行业竞品所不具备的。 从产品角度来说,做客服软件最大的痛点就是刚才提到的高级和大型用户的复杂定制化需求,如何解决,就是通过环信的PaaS平台,把基础功能开放出来,不仅做自己的产品也让合作伙伴在这个平台上做二次开发,比如开发者可以在我们平台上做一个专门的报表模块。这应该是所有的SaaS厂商的必由之路,但这需要底层的平台有很好的扩展性和开放性,这在技术上的门槛非常高。
这实际就是生态圈的玩法。生态圈相当于一个核武器,超越产品是有可能的,但想超越生态圈难度太大了。
收起阅读 »
关于昵称头像用户信息存储讨论
---------割---------
写在前面的话:
集成环信即时通讯的时候,相信大家都有问过这个问题,“昵称头像怎么实现?”
如果你的你的昵称头像已经实现,请直接跳到文章末尾进入讨论!
在回答这个问题前先简单介绍下环信对于昵称头像的设计:
环信只是即时通讯的消息引擎。环信本身不提供用户体系,环信既不保存任何APP业务数据,也不保存任何APP的用户信息。比如说, 你的APP是一个婚恋交友APP,那么你的APP用户的头像,昵称,身高,体重,注册电话号码,注册邮箱等信息是保存在你自己的APP业务服务器上,我们服务器端不保存任何用户具体信息。
环信这样设计的目的有2个:
1. 尽量少的侵入开发者自己APP的业务数据和用户体系。用户体系是一个APP的最最核心的数据,在当前中国的环境下,部分开发者会比较难信赖一个第三方厂商,把自己最关键的用户体系信息托管到一个第三方平台上。
2. 大多数APP都有自己的服务器后台,有自己的用户体系。所以环信要尽力做好的环节是尽可能方便开发者把环信和自己的用户体系集成,而不是为开发者提供他们可能并不会用的用户体系。
不知道大家看明白了没有,如果有疑问接着往下看
集成环信即时通讯在实现昵称头像方面推荐两种做法
方法一 从APP服务器获取昵称和头像
方法二 从消息扩展中获取昵称和头像
关于两种方案的实现思路与对比优缺点在连接后面也有阐述。
思路给出来,大家就按照着做吧,在做的过程中也收到了一些小伙伴们的吐槽,能不能有现成的参考呀?于是环信在后来的demo中就实现的昵称和用户信息,小伙伴们又可以愉快的敲代码了!
关于demo 的昵称头像需要给大家说明的,这里非常重要,请接着往下看:
demo使用的的存储使用了parse的服务,有一些开发者可能会直接copy了demo中的代码也使用了parse来存储昵称和用户信息,parse的服务快要到期了,还有两个月就会迁走,我们想统计下有哪些用户用了parse的服务?
今天要讨论的事情就这么多,大家如果使用了parse请告诉我们,作为环信的用户肯定是要对大家负责的,会给出一个解决方案,或者直接提供一套这样的服务。
收起阅读 »
没有表情呢
环信直播课堂第七期--3.xSDK实时音视频的集成
持续时间:半小时
描述:教你如何从零开始,用环信ios sdk实现即时视频和聊天
本期环信直播课堂将由环信IOS工程师fudh给大家详细讲解集成3.0 SDK实时音视频
直播观看地址: http://www.imgeek.org/video/15
视频回放地址:http://www.imgeek.org/video/24 收起阅读 »
环信CEO:从传统呼叫中心到全媒体客服,一场“效率”革命
2016年4月8日,由江苏智恒发起的《企业通信与呼叫中心技术发展论坛》在江苏南京圆满落幕。环信做为全媒体智能云客服倡领者受邀参加了本次行业盛会,环信CEO刘俊彦在大会与现场的数百位行业精英一起分享了题为《全媒体智能客服时代的最佳实践》的主题演讲。
本次论坛活动旨在促进新兴通信技术在企业通信呼叫中心领域的推广、提高企业的通信能力、提高企业部署通信和客户服务平台时的策划水平。包括开源软交换技术,基于浏览器模式的实时通信技术,视频直播技术,呼叫中心领域中的智能化和多渠道客户体验技术。
2015年作为中国企业级服务元年,同时也是SaaS服务元年,尤其在客服领域诞生了一大批以产品技术驱动的SaaS公司,而以全媒体、智能化、移动化为主打的环信移动客服更是其中的翘楚,不到一年时间内服务了1万多家企业,并且在融资额和市场份额上也遥遥领先。
从传统呼叫中心到全媒体客服,一场“效率”革命
随着人口红利消失,呼叫中心的升级转型将越来越普遍,2015年中国劳动力规模由2012年的9.37亿降至9.11亿人。中国劳动力人口连续4年绝对值下降企业客服面临的“用工荒”将持续扩大,运营成本将越来越高,越来越多的企业将复制环信客户“学而思”的客服转型之路,从语音呼叫中心为主转而采用全媒体客服,拥抱移动互联网。
学而思以前部署有4套客服产品包括:1,呼叫中心。2,网页客服。3,新媒体客服。4,APP客服。同时对应4个客服团队支持,相互数据不打通,尤其自开通微信客服后,咨询量增长明显,由用户数据不打通带来的用户投诉增多。而且每年10—11月是教育行业的交费季,以前主要靠呼叫中心外呼,工作量巨大,效果不满意。学而思在2015年集成环信移动客服以后,服务模式改为APP内缴费,并在APP内提供客服支持。整个2015年缴费季,APP客服部门数十人完美解决了往年数百个语音客服的工作。环信CEO刘俊彦认为:“APP客服相比电话客服大幅度提供服务效率,全渠道客服也已经成为企业刚需。”
IVR进入触摸时代,自助服务的未来,智能机器人将大显神通
传统IVR,用户需要听完所有菜单再做选择。而现在主流的ITR导航,用户只需在手机上直接选择关注的问题,简单方便。其中神州租车就采购环信移动客服,其中的智能ITR大大缓解了人工客服压力。Gartner预测到2020年,ITR将完全取代IVR全面进入触摸时代。
近期李世石1:4不敌AlphaGo的事件又将人工智能推上了风口浪尖。而环信是客服行业少数自主开发智能应答机器人产品的公司,环信知识库+智能聊天机器人可以帮助人工坐席挡住80%的常见问题。同时具有以下特性:1,灵活可定制的智能会话、自定义菜单导航功能。2,预置的行业知识库,行业相关的常见问答可以一键拥有。3,与现有知识库系统对接,机器学习,智能优化知识库。4,人机无缝配合,更少的成本,更好的客户体验 。
最后,环信CEO预测:“随着国内SaaS客服产品的逐渐成熟完善,中小企业将全面拥抱SaaS客服,建设全媒体客户关系中心。而传统大型企业也将增量部署全媒体客服,保护已有投资,拥抱移动互联网。”SaaS客服也将逐渐成长为一个千亿级市场。
环信移动客服简介
环信移动客服是全球首创的全媒体智能云客服平台。支持全媒体接入,包括网页在线客服、社交媒体客服(微博、微信)、移动端客服和呼叫中心等多种渠道。环信移动客服基于环信业界领先的IM长连接技术保证消息必达,并通过强大的智能机器人技术极大降低人工客服工作量。
环信移动客服于2014年12月上线,截至2015年底,环信移动客服共服务了12000家企业用户,现已覆盖包括电商、O2O、互联网金融、在线教育、在线旅游、移动医疗、智能硬件、游戏等20大领域的Top10客户,典型用户包括国美在线、58到家、楚楚街、随手记、海尔、51talk,链家自如客等众多互联网和传统企业。根据易观国际发布的《中国SaaS客服市场专题研究报告2015》显示:截至2015年第三季度,环信移动客服在SaaS移动端客服用户覆盖占比为77.4%,以绝对优势稳居行业第一。 收起阅读 »
你的公众号为什么总是留不住粉丝?
当然,每天少数几个粉丝取关确实是正常的,特别是在文章推送或者微信活动之后,会出现较平常多的掉粉现象。正常的粉丝取关可以起到甄别非目标受众,为微信公众号沉淀优质粉丝的良好作用。
然而,对于很多刚刚起步的公众号来说,当看到自己的粉丝好不容易涨了三十个,却掉了十五个,相当痛心的一件事不是吗?你仍然紧盯着如何如何快速涨粉,关注着又新增了多少多少个,唯独忽视了取关的那部分;或者看到了,然后惋惜一下,就再没有然后了。第二次、第三次,以致每一次,掉的粉丝快赶上增的粉丝了,还能无动于衷吗?
草莓君认为,公众号无论大小,粉丝无论多少,当每天持续不断有较多粉丝流失时,该停下来,认真找找原因:为什么粉丝会取关?怎样减少粉丝的再取关?
>>>>从粉丝关注解读粉丝取关的深层原因
为什么会关注一个公众号?无非是因为它对于关注者来说,有价值。这种价值有多种表现形式,可能是对受众有某种知识方面的教导(如:运营干货、化妆技巧);可能为受众提供了即时资讯(如:早间新闻、一天热点);也可能给受众带来精神层面的满足(如:笑话、情感读物);当然这只是内容方面的价值。
还有一些公众号,通过二次开发,作为为受众提供实实在在服务的工具而存在,比如订票类公众号。往往,这种带有实质性服务的公众号,粉丝粘性会更高,因为关注的用户确实并且持续需要这样的服务。
由此就可以推断出:取消关注一个公众号,往往是因为它所提供的价值不能满足需要,对于关注者而言,没有了存在的意义。我为什么要留着一个对我毫无用处的东西呢?果断取关就在一瞬间。
好比,“活动盒子”公众号的定位是为广大运营人员提供运营干货、营销技巧,粉丝关注之后却想要知道如何做具体的抽奖活动,两个目的出现了分歧,公众号无法提供这样的服务来满足粉丝的要求,粉丝得不到她想要的,最终也就取消了关注。
>>>>从公众号的内容了解粉丝取关的基本原因
1、推送的内容和微信公众号的定位有过大的出入,主题混乱,不按常理出牌。一个美食公众号整天教你怎样化妆,做运营干货的老发心灵鸡汤,这得多突兀啊。完全就是怎么任性怎么来,粉丝本来就是冲着能提供如定位所说的价值而关注的,内容一旦脱离了定位,价值也就不复存在了。对广大粉丝来说,现在不取关更待何时呢?因此,不要轻易改变公众号的定位,推送不相关的内容。
2、推送的内容质量低、伪原创乃至同质化严重。据统计,2016年微信公众号的数量已超千万,每天推送的消息多达70万条,再加上公众号之外的网络平台,受众每天接收的信息不计其数,有太多的途径可以选择。
当所关注的公众号长期推送一些东拼西凑的伪原创文章,或者直接转载一些被转烂了的文章,又或者老写一些流水账式的文章,毫无亮点可言。最终会让粉丝觉得,这就是一个随随便便的公众号,没有实质的内容引起自己的兴趣和共鸣,自然选择了取关,再选个更符合自己要求的同类型公众号进行关注。
图片来源:企鹅智酷
3、微信公众号长时间不推送,成为名副其实的“僵尸号”。公众号又分为服务号和订阅号,订阅号每天都可以推送一次,而服务号只能每个月推送四次。但不管是什么号,如果粉丝长时间等不到内容更新,每次点开都只有N久前的消息,活跃度低的可怜,也就被当成一个“弃号”取关。
因此,对于推送的一些建议,盒子君认为:服务号应该每个星期推送一次,每个月四个星期,正好用完四次推送。订阅号的话,要按照每个号的性质和定位来决定推送的周期,像某些新闻、资讯、每日定点更新类的必须一天推送一次;而其它的如果不是每天推送,最好也要定好隔几天推送一次或者一个星期推送几次。目的就是在粉丝面前刷存在感,增加活跃度。
4、内容排版混乱,阅读体验太差。想象一下,读一篇文章,图片忽大忽小,忽左忽右;文字不分段,全堆在一起;这里明明用的是宋体,那里又变成了黑体;该表明小标题的地方又没有标出来;错别字还一揪一大堆。几千字的文章用手机阅读本来就够呛,又各种排版混乱,还能好好读下去吗?
如果说是赶时间推送,几次的失误就算了,次次都是这样,再好的文章,印象分也被磨灭了。忍无可忍之时就是取关之日。所以,请多花点时间,认真做好排版,让受众看的舒服。
5、推送的内容带有明显的广告营销性质。如果你没有达到相当的水准,请不要轻易给自己的文章插入广告。不要把粉丝当傻瓜,也不要妄想着你的粉丝会为你的广告买单,目的和利益性太过明显只会让粉丝觉得烦,久而久之也就取关了。当然,如果你能达到“王左中右”公众号中,文章广告插入的炉火纯青程度就完全没有问题了。
图片来源:公众号“王左中右”
>>>>从细节方面分析粉丝取关的可能原因
粉丝留言处理不当,引起不满甚至反感。有些公众号显得过于高冷,极少回复粉丝留言,或者回复的官方敷衍,这都不利于增强粉丝粘性。
通常粉丝留言说明对文章表现出了强烈的兴趣,不管好坏,都是一种反馈。作为公众号的运营人员,应该及时处理好粉丝留言,特别是提出了某些疑问等待回答的,要在第一时间发现并答复,让粉丝感觉得到了该有的重视。另外,如果粉丝表达了自己的反对观点,应该表示理解,不能用过激的语言进行争辩,作为一个公众号,必须展现出大度。
另外,粉丝互动不够、文章推送时间没选好也会影响到粉丝取消关注的情况。
总而言之,如果微信公众号粉丝出现较为异常的取关情况,可以从以上几大方面入手分析挖掘原因,然后对症下药,防止粉丝再流失。但并不是所有的粉丝取关都是不好的,我们需要正确看待这件事。
文/活动盒子
收起阅读 »
【产品快递】WebIm V1.1.0发布,网页端新增聊天室功能
版本:V1.1.0 2016-4-6:
功能改进:
1. 将表情包移除sdk,变为可自定义导入配置。
2. 增加XMPP连接多resource支持的参数。
3. 对于不支持wss,如qqX5内核浏览器,自动降级为https long polling。
4. 增加聊天室功能,在线聊天室列表,加入聊天室,退出聊天室等接口
5. 与之前版本sdk部分api已不兼容,添加shim.js,做降级支持
6. 新增消息发送的成功失败回调
7. 重整目录结构,优化代码,bug fix
easemob webim sdk已支持如下功能:
1.sdk本身已支持IE8+、FireFox、Chrome、Safari之间文本、表情、图片、音频消息相互发送
2.sdk支持web端之间,web端与app端相互添加、删除好友功能
3.sdk支持与ios、android sdk见相互发送文本、图片、音频消息
4.sdk提供部分公共方法,具体参见quickstart.md
5.sdk对于消息的处理方式如下:
1)文本消息,直接发送,接收方接收到为文本消息
2)表情消息,sdk得到表情对应的编码后,发送的文本消息,接收方接收到后处理根据编码还原表情
3)图片消息,sdk上传图片到聊天服务器,然后发送图片基本信息消息,消息中带有发送方上传的图片url等,接收方根据图片url、secret和自身的登录信息,以流的形式从服务器上下载图片到本地显示
4)音频消息,sdk上传音频到聊天服务器,然后发送音频基本消息消息,消息中含有发送方上传的音频url等,接收房根据音频url、secret和自身的登录信息,以流的形式从服务器上下载音频到本地播放
6.跟随sdk会有简单的demo,方便大家参考,已实现简单的聊天添加删除好友功能。
7.对于amr格式音频FF、Chrome、IE、Safari已实现接收方对收到后音频下载,调用本地播放器实现播放。
8.支持群组线聊天功能,显示群组成员列表
9.支持陌生人聊天功能
测试环信WebIM请访问 https://webim.easemob.com
登录可以使用环信UIDemo的账号和密码(见http://www.easemob.com/demo)
环信WebIM快速入门文档请见:https://github.com/easemob/web-im/blob/master/static/sdk/quickstart.md
更多关于环信的开发文档请见:https://docs.easemob.com
WebIm V1.1.0 下载
↓↓↓
收起阅读 »
环信视频直播在线技术支持下周正式上线
详情如下
在咨询问题的过程中,描述不清楚问题怎么办?
解决问题的过程中,工程师给出的解决方案自己看不懂怎么办?
环信视频直播答疑已开启,面对面交流,工程师还通过分享桌面的形式演示,以后再也不用担心交流困难,看不懂解决方案了。
不知道小伙伴们去体验了没有?反正用过了都说好用哈!
这里要做一个公告:“视频直播技术支持暂停一周,下周正式上线!”
这周我们在做界面还有内容优化,保证下次上线时给各位开发者童鞋更好的体验!
当然如果小伙伴们上班过程中因为环境限制不能观看直播,也可以去原有的渠道联系环信技术支持哈。
最后就是欢迎大家吐槽啦,对视频直播技术支持有任何问题建议欢迎评论留言,老规矩,直接现金打赏! 收起阅读 »
环信荣获2015开发工具及服务年度最佳品牌影响力奖
即将于2016年1月15日举办的【2015开发工具及服务年度大奖评选颁奖典礼】上,除各个获奖厂商前来领奖外,主办方还为所有获奖厂商制作珍藏版纪念奖杯,表彰其过去一年来的卓越成绩,以期鼓励开发工具及服务从业者在2016年继续耕耘,为行业贡献更全面细致的服务、更夯实稳健的工具。
随着开发工具及服务不断涌现,从云服务、即时通讯、安全到统计监测、人工智能、物联网平台等,越来越多的从业者提供了优质的服务,也有越来越多的开发者从中受益,综合提高了开发效率。2015开发工具及服务年度大奖评选是CSDN创立的针对开发工具及服务的评选大奖,目的在于推动开发服务及工具质量的提升,提高行业的专业性,表彰行业内的优秀的工具/服务提供商,从而激励整个行业的从业者,促进行业的发展。
最佳品牌影响力奖
【环信】
入选理由:
2015年,环信进击移动客服领域,由PaaS到SaaS。旗下拥有两个产品,IM云和移动客服,一个是PaaS一个是SaaS,两个产品的技术跨度比较大,但基于自身PaaS的SaaS产品的优势也不言而喻,环信未来会将移动客服推向两个方向:一是更智能,二是建立生态圈和平台。收起阅读 »
环信首席架构师:一个单元化架构的例子
为什么要有架构实践?
很多人喜欢的是细节,因为有句名言叫魔鬼在细节里,于是都去细节里寻找魔鬼。但是打败了魔鬼就能看到天使么?未必。细节其实是最容易掌握的部分,细节之外还有很多。就像有了水泥和沙子,你能够做出混凝土,但是离建成高楼大厦还有很长的路要走一样,你要学着去设计架构。
但是事情并没有完,就像没有唯一的真理一样,架构也并不是只有一种。你不可能一朝学会,从此天下无敌。如果要赈灾,你需要的是帐篷,如果要重建,你需要的是瓦房。不同的住所需要的是不同的架构。
不同的服务也需要不同的架构设计,这也就是我们需要架构实践的重要原因。在这之后的原因,是我们做任何服务,都要考虑服务的性能和成本。
但优化有很多方式,为什么是架构呢?诚然,从硬件到操作系统,从共享库到应用软件,从算法到架构,每一层都可以优化,但每一层所做的工作量和收益也都是不同的。架构可能是需要投入最多精力的,但在很多时候却也是很少的可以提供超过数量级的提升方式。
所以,思维方式的转变才是你最应该在意的部分,单元化只是一个例子,而粉丝服务平台只是这个例子的例子,而已。
言归正传,接下来本文将从三个问题来介绍这次实践,单元化是什么,为什么要用以及我们如何做到的。
1. 单元化是什么
单元化架构是从并行计算领域发展而来。在分布式服务设计领域,一个单元(Cell)就是满足某个分区所有业务操作的自包含的安装。而一个分区(Shard),则是整体数据集的一个子集,如果你用尾号来划分用户,那同样尾号的那部分用户就可以认为是一个分区。单元化就是将一个服务设计改造让其符合单元特征的过程。
图 1 :洋葱细胞的显微镜截图,单元化要达到的目的就是让每个单元像细胞一样独立工作
在传统的服务化架构下(如下图),服务是分层的,每一层使用不同的分区算法,每一层都有不同数量的节点,上层节点随机选择下层节点。当然这个随机是比较而言的。
图 2 :传统的服务化架构,为伸缩性设计,上层节点随机选择下层节点
与其不同的是,在单元化架构下,服务虽然分层划分,但每个单元自成一体。按照层次来讲的话,所有层使用相同的分区算法,每一层都有相同数量的节点,上层节点也会访问指定的下层节点。因为他们已经在一起。
图 3 :单元化架构,为性能和隔离性而设计,上层节点访问指定下层节点
2. 为什么要用单元化
在性能追求和成本限制的情况下,我们需要找到一种合适的方法来满足服务需求。在传统的分布式服务设计,我们考虑的更多是每个服务的可伸缩性,当各个服务独立设计时你就要在每一层进行伸缩性的考虑。这是服务化设计(SOA)流行的原因,我们需要每个服务能够单独水平扩展。
但是在摩尔定律下,随着硬件的不断升级,计算机硬件能力已经越来越强,CPU越来越快,内存越来越大,网络越来越宽。这让我们看到了在单台机器上垂直扩展的机会。尤其是当你遇到一个性能要求和容量增长可以预期的业务,单元化给我们提供另外的机会,让我们可以有效降低资源的使用,提供更高性能的服务。
总体而言,更高性能更低成本是我们的主要目标,而经过单元化改造,我们得以用更少(约二分之一)的机器,获得了比原来更高(接近百倍)的性能。性能的提升很大部分原因在于服务的本地化,而服务的集成部署又进一步降低了资源的使用。
当然除了性能收益,如果你做到了,你会发现还有很多收益,比如更好的隔离性,包括请求隔离和资源隔离,比如更友好的升级,产品可以灰度发布等。单元化改造后对高峰的应对以及扩容方式等问题,各位可以参考#微博春节技术保障系列#中的单元化架构文章,也不在此一一赘述。
3. 我们如何做到
此次单元化改造基于微博现有的业务,因此这里也先行介绍一下。粉丝服务平台是微博的内容推送系统(代号Castalia),可为V用户提供向其粉丝推送高质量内容的高速通道(单元化之后已到达百万条每秒)。整个服务涉及用户筛选、发送计费、屏蔽检查、限流控制和消息群发等多个子服务。由于改造思想相通,这里以用户筛选和消息群发两个服务为例,下面两图分别为商业群发在服务化思想和单元化思想下不同的架构。
图 4: 服务化思想下的商业群发架构设计(旧版)
图 5 :商业群发在单元化思想下的架构设计(新版)
对于筛选服务,在服务化架构里,需要去粉丝服务获取粉丝关系,然后去特征服务进行用户特征筛选,最后将筛选结果传输到群发服务器上;而在单元化架构里,粉丝关系直接就在本地文件中,用户特征服务也在本地,最后的筛选结果再不需要传输。服务本地化(粉丝关系和用户特征存储)减去了网络开销,降低了服务延时,还同时提高了访问速度和稳定性,而筛选结果本地存储又进一步节省了带宽并降低了延迟。以百万粉丝为例,每次网络操作的减少节省带宽8M左右,延时也从400ms降为0。
群发服务同样如此。由于在服务化架构里,我们使用MySQL和Memcache的方案,由于关系数据库的写入性能问题,中间还有队列以及相应的队列处理机,所有四个模块都有单独的机器提供服务,而在单元化架构里,四合一之后,只需要一套机器。当然机器的配置可能会有所提升,但真正计算之后你就会发现其实影响微乎其微。原因除了前面介绍的硬件增长空间外,上架机器的基本配置变高也是一个原因。而且,在单元化方案里,当我们把缓存部署在本地之后,其性能还有了额外的20%提升。
一些业务特有问题
不过群发这个场景,我们也遇到了一些特定的问题,一是分区问题,一是作业管理。这里也与各位分享下我们的解决方法。
分区问题分区问题其实是每个服务都会遇到的,但单元化后的挑战在于让所有服务都适配同一分区算法,在我们的场景下,我们按照接收者进行了分区,即从底层往上,每一层都来适配此分区算法。这里有特例的是用户特征和屏蔽服务,由于总体容量都很小,我们就没有对数据进行分区,所有单元内都是同一套全量数据,都是一个外部全量库的从库。不过由于本单元内的上层服务的关系,只有属于本分区的用户数据被访问到。所以,适配同一分区算法在某种程度上讲,可以兼容即可。
作业管理按照前面的分区方式,将群发服务的整体架构变成了一个类似Scatter-Gather+CQRS的方案,因为Gather不是一个请求处理的必须要素。也就是说,一个群发请求会被扩散到所有单元中,每个单元都要针对自己分区内的用户处理这个群发请求。广播方式的引入,使得我们首先需要在前端机进行分单元作业的处理监控,我们在此增加了持久化队列来解决。同时,由于单元内每个服务也都是单独维护的,作业可能在任何时间中断,因此每个作业在单元内的状态也都是有记录的,以此来达到作业的可重入和幂等性,也就可以保证每个作业都可以在任何时间重做,但不会重复执行。
除此之外,我们还对服务器进行了更为精细的控制,使用CPU绑定提高多服务集成部署时的整体效率,使用多硬盘设计保证每个服务的IO性能,通过主从单元的读写分离来提高整体服务等等。
后记
我平时不善文章,现在要成文发表,还是有一点紧张的。不过想到或许可以抛砖引玉,有机会向各位大牛学习,或者跟各位同学一起交流,内心又有些许期待。关于微博或者其他任何网站的设计,欢迎大家一起探讨,随时在微博恭候。
收起阅读 »
Android Studio 2.0 导入环信Demo3.10 问题
在这里主要介绍后面四个文件夹内容:
doc文件夹:SDK相关API文档第二步我们要导入的是examples文件夹里的内容
examples文件夹:ChatDemoUI(为开发者能够更深入理解SDK而提供的一个demo)
libs文件夹:拥有实时语音,实时视频功能的SDK(大小在1.34M左右)包和.so文件
libs.without.audio文件夹:无实时语音,实时视频功能的SDK包(大小在900多K)
tools官网没给解释(未知)
接下来删除两个文件夹下的build.gradle
第三步导入项目 我是在打开项目的基础上又重新打开一个界面,导入方式就不多说了
导入后项目的运行可能是灰色的 我们通过进入Project Structure来先删除mod,在次导入mod 导入时选择easeUIDemo
第四步导入jar和io文件
在自行开发的应用中,集成环信聊天需要把libs文件夹下的easemobchat_2.1.6.jar和armeabi目录导入到你的项目的libs文件夹底下,如果不需要语音和视频通话功能,导入libs.without.audio下的jar文件即可。(这是环信文档)由于我是集成即时通讯,真实文件是下面这两个,复制粘贴到libs文件夹下
报错:
Error:Execution failed for task ‘:easeUIDemo:compileDebugNdk’.
Error: NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin. For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental. Set “android.useDeprecatedNdk=true” in gradle.properties to continue using the current NDK integration.解决方法 项目build.gradle下图对应位置加入如下代码 ( 可复制粘贴)
sourceSets.main {
jni.srcDirs =
}
然后就可以了,自己遇到的问题,希望能帮到面临这些问题的人
本篇Android studio集成由环信热心开发者提供,博客请点击Crazy丶code 收起阅读 »
环信直播课堂第六期--2.x和3.x的单聊的集成
http://www.imgeek.org/video/23
持续时间:半小时
描述:集成环信2.x 3.x sdk怎么选?怎么用最简便的方法集成聊天功能?
本期环信直播课堂将由环信ios工程师shenc给大家带来ios 2.x和3.x集成介绍,并详细讲解头像昵称的实现,大家有其他问题也可以直接提问哦!
PS:这是一份史上最全的环信iOS 2.x and 3.x SDK单聊的集成方案!
直播观看地址: http://www.imgeek.org/video/15
视频回放地址:http://www.imgeek.org/video/23 收起阅读 »
“App增长加速度”主题分享会:听环信解读”APP如何提升造血能力“
随着移动互联网的发展,加上政府的鼓励和扶持,一股轰轰烈烈的全民创业大浪潮正席卷全国。然而,万众创新下的创业者们却面临着流量被垄断和马太效应等重重创业关卡。
2016年,如何突围缺钱、缺人、缺流量关卡,加速App内增长,提升企业业务竞争力及商业价值?或许可以用共享经济法则和移动应用新技术mLink切入万亿级App市场,或许可以借力大数据揭秘资本寒冬下的增长之道,又或许可以试试用户人群精细化运营的正确姿势……本期“App增长加速度”主题分享会邀您一起发现改变力!
【时间】2016年4月9日下午13:00—17:00
【地点】成都高新区软件园A9 3楼(十分咖啡·投资家)
【人数】300人
【人群】欢迎移动端App创业者、研发人员、架构师、产品经理报名参加!
二、活动福利
•尝鲜硅谷最新创业创新理念及实操干货经验
•和来自北京上海增长最快的技术创业团队面对面探讨创业经
•免费获得魔窗价值30000元/月的VIP账号
•免费获得GrowingIO企业版代金券4000元
•免费获得猿团周边礼品包1份
三、活动流程
13:00-13:15 签到、交换名片
13:15-13:30 主持人:初笋科技创始人冷治福
13:30-14:00 魔窗创始人兼CEO 姜孟君:《如何用共享经济法则切入万亿级App市场》
14:00-14:30 GrowingIO创始人、CEO 张溪梦:《数据驱动增长——GrowingIO》
14:30-15:00 Testin西南区技术总监李小川:《APP全生命周期质量》
15:00-15:30 环信高级产品市场经理谢韩:《资本寒冬,APP如何提升造血能力》
15:30-16:00 猿团科技创始人&CEO谢恩明:《App+》
16:00-16:10 休息
16:10-16:40 圆桌会议:现场提问+嘉宾答疑
16:40- 自由交流
四、分享嘉宾&主题
1、分享嘉宾:魔窗创始人兼CEO姜孟君
企业级和互联网解决方案双料专家,多年大数据资深从业者,O2O经验咨询平台“在行”资深行家。从业15年+,拥有大型企业级SAAS解决方案及多年营销大数据经验,擅长软件云化与服务化、大数据处理与应用、社会化倾听、电子商务、互联网精准营销相关及团队建设等方面。曾在一年半内从零组建一支30多人规模的互联网创业团队,并交付4个明星级别产品,单一产品线第一年收入超过500万。
曾担任惠普中国、惠普美国数据管理平台和新一代数据中心核心负责人;SAP首席工程师,SAP云加速特别行动小组首位中国区代表;AdMaster研发副总裁及上海研发中心总经理。
两年前加入互联网创业浪潮,开创App Growth Engine——魔窗(MagicWindow),为App提供变革式的面向服务的开发方式,1天让APP变本地开放平台,提升App用户体验及转化率,让每一个App都可以轻松情景式相连,让创业更加轻松愉悦!
分享主题:《如何用共享经济法则切入万亿级App市场》
•探讨共享经济理念在APP创业者当中能否成立
•阻断App创业者协同创业最大的瓶颈是什么
•如何打破资源和流量的马太效应完成有机增长
•2016移动端应用的变革——mLink
2、分享嘉宾:GrowingIO创始人、CEO张溪梦
GrowingIO创始人、CEO。前LinkedIn美国商业分析部高级总监,美国Data Science Central评选其为“世界前十位前沿数据科学家”,亲手建立了LinkedIn将近90人百人商业数据分析和数据科学团队,支撑了LinkedIn公司所有与营收相关业务的高速增长。2015年5月,从硅谷创办基于用户行为的新一代数据分析产品GrowingIO,提供全球领先的数据采集和分析技术。企业无需在网站或app中埋点,即可获取并分析全面、实时的用户行为数据,以优化产品体验,实现精益化运营,用数据驱动用户和营收的增长。2015年12月,荣获DOIT评选的2015中国十大数据英雄,由他创办GrowingIO并获得《快公司》评选的2015年中国最佳创新公司50。
分享主题:《数据驱动增长——GrowingIO》
•来自硅谷增长黑客秘密
•海盗法则 Pirates AARRR
•增长黑客实现方法
•如何衡量?建立合理的KPI体系
•GrowingIO案例分享
3、分享嘉宾:Testin西南区技术总监李小川
八年互联网产品测试及质量管理经验,曾任北京邮电大学信息安全中心研究员、华为测试经理、北京云蜘蛛科技副总,曾担任过6个运营商级项目的测试经理,对于产品质量控制和自动化测试有丰富的经验。
分享主题:《APP全生命周期质量》
互联网的根本是用户,APP产品如何留住用户?红利、互联网推广还是好的用户体验?根据Testin数据分析,随着移动互联网人口红利的逐步消失,新用户的比例在逐步减少,相反,老用户的比例攀升。这一变化预示着用户对于应用的选择将越来越苛刻,部分用户体验较差、运营不佳的应用将被迅速淘汰。因此,如何做好APP质量,提升用户体验是重点。
如何做好APP产品质量,Testin分享APP质量之APP全生命周期测试:功能、兼容、性能、体验、压力、安全。
4、分享嘉宾:环信高级产品市场经理谢韩
IT行业跨领域市场研究者,先后从事网络、安全、互联网领域的市场研究与分析工作,对商业技术趋势有较深理解。
分享主题:《资本寒冬,APP如何提升造血能力》
随着外部资金渠道的趋紧,依靠APP自身实现内源性增长成为必然的选择,这就需要App能够自我造血,具备吸引用户和转化用户的能力。在这个过程中,连接人与人的IM技术,连接人与商业的移动客服,是帮助App建立社区,实现商业变现过程中的有力助手。在此基础上,基于连接属性所进行的人群和内容大数据分析,也能够推动App实现精准化营销和精细化运营。
5、分享嘉宾:猿团科技创始人&CEO谢恩明
80后青年创业者,十年连锁企业负责人。08年加入互联网行业,曾任职于金山、腾讯,具备丰富的客户服务、企业培训、企业管理等经验。之后创立猿团科技,担任CEO,猿团科技在他的带领下,半年时间从估值两千万到两个亿,随后创立猿团投资公司,猿团传媒公司,目前已经帮助40+个项目进行创业。
分享主题:《App+》
报名请点击阅读原文
收起阅读 »
【活动报名】HTML5 app轻架构高性能开发交流会,4月9日北京
如果认为这是危言耸听,那么你危险了。在W3C宣布html5正式定稿一年半以来,h5技术带来的产业变革已经不再停留在“干打雷”,而是掀起了“疾风骤雨”:
Adobe支持用户放弃Flash,鼓励使用html5;
微信即将推出应用号;
Facebook、谷歌、微软、BAT等纷纷全面支持html5;
html5病毒式疯狂传播案例的频频出现;
… …
移动应用开发领域亦受到html5技术风暴的“席卷”。
然而,面对HTML5带来的变革机遇,你是否因为对h5 app的种种担心,放缓了抢占市场先机的步伐?
——担心h5 app性能不稳定,交互体验效果差,影响用户体验感
——担心自身技术不过硬,无法快速进入h5 app开发者行列
——担心开发平台限制多,应用源码及产权难保障
… …
4月9日13点30分,北京百川创业营,由WeX5移动应用开发平台主办的html5 app轻架构高性能开发交流会(北京)将给你答案!。
届时,WeX5首席技术运营官将为您的问题进行解答,并与您分享诸多干货:
h5 app为何成为颠覆App既有行业格局的力量;
如何规避h5 app开发中的各种坑;
WeX5开发平台为开发者带来哪些极致体验;
深入交流探讨html5 app轻架构、高性能开发的技术问题和案例现场讲解;
WeX5开发app过程视频展示。
此外,本次技术交流活动不仅为各位开发者准备了技术盛宴,还提供有各种精美礼品,幸运者更可享受WeX5产品VIP服务,让您领航h5 app开发之路。
【活动时间】
2016年4月9日(周六)下午13:30—16:30
【报名入口】
点击“阅读原文”,即可免费报名。
【活动地点】
北京市海淀区长春桥路11号万柳亿城中心C2裙房B1百川创业营
(C2楼北侧进,电梯下往B1层即到)
【主办方】
【合作伙伴】
阅读原文 收起阅读 »
Android 3.1.1, iOS3.1.1 release
新功能:
音视频增加弱网/断网检测功能;
音视频增加音频、视频流暂停、恢复功能;
音视频增加录制功能;
发送图片默认压缩图片,节约流量;
bug fix:
Fix iOS demo退到后台后某些情况下crash的bug。
点击下载:http://www.easemob.com/download
收起阅读 »
Uber弃用email客服改用应用内客服,App内置客服将成趋势?
Uber的用户求助服务一直是通过Email沟通,而近日Uber将该服务切换到了应用内部。这么做理由何在呢? 因为在Uber一直希望获取大量市场份额的部分国家,例如中国和印度,用户并不像西方人那样习惯使用Email。
我们从上世纪90年代中叶开始就习惯了往来的电子邮件传达信息,而中国的大部分用户甚至连Email地址都没有。因为互联网不那么让人觉得靠得住,在中国和印度,人们更喜欢使用微信这样的聊天软件进行交流。在2015年,微信已拥有超过10亿用户。
Uber的“用户沉迷”产品经理Michael York说,虽然新的应用内服务去年晚些时候在美国铺开,实际上为了从Email交流转变为应用内沟通,Uber已潜心研究数年。Uber现在正在将其业务拓展到这样一些国家——为留住用户,Uber需要帮助用户找回不小心落下的东西、或处理其他投诉,这些工作需要牵涉到乘客和司机两个方面。
York说“(这种转变)对于中国、印度及其他更喜欢即时聊天的地区用户而言是巨大的。”而这种转变也同样减轻了客服部门的压力。Uber专家以往需要同时处理无礼乘客、失物找回等各类投诉Email,而这已成为过去式,因为彼时Uber还没有这么多用户。
Uber还一直因为不提供电话协助服务而饱受批评,因为有的时候发邮件几乎是不可能的。而且Uber的客服邮件一般都是自动回复的统一信息,之后才会有人工回复。
在过去的几年,Uber开始投入“数百万”的资金建立其支持中心的网络以加快反应速度。中心已建立在包括芝加哥(美国)、凤凰城(美国)、利默里克(爱尔兰)、克拉科夫(波兰)、武汉(中国)、海德拉巴(印度)、马尼拉(菲律宾)等许多地方。然而公司与用户之间的沟通需要比用Email更接地气的方式。
Uber的全球运营主管Michael Mizrahi说,为应对这样的改变,工程师不得不在后端重写整个支持系统,新的Uber应用将会在未来几周内推出。美国市场将最先获得更新,然后再陆续推广至全球其他地区。
如果您的公司也有和Uber一样的客服困境,那么现在市场上主流的SaaS移动客服是您的不二选择:1,极简快速集成,一天时间即可让您的APP拥有应用类客服功能。2,按需付费。3,弹性扩容。4,智能机器人提高效率降低成本。5,全媒体接入,包括微博、微信、网页、H5、APP、呼叫中心等一键集成一网打尽。
环信移动客服是全球首创的全媒体智能云客服平台。支持全媒体接入,包括网页在线客服、社交媒体客服(微博、微信)、移动端客服和呼叫中心等多种渠道。环信移动客服基于环信业界领先的IM长连接技术保证消息必达,并通过强大的智能机器人技术极大降低人工客服工作量。
截至2015年底,环信移动客服共服务了12000家企业用户,现已覆盖包括电商、O2O、互联网金融、在线教育、在线旅游、移动医疗、智能硬件、游戏等20大领域的Top10客户,典型用户包括国美在线、58到家、楚楚街、随手记、海尔、51talk,链家自如客等众多互联网和传统企业。根据易观国际发布的《中国SaaS客服市场专题研究报告2015》显示:截至2015年第三季度,环信移动客服在SaaS移动端客服用户覆盖占比为77.4%,以绝对优势稳居行业第一。
此番Uber弃用传统email客服改用应用内客服其实是一个必然趋势,那么是否会对亚太乃至整个客服市场造成影响?我们拭目以待。
环信编译自“techcrunch美国”,请点击“阅读原文”跳转至英文链接。
阅读原文 收起阅读 »
清明节特辑:那些过时却仍在使用的技术
清明节对于中国人来说是祭祖和扫墓的日子。不过在新旧更替、大浪淘沙的互联网行业,过去一年也有不少技术难逃过时的命运,当然原因也是各种各样。
但是笔者一直觉得,有些技术虽然已经过时,但是不会死,只会慢慢消亡。今天就来一起盘点下,那些已经过时,却仍在使用的技术!
1、拨号上网
我记得在我上一次使用拨号上网的时候是希望从某网站上下载一份学习报告,但在忍受了长时间的蚂蚁网速后,我终于下定决心同拨号上网说拜拜。然而,根据皮尤公布的《互联网与美国人生活习惯研究项目》(Pew Internet & American Life Project)数据显示,大约有4% 的美国人仍然在使用拨号上网。这也就是说,有超过 1000 万人在以不超过 56.6k/s的速度访问互联网!
需要指出的是,这4% 的拨号上网用户中可能有一部分是由于地处偏远地区而没有宽带互联网连接(这部分人群大约占据全美总人口的6%),剩下的一部分人则可能是基于费用或者其他原因而没有安装宽带。
2、传呼机
在上世纪 90 年代,人们彰显自己身份的标志之一便是传呼机。在那个年代,如果你拥有一部传呼机的话,人们通常会把你认作是企业 CEO,或者是一名外科医生,因此续续时刻同外界保持联系。但在几年的时间内,可以同时让人们收发信息手机的出现已经逐渐使传呼机退出了历史舞台。
尽管目前手机已经拥有着绝对统治地位,但传呼机仍然拥有着一定的市场份额。根据美国消费电子协会的报告指出,2012 年美国人总共采购了总金额为 700 万美元的传呼机,数量约为 1 万部左右。如果说你希望在能够保持同外界接触的情况下保留一定个人隐私的话,传呼机似乎的确是一个不错的选择。
说到这里,你可能会想象到一个个其貌不扬的毒品贩子在街头通过传呼机联络的画面。但事实上,现在有许多医院仍然倾向于为医生配备一部传呼机,因为他们认为传呼机网络相比手机网络更加可靠,尤其是在紧急情况发生的情况时。
3、点阵打印机
尽管在很多场合内,点阵打印机的地位早已被喷墨打印机所取代,但根据知名市场研究公司 NPD 公布的数据显示,美国人在 2012 全年还是购买了大约 2 万部全新点阵打印机。而且,在亚马逊购物网站上,我们仍然发现点阵打印机拥有一个完全独立的板块,其售价也往往比普通的喷墨打印机贵上了一倍左右(最低售价为 205 美元)。
那么,现在还有哪些企业或者工作人员需要使用到这个出生于 1983 年的老旧技术呢?事实上,许多仓库、销售点或者其他一些业务系统都仍然十分依赖于这一设备,因为他们往往需要开具一式五联的单据,而开具这样单据的最好方法便是通过点阵打印机来实现。
4、PDA(个人数字助理)
在很久以前,我曾经拥有过一部 Palm Pilot 个人助理设备,这是有史以来用户第一次可以从通讯录里直拨电话的设备。随后,我又用上了拥有彩色显示屏幕的 Cassiopeia。但是,我和个人数字助理设备之间的情缘也就到此为止了,因为智能手机的出现几乎使 PDA 变得一无是处。
然而,根据美国消费电子协会给出的数据显示,去年美国地区依然卖出了大约 35 万部全新 PDA 设备。该协会行业分析主管史蒂夫-科尼格透露,“人们购买 PDA 并不是因为他们因循守旧,而是因为许多垂直市场依旧需要使用随身 PDA 来收集数据,尤其是在仓库和医院这样的特殊办公场所”
5、公共电话
根据美国公共交流委员会(American Public Communications Council)在 2012 年第三季度给出的数据显示,全美境内目前仍然拥有多达 30500 个公共电话,对于知名乐队 Maroon 5 的粉丝来说,这或许是个不错的消息(该乐队的最近一张专辑的主打歌曲就是“Pay Phone”)。
事实上,这些公共电话直到现在也仍然在发挥着自己的巨大作用。美国公共交流委员会透露,2012 年人们总计使用这些公共电话拨打了超过 5000 万次电话。那么,到底有哪些人会直到现在仍然在使用公共电话呢?
分析人士认为,那些无力购买一部手机的低收入群体、希望保持自己匿名身份的人、手机在路上突然没电的用户以及那些突然无法接收运营商信号的人都有可能使用到公共电话服务。
6、录像带和磁带
在互联网高速发展的时代,人们已经可以在线下载许许多多的音乐和其他数字内容。亦或者,用户也可以选择继续沉浸在 1985 年的生活中,也就是利用磁带录下广播中的歌曲、利用录像带录下电视中正在播放的节目。
7、固定电话
在 2012 年中期,全美大约 34% 成年人家中没有安装固定电话。但与此同时,仍有 66% 的成年人不仅在家里安装了固定电话,而且还会为这套系统购买新硬件。根据美国消费电子协会给出的数据显示,美国人 2012 年总共购买了 500 万部固定电话和 2150 万部无绳电话。
8、CRT 电视
虽然目前仍然有相当数量的美国家庭在使用老旧的 CRT 电视,但大多数消费者电子产品公司已经基于种种理由而停止了这类产品的生产、开发工作。因为这些 CRT 电视不仅丑陋、过时,其内部笨重零部件的生产和海外运输成本也十分高昂。但是,根据知名市场研究机构 NPD 给出的数据显示,美国人在去年总计购买了 1 万台全新 CRT 电视,其中大多数 CRT 电视的主要观看群体是儿童。
9、胶卷
现在,绝大多数用户手中的智能手机都已经配置了高清摄像头,但传统一些的卡片式照相机以及数码单反相机也依旧十分流行,现在用户甚至只需要花费不到 100 美元的价格便可以购买一部成像效果相当不错的数码相机。因此,考虑到用户利用数码相机所拍摄图片的持久性、可分享性以及高品质,我们实在很难想象现在依旧有人在使用老式胶卷相机。
然而根据 NPD 给出的数据显示,美国人似乎依旧对于这种老式的生活记录方式情有独钟,因为美国地区在去年依旧卖出了高达 3500 万卷相机胶卷。其中,部分人们是 Lomo 拍摄方式的狂热爱好者,另有一部分人则仅仅是不愿意同自己的宝丽来相机说分手而已。
10、Windows 98 和 Windows 98 操作系统
虽然绝大多的人们都喜欢驾驶配置了诸如先进燃油喷射、安全气囊和操控体验的新款汽车,但世界上总有那么一部分人更喜欢驾驶老式的本田 Civic 车型,而这一点在人们所使用的一些复古操作系统中也可见一斑。
据市场调研究公司网络应用(Net Applications)公布的数据显示,目前仍然有 0.05% 的美国人在使用 Windows 98 和 Windows 2000 操作系统。与此同时,The Computer Industry Almanac 则表示,考虑到目前美国总计拥有 3.11 亿部电脑的事实,我们可以发现仍有超过 15 万人在使用来自上个世纪的操作系统。
11、传真机
早在上世纪 70 年代,传真机就成为了一款必不可少的办公室设备。但在过去了整整 40 年后,随着电子邮件、即时通讯应用等服务的兴起,传真机似乎已经失去了自己继续存在下去的理由。然而,事情的发展却没有同人们的想象保持一致,由于许多商业合同的签订仍然需要企业高层的亲笔签名,因此传真机在现代企业中仍然十分普遍。
根据 NPD 的数据显示,美国人总计在 2012 年内购买了 35 万部新传真机,但相比 2011 年同比下降了 14%。
12、黑胶唱片机
当猫王正处于流行舞台最中央的时候,黑胶唱片机也成为了当时许多年轻人听歌的第一选择。但是,在当今数字音乐下载和流媒体服务大红大紫的年代,看似“过时”的黑胶唱片却显示出了卷土重来之势。
尽管这一技术已经面世了很长时间,但现在有越来越多的新唱片开始以黑胶唱片的形式发行,其中就包括来自蠢朋克乐队(Daft.Punk)和僵尸周末乐队(Vampire Weekend)的最新作品。根据美国知名数据分析机构 Nielsen SoundScan 日前公布的数据显示,美国人在 2012 年总计购买了 460 万张黑胶唱片,同比上升了 17.7%。尽管这一数字相比 2012 年 1.18 亿数字专辑的销量还相去甚远,但这一“古老”产业的复兴似乎已经成为了一件不争的事实。
总结:
虽说科技在近年来迎来了前所未来的巨大飞跃,在对于许多普通人来说,我们的日常生活中还是能够时时刻刻看到许多“古老”技术的存在。比如,对于诸如拨号上网、磁带播放器、录像机等这些物品相信大家都不会陌生。就此,美国消费电子协会(CEA)行业分析主管史蒂夫-科尼格(Steve Koenig)就表示:“真正淘汰一项技术所需要的时间恐怕会超出你的想象。”
与此同时,美国消费电子协会日前公布的一份研究报告也指出,“大约仅有13-15%的人们是新兴技术的早期试用者,另有超过60%的人则通常会在一段时间以后才选择升级自己的老设备、或者采纳新技术。
在传统的客服中心领域也正在发生这种技术变革,传统的呼叫中心正在被以全媒体、智能机器人、移动端等特性的SaaS客服所颠覆和取代。新时代的SaaS客服集成简便快速,按需付费,弹性扩容,结合新一代的智能机器人技术极大的提高效率帮助企业降低成本,最后最重要的一点就是“价格特别低,价格特别低,价格特别低。”重要的事情说三遍。环信移动客服——全媒体智能云客服倡领者,1500元/坐席 一年的价格是不是童叟无欺。PS:两个坐席以内还完全免费哦。
环信移动客服是全球首创的全媒体智能云客服平台。支持全媒体接入,包括网页在线客服、社交媒体客服(微博、微信)、移动端客服和呼叫中心等多种渠道。环信移动客服基于环信业界领先的IM长连接技术保证消息必达,并通过强大的智能机器人技术极大降低人工客服工作量。收起阅读 »
环信直播课堂第五期--消息输入状态与群组@人
持续时间:半小时
描述:想知道对方是否正在回复你的消息?群组里想把消息说给指定的人,群消息太多对方没关注怎么办?
本期环信直播课堂将由环信Android工程师zhuhy给大家带来“如何实现消息输入状态与群组@功能!”
PS:有些妹子真是太倔强了,明明可以靠脸吃饭,偏要靠才华...
直播观看地址: http://www.imgeek.org/video/15
直播视频回放:http://community.easemob.com/video/22
消息输入状态与群组@人demo下载↓↓↓
收起阅读 »
环信“连接”沙龙第五期技术干货全分享:一切不以变现为目的的APP运营都是对投资人耍流氓
在“对,就是这个胖子”的小声议论中, 环信市场VP程开源上台致欢迎词...
在活动现场,演讲嘉宾围绕App变现,从不同维度,不同角度与参会者分享了自己的观点。演讲嘉宾包括环信大数据产品总监马冀、云账户联合创始人兼CTO邹永强、魔窗CTO张申竣、北京妙创意科技联合创始人苏然分别从大数据分析、App金融SDK、Deep Link技术、场景化造物等不同维度与到场的市场运营和开发者们进行了深入交流,气氛十分热烈。
一,深藏的金矿——社交大数据分析和挖掘
环信颜值担当大数据产品总监,九头身欧巴马冀走着台步就上来了...
针对当前众多App所困扰的变现问题,环信大数据产品总监马冀分析了App变现面临的难题以及从大数据的角度,如何破解。首先App需要明确的几个问题,“要卖什么?”“卖给谁”、“真实用户有多少?”只有在了解了当前APP的真实状况后,才能进行精准化的营销。
基于大数据的社交分析能够帮助运营者了解当前App的真实用户粘性。目前,环信大数据平台已经为App提供了数十个指标,包括DAU,日存留用户、具有IM行为的用户数、每日消息数等等。有了这些实际数字,App运营者就可以清晰的知道当前真实的用户群状况,从而采取相应策略的提升用户粘性。
其次,基于大数据的社交分析能够帮助App进行精准化的营销。一是对用户内容进行分析。例如,当前App中有哪些主题和关键字最受用户关注,哪些用户对这些主题最热衷,哪些用户对这些关键最反感等等。基于内容的分析能够帮助App运营者找到用户的关注点。其次,大数据还能够对用户进行分析,例如,找到用户之间的关系圈,哪些用户之间联系较为紧密,具有相同的兴趣爱好,这些用户最爱购买哪些商品。某款产品,哪些用户群的需求量最大。通过对社交的大数据分析,App可以清晰的对用户进行画像,从中挖掘出潜在的需求,进行精准化营销,从而实现商业变现。
PPT下载:http://www.imgeek.org/article/825307747
二,云账户,金融SDK助App流量变现
有着一张明星脸的云账户联合创始人兼CTO邹永强上来很爽快的在活动群发了个大红包,场下有人嘀咕:“岳云鹏就是大方...”
邹永强博士认为广告离钱很近,但并不是唯一的变现方法。广告的产品形式不够丰富,与App场景的结合不是很好,而金融是离钱更近的行业,所以云账户提倡场景式金融,关心金融与App场景的结合。国内很多公司都在涉及互联网金融领域,例如58同城、同程等。”云账户的思路是通过做一个金融的SDK结合App去变现,包含多种模式。
云账户金融SDK具体包含四种模式:
1.社区式理财超市:包含各类的理财产品;
2.App内余额生息:为本身有用户余额体系的App提供生息服务;
3.押金理财:为保证金或押金增加理财功能;
4.红包:提供点对点红包、拼手气群红包、品牌红包、卡券,已集成至环信IM SDK。
云账户金融SDK提供多种服务,包括:
1.对接金融机构和产品,免去商务和技术成本;
2.对接监管系统,解决分布式事务、对账、性能等问题;
3.支持多种App接入方式;
4.提供运营解决方案,包括加息券、体验金,App定制活动,运营方案建议等;
5.提供数据分析系统,包括用户、投资、红包商户端、用户行为报表、自定义用户行为分析、第三方监测等;
6.提供多层次的安全体系,即信息安全、金融安全、反欺诈和业务安全。
流量变现是App的核心问题,场景化金融是新途径,云账户提供可定制的金融SDK帮助变现,在四种模式中涵盖了很多服务。金融SDK模式可以快速接入,并且不会导出用户流量。通过简单易操作、直接集成至IM SDK的红包功能,为新时代的App提供更多变现、促活的可能。环信即将联合“云账户”上线包括品牌特定主题红包及商家卡券等更多增值服务和新玩法,将为移动互联时代的App社交和变现提供更多的想象空间。
PPT下载:http://www.imgeek.org/article/825307751
三,Deep Link——移动应用的变革
极客范十足的魔窗CTO-张申竣,上场就问“亲,你知道Deep Link么?”直到他演讲完我估计大家都懂了...
Deep Link是一种无需通过传统的App启动方式即可呼起移动App的一种方式,是近期科技业内的热门。Deep Link这项技术使得App 有能力像web页面那样被传播,让用户一键直达App的内容页。每个App都可以利用Deep Link完成服务化,让每个需要传播的页面都能直接被访问。
针对Deep Link技术的落地,魔窗CTO张申竣介绍了mLink解决方案的优势。mLink解决方案能够额外为开发者带来微信内的直接唤醒,用户在没有安装过App情况下的各种策略优化,以及用户通过deep link在第一次安装打开应用后直接唤起相应的服务页。这些特性能够帮助App很好的利用Deep Link传播服务,实现有机增长。魔窗的mLink还能使得App能将自己的Deep Link服务注册到服务市场被其他app发现,传播并且评估效果。
PPT下载:http://www.imgeek.org/article/825307750
四,场景时代下的造物变现逻辑
苏然有多潮,现阶段电商就有多火...
北京妙创意科技联合创始人苏然和与会听众分享了关于场景造物和场景器官的APP变现思路。在当前,已经不是物以类聚的时代,而是人以群分的时代。传统的电商做物以类聚的事情,找出性价比,让消费者更容易看到它,以一个看起来奢侈品的包装卖出超级低的价格形成转化,这是传统电商的模式。而现在的时代是一个新场景的时代,移动电商下的人群并不是在卖货,而是卖一个人群下的同样发生下的场景。每一个APP也好,每一个流量也好,需要匹配变现的价值是场景延伸的价值。让一个场景产生延伸的能力,我们赐予它场景延伸的能力,这个东西叫场景器官。通过大量实际例子,苏然和大家分享了场景变现的思路和实践。
PPT下载:http://www.imgeek.org/article/825307749
我不会告诉你右侧环信市场部两位年轻人至今单身,除了加班无不良嗜好,性取向正常,请留言索要联系方式...
感谢以上小伙伴对本次活动的大力支持,未来还要一起玩耍一起飞...
通过“连接”沙龙,环信旨在推动并打造一个互联网技术创新的平台,以期能够将有价值的技术资源整合推出,让更多的技术人开始分享技术,获得价值。
环信“连接”沙龙第七期(上海站)开始报名
APP变现之路 ——环信“连接”沙龙第七期(上海站)开始报名。可以点击“环信“连接”沙龙第七期(上海站)”查看详情以及报名,敬请期待!ps:上海站演讲人有中华小姐出境哦,有些人真是太倔强了,明明可以靠脸吃饭,偏要靠才华...
环信“连接”沙龙第七期(上海站) 收起阅读 »
Deep Link——移动应用的变革
魔窗CTO 企业级 SaaS 服务,移动技术和大数据专家。 超 过 10 年服务世界知名科技企业以及国内知名数据监 测公司,曾领导开发了 MMA China 的第一版移动端 监测 SDK。 现带领魔窗技术团队研发魔窗 SDK、 魔窗 SaaS 平台以及大数据计算平台的研发。
1.Deep Link的重要性及现状
为什么在没有 Deep Link 的情况下,在花费了大量研发成本后开发出的 App 的下载量始终很低。
2.Deep Link冰山之下的技术
是否只要实现了 URI Scheme 和路由跳转后,就能充分利用 Deep Link 提高用户转化率。
3.Deep Link平台化的技术要求
Deep Link 如何被发现,如何被管理,如何被监测。
讲师PPT下载↓↓↓
收起阅读 »
测拉菜单的demo,加上个点开菜单后对应不同类型的商品信息
self.navigationController.navigationBar.barTintColor = NavColor;
self.navigationItem.title = @"主页";
self.navigationController.navigationBar.translucent = YES;
GoodsImage = [NSMutableArray array];
PhoneArray = [NSMutableArray array];
ComputerArray = [NSMutableArray array];
LifeGoodsArray = [NSMutableArray array];
qitaArray = [NSMutableArray array];
UIButton *menuBtn = [UIButton buttonWithType:UIButtonTypeCustom];
menuBtn.frame = CGRectMake(0,0,30,40);
//[menuBtn setImage:[UIImage imageNamed:@"2.png"] forState:UIControlStateNormal];
[menuBtn setBackgroundImage:[UIImage imageNamed:@"2.png"] forState:UIControlStateNormal];
[menuBtn addTarget:self action:@selector(openOrCloseLeftList) forControlEvents:UIControlEventTouchUpInside];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:menuBtn];
SpeciesArray=@[@"手机数码",@"家具家电",@"日用百货",@"其他二手"];
//左侧是tableview显示页面
TableView = [[UITableView alloc]initWithFrame:CGRect1(0, 0, 120, 667-104) style:UITableViewStylePlain];
TableView.delegate = self;
TableView.dataSource = self;
TableView.separatorStyle = UITableViewCellSeparatorStyleNone;
TableView.rowHeight = 70*SCALE1;
[self.view addSubview:TableView];
//右边是对应的collection对应的显示页面
collection = [[UICollectionView alloc]initWithFrame:CGRect1(130, 80, 205, 563) collectionViewLayout:[[UICollectionViewFlowLayout alloc]init]];
[collection registerClass:[MyCollectionViewCell class] forCellWithReuseIdentifier:@"cell"];
collection.dataSource = self;
collection.delegate = self;
collection.backgroundColor = [UIColor whiteColor];
[self.view addSubview:collection];
}
//测拉菜单的实现开启
- (void) openOrCloseLeftList
{
AppDelegate *tempAppDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if (tempAppDelegate.leftslidevc.closed)
{
[tempAppDelegate.leftslidevc openLeftView];
}
else
{
[tempAppDelegate.leftslidevc closeLeftView];
}
}
/************tableView行数************/
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return SpeciesArray.count;
}
/************tableViewcell添加*********************/
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *inder = @"cell";
MainPageTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:inder];
if (cell ==nil) {
cell = [[MainPageTableViewCell alloc]initWithStyle:1 reuseIdentifier:inder];
}
cell.textLabel.text=SpeciesArray[indexPath.row];
return cell;
}
/****************tableview选中*********************/
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// [tableView deselectRowAtIndexPath:indexPath animated:YES];
if (indexPath.row ==0)
{
self.navigationItem.title = @"手机数码";
GoodsImage =[NSMutableArray arrayWithObjects:@"苹果皮",@"三星",@"华为",nil];
[collection reloadData];
}
if (indexPath.row ==1)
{
self.navigationItem.title = @"家具家电";
GoodsImage = [NSMutableArray arrayWithObjects:@"电视",@"冰箱" ,nil];
[collection reloadData];
}
if (indexPath.row ==2)
{
self.navigationItem.title = @"日用百货";
GoodsImage = [NSMutableArray arrayWithObjects:@"毛巾",@"脸盆" ,nil];
[collection reloadData];
}
if (indexPath.row ==3)
{
self.navigationItem.title = @"其他二手";
GoodsImage = [NSMutableArray arrayWithObjects:@"牙刷",@"奔驰" ,nil];
[collection reloadData];
}
}
收起阅读 »
iOS如何基于3.0SDK集成单聊界面
2.然后将demo中的SDK加入到你的工程中(SDK的文件名是 HyphenateSDK),SDK文件中有两个.a包,一个是带实时通话功能,一个是不带的,选其中一个,另一个删除掉。 具体看链接如何添加SDK以及SDK的依赖库:http://docs.easemob.com/doku.php?id=im:300iosclientintegration:20iossdkimport
3. 添加完SDK之后,添加聊天页面,环信demo中UI的部分都封装在了EaseUI文件中(具体是聊天页面,回话列表界面,联系人界面),找到环信 demo中的EaseUI文件。将EaseUI内部的EaseUI,以及EaseUIResource里的Resource,以及export文件 --->resource文件-->EaseUIResource.bundle,将这3个文件加到你的工程中,编译的过程会报错,下面是避 免报错的解决方法(还有就是会遇到三方库重复的报错,报错会提示你是哪个三方重复,看名称和路径自己删除一个)。然后先找到EaseUI- Prefix.pch,将其中的 #define NSEaseLocalizedString(key, comment) [[NSBundle bundleWithURL:[[NSBundle mainBundle] URLForResource:@"EaseUIResource" withExtension:@"bundle"]] localizedStringForKey:(key) value:@"" table:nil] 这段代码拷贝到自己的pch文件下, 在自己pch文件中所有代码的首尾加上#ifdef __OBJC__和#endif,具体看demo中的pch文件,然后再将NSObject+EaseMob这个类删除了,全局搜索就能搜索到。
然后将SDK的头文件引入到你的pch文件中,如果是用的带实时通话功能的SDK就引入 #import "EMSDKFull.h" 如果不带实时通话功能的引入 #import "EMSDK.h",同时在引入 #import "EaseUI.h"(UI的头文件)
4.工程编译成功后,在你的appdelegate,写上初始化环信appkey,以及登录环信服务器的方法:http://docs.easemob.com/doku.php?id=im:300iosclientintegration:30iossdkbasic (收发消息是根据环信ID,客户端一定要写登录环信服务器的方法,这个环信ID就是你环信管理后台应用下的IM用户)。然后自己可以写一个按钮,在按钮的点击事件中,跳转到聊天页面,方法如下:
EaseMessageViewController *message = [[EaseMessageViewController alloc] initWithConversationChatter:"这里填接受消息方的环信ID" conversationType:EMConversationTypeChat]; (EMConversationTypeChat是单聊类型)
这里用到的聊天页面就是EaseUI中的EaseMessageViewController.m聊天页面,自己引一下头文件
5.在聊天界面点击表情会崩的解决办法,可以在 在EaseMessageViewController.m类中的 viewdidload中的最后加上 EaseEmotionManager *manager= [[EaseEmotionManager alloc] initWithType:EMEmotionDefault emotionRow:3 emotionCol:7 emotions:[EaseEmoji allEmoji]];
[self.faceView setEmotionManagers:@[manager]];来进行处理。
6.在聊天界面收发消息,退出页面后再重新进入会看不到之前消息的处理方法,也是在EaseMessageViewController.m类中的 viewdidload中 调用[self tableViewDidTriggerHeaderRefresh];就可以了。
环信demo中用到的聊天类是ChatViewController.m是继承于EaseMessageViewController.m类的,具体的可以去看下(如果以后使用ChatViewController类的话,把上面5,6中添加的代码都注释掉,要不会出现问题)
7.以上步骤基本集成单聊的聊天页面,如果遇到了其他问题,可以到环信官网联系技术支持。 收起阅读 »
环信直播课堂第四期--消息撤回 和 阅后即焚
持续时间:半小时
描述:聊天的时候不小心说错了话,还是发错了人,真的有后悔药吗?
环信最新版本sdk 新增阅后即焚,消息撤回功能,让聊天更加有趣,打造社交新玩法!
本期将由环信Android工程师--一鸣 ,他将给大家讲解消息撤回与阅后即焚的原理,并现场手把手教你如何实现消息撤回与阅后即焚!
直播观看地址:http://www.imgeek.org/video/
稍后直播完会把视频和demo更新在本篇文章后面!
视频回放:http://www.imgeek.org/video/20
收起阅读 »
环信联合创始人:App主流反垃圾服务难点和技术实现全解析
环信联合创始人马晓宇
App开发者想方设法在App里集成IM功能,鼓励用户沟通、互动、分享。但在享受用户量迅速上涨的同时,却也面临着不小的麻烦——垃圾信息。用户数量上来后,各种广告、钓鱼、色情等垃圾信息也不请自来。影响用户体验不说,一旦涉及到政治类信息,甚至会给App带来下架的风险,这实际上已经有过前车之鉴。即使是过百万用户量,由于没有即时采取措施遏制垃圾信息泛滥,最终导致被用户抛弃的App也已是不乏其数了。有人对此总结了一句话:“始于约炮,发展于炫耀,终结于代购”。
App植入IM功能是大势所需,关键在于,如何有效过滤各种垃圾消息,让App满足用户真正的社交需求。
一,垃圾消息分类与伪装术
“知己知彼,百战不殆”,我们先了解一下当前IM软件上垃圾信息的特点。
从内容上来看,垃圾信息通常分成这么几类:
广告类:用于推销商品、网站、店铺等,例如减肥药、化妆品、四六级答案等;
钓鱼类:通过发布一些虚假信息,诱使人们点击或是回复,从而一步步陷入骗局;
色情类:用于色情交易或事色情网站宣传等;
SEO类:通过让用户点击提高小网站的搜索排名;
政治类:例如境外势力支持下的对重大事件的负面舆论。这类信息风险极大,一旦广为扩散极有可能造成App被下架。
对于简单的垃圾信息,管理员只要设置好关键字过滤即可。但发送者为了逃避拦截,通常都会对垃圾信息进行伪装,几种典型的伪装术:
不相关内容+垃圾内容。例如在四、六级或考研季来临时,常常会收到这种垃圾消息:“白日依山尽,黄河入海流。考研答案,联系QQ******”。前半句“白日依山尽,黄河入海流”即为干扰项。
添加随机噪声,包括文字变换,随机字母,不同字体等。例如,“QQ群”改写成“藤训裙”、“叩叩裙”等,或者同时使用符号、文字变换:
使用多媒体技术,例如使用图片或者音视频来封装广告。
二、垃圾信息检测技术
从垃圾消息的伪装技术来看,仅依靠传统关键字过滤显然是无效的,必须另辟蹊径。目前在学术界和业界的几个研究方向:
1. antispam_based_user_keyword,基于敏感词的模糊匹配技术。
这项技术的核心是实用双数组字典树算法进行关键词的查询。首先服务会对输入的内容先进行简繁体、全半角、火星文、同义词、特殊字符过滤等一系列预处理。然后进行高效的关键词查询,主要功能点:
基于基本词库进行过滤(如政治、色情、暴力等),同时支持用户自定义词库;
大小写模糊匹配;
将需要屏蔽的关键词替换为通配符(如星号*);
2. antispam_based_user_behavior,基于用户行为检测
基于用户行为的反垃圾算法的核心是使用聚类算法对用户行为进行识别,识别维度包括行为要素(如发送者、发送时间、内容类型等等)和行为关系。所谓行为关系,是指用户的社交属性,例如消息发送频率,时间间隔,消息响应率等等。通过高效的聚类算法可实现:
单用户行为识别:如单一用户发送大量的垃圾信息;
多用户行为识别:大量马甲发送大量的垃圾信息;
识别图片、语音、视频等多媒体类型的垃圾信息。
3. antispam_based_user_content,基于用户内容的识别
基于内容的反垃圾服务的核心是构建分类器模型,采用自然语言处理技术(NLP),对内容进行语义分析,利用持续的机器学习与分类器训练,使机器能够理解语句的真实含义。该技术可实现:
经过内容伪装的垃圾信息。例如加入了随机干扰内容的垃圾信息;
局部热点聚类并拦截。通过聚类算法可识别一些特定范围内大量传播的垃圾信息,通过生产规则遏止这些信息进一步扩散。
国内市场上为APP提供即时通讯能力的厂商中,目前市场占有率第一的环信率先将上述技术集成至其IM产品中,为APP提供反垃圾信息服务。可以在APP中实现几种垃圾信息的拦截:
单一用户行为,如发送大量重复的“你好”、“hi”、可爱表情等打招呼行为,或冒充官网人员发送恶意链接、营销广告、色情信息等,这种类型的垃圾信息可基于用户行为检测技术+内容检测技术,同时借助NLP及训练模型对内容进行识别和拦截,紧急情况下可使用敏感词进行拦截。
多用户行为。例如垃圾信息发送者拥有马甲库,切换不同马甲来进行垃圾信息发送,甚至展开小型DDoS攻击,此类可基于全局用户行为检测技术,以及全局消息内容聚合进行识别和拦截;
高级形式的垃圾信息。如“目的内容+随机干扰”,这种形式的垃圾信息可通过局部聚类检测技术对热词进行识别,同时结合语义分析技术进行识别拦截;
对于内容完全随机的垃圾信息,可以采用发送频率限制技术增加发送者的成本,让他们趋于正常用户的行为,削减影响。
环信反垃圾技术流程图
从在APP中实际部署的效果来看是非常明显的,过滤率基本在99%左右。下图是在环信产品后台看到的实际拦截效果,分别是基于行为的拦截和基于内容的拦截。
基于行为的垃圾信息拦截
基于用户内容的垃圾信息拦截
反垃圾信息服务是一项“长期斗争”,除了技术手段外,还可以采取一些管理手段。例如,注册时要求绑定手机号,而非邮箱号。设置举报机制和拉黑功能等等,从而提升垃圾消息发送者的成本。通过技术手段,再辅以管理手段,必将遏止App中的垃圾消息,打造一个健康的网络社交环境。
作者简介:
马晓宇,环信联合创始人,拥有17年研发经验,先后任职于Symbian、Nokia,带领团队主持开发了数款Nokia手机的操作系统及内核软件,手机操作系统,手机应用软件专家。
收起阅读 »
【转帖】App测试中的那些不可遗忘的基础知识
App测试是一项批判性的工作,目的就是找出软件中的缺陷。这里暂时不去深究为什么要进行App测试,以及App测试带来的好处。只介绍App测试中一些基本的测试方法。根据是否查看代码程序分为黑盒测试和白盒测试;根据是否运行软件又可分为静态测试和动态测试。
黑盒测试:又叫功能测试或行为测试,只需考虑各个功能,不需要考虑整个软件的内部结构及代码。
白盒测试:访问代码,通过检查代码的线索来协助测试。
静态测试:测试软件不运行的部分,只是检查和审核。
动态测试:使用和运行软件进行测试。
1、静态黑盒测试:检查产品说明书,并在软件编写之前找出问题
· 对产品说明书或软件需求报告进行高级审查:
(1)站在一个设计者的角度进行审查,找出根本性问题或遗漏之处
(2)站在客户(使用者)的角度来审查,因为软件质量的定义是满足客户的需求
(3)研究现有的标准和规范,可以是公司习惯用语和约定、行业要求、GUI、安全标准;检查所用标准是否正确、遗漏,是否与标准和规范相抵触
(4)审查和测试类似软件,检查它的规模、复杂性、测试性、质量和可靠性、安全性
· 对产品说明书或软件需求报告进行低层次测试:
一份优秀的产品说明书或者需求报告:必须是完整、准确、精确(不含糊、清晰)、一致、贴切、合理、代码无关、可测试性
2、动态黑盒测试:在不了解软件如何工作的前提下进行测试
两种基本方法:通过性测试和失效性测试
选择测试用例:等价类划分:把软件具有相似输入,相似输出,相似操作的分在一组。一个等价类或等价类划分是指测试相同目标或者暴露相同软件缺陷的一组测试用例。
等价类划分的目标:把可能的测试用例集缩减到可控制且仍然足以测试软件的小范围内。
(1)测试数据
通过性测试:
a) 边界条件:软件运行在计划操作界限的边界情况。测试边界包括测试临近边界的有效数据、测试最后一个可能有效的数据、测试刚超过边界的无效数据。
b)次边界条件:典型的次边界条件:2的幂、ASCII表
c)测试默认、空白、空值、零值和无这些数据
失效性测试:
d)测试非法、错误、不正确和垃圾数据
(2)测试状态
软件状态:软件当前所处的条件或者模式。
状态测试:测试程序的状态及其转换。
步骤:
1)建立状态转换图
2)减少要测试的状态及其转换的数量
a. 每一种状态至少访问一次
b. 测试状态之间最不常用的分支
c. 测试所有错误状态及其返回值
d. 测试随机状态转换
e. 测试看起来是最常见和普遍的状态转换
** 通过性状态测试**:审查软件,描绘状态,尝试各种合法可能性,确认状态及其转换正常。
失效性状态测试:竞争条件、重复(检查内存泄漏)、压迫(在不够理想条件下运行:内存小,磁盘空间少...尽量限制软件的必要条件)、重负(提供条件任其发挥)。
3、静态白盒测试:在不执行软件的条件下有条理地仔细审查软件设计、体系结构和代码,从而找出软件缺陷的过程
(1) 编码标准和规范:可靠性、可读性/可维护性、可移植性
(2)通用代码审查清单:
a. 数据引用错误 -> 缓存区溢出
b. 数据声明错误 <- 不正确地声明和使用变量和常量
c. 计算错误
d. 比较错误 <- 边界条件问题
e. 控制流程错误 <- 循环等控制结构未按预期方式工作,由计算或比较错误间接引起
f. 子程序参数错误 <- 子程序不正确地传递数据
g. 输入/输出错误
h. 其他检查 -> 编码、可移植、兼容
4、动态白盒测试:结构化测试,检查代码并观察运行状况,利用查找代码功能和实现方式得到的信息来确定哪些需要测试,哪些不需要,如何开展测试,包括如下内容:
(1) 直接测试底层函数过程,子程序和库(API)
(2) 以完整程序的方式从顶层测试软件,根据对软件运行的了解调整测试用例
(3)从软件获得读取变量和状态信息的访问权,确定测试与预期结果是否相符,强制软件以正常测试难以实现的方式运行
(4) 估算执行测试时命中的代码量和具体代码,调整测试,去掉多余的测试用例,补充遗漏的用例
动态白盒测试与调试的区别:都包括处理软件缺陷和查看代码的过程,但是它们的目标不同:测试的目标是寻找软件缺陷;调试的目标是修复缺陷
测试方法:分段测试(单元测试和集成测试)、数据覆盖、代码覆盖
数据覆盖:
数据流覆盖,在软件中完全跟踪一批数据。
次边界:与动态黑盒测试类似。
公式和等式:类似除法运算中,考虑除数为0的情况。
错误强制:迫使软件中的所有错误提示信息显示出来。
代码覆盖:测试程序的状态以及程序的流程,设法进入和退出每一个模块,执行每一行代码,进入软件每一条逻辑和决策分支
代码覆盖包括:程序语句和代码行覆盖、分支覆盖(比如判断语句中if分支和else分支)、条件覆盖(一个条件中可能包含几个子条件,要覆盖每一个子条件及它们的组合)。
App测试其实就是在用户之前使用和运行软件,尽早找出软件中存在缺陷。我们不可能对软件进行完全测试,只可能在测试有限的用例后使得软件仍然存在bug的概率尽可能小。以上所述仅仅只是一点皮毛,App测试覆盖的知识面很广,需要学习的还有很多!!
收起阅读 »
快讯! 环信sdk红包正式发布了。让所有的app都有属于自己的红包!
SDK下载 : http://www.easemob.com/download
注意红包功能现仅用于环信iOS, Android SDK 2.0, 3.0SDK暂未发布,请与我一起期待
文档已经包含在SDK包里,下载后可见。
快速体验带红包功能的demo
one more thing,
同期发布的SDK中一并增加了 阅后即焚,消息撤回的功能,有待你的发现哦。
收起阅读 »
本周末,中国开发者技术生态联盟邀你一同谈“技术”
云计算、VR、H5、即时通讯……本周末(3月27日),中国开发者技术生态联盟系列沙龙将走进杭州东部软件园。
如果你是一名不折不扣的“技术帝”并且想要扩大社群圈提升自我、充实技术和行业经验;如果你是一名与电商、零售、金融、互联网行业相关的创业者,想要了解大数据、云计算在实际行业中的实际应用,寻找创业技术合伙人;如果你是项目需求方、投资方、解决方案服务商,了解和认识新技术、新思想、发现和挖掘新的潜在独角兽,现场沟通与交流丰富自己的信息渠道。那一定不要错过这场技术界的“盛宴”。
据本次活动主办方崔牛会和中国开发者技术生态联盟介绍,本次活动将邀请到WeX5开发工具首席技术运营官王洁、环信技术经理杜超、UCloud高级架构师林超、极企科技联合创始人孙冰等行业大咖为与会的“技术宅”们带来“H5应用如何做到极速秒开”、“让APP快速实现即时通讯”、“资本如何看待开发者项目”等精彩分享。
如果你对此次活动感兴趣,如果你想提升自我,那就赶紧点击进入报名通道了解详情吧。咨询热线:15168266111 收起阅读 »