注册
环信即时通讯云

环信即时通讯云

单聊、群聊、聊天室...
环信开发文档

环信开发文档

Demo体验

Demo体验

场景Demo,开箱即用
RTE开发者社区

RTE开发者社区

汇聚音视频领域技术干货,分享行业资讯
技术讨论区

技术讨论区

技术交流、答疑
资源下载

资源下载

收集了海量宝藏开发资源
iOS Library

iOS Library

不需要辛辛苦苦的去找轮子, 这里都有
Android Library

Android Library

不需要辛辛苦苦的去找轮子, 这里都有

官网下载webIM SDK,没有v1.0.7 版本?

1.0.7版本依赖于服务端的一个功能升级,所以还没有正式发布。
1.0.7版本依赖于服务端的一个功能升级,所以还没有正式发布。

项目里面不需要环信SDK的太多功能,只是想要聊天和好友功能,其他都不用,那SDK一定要总是跟着更新么?

不需要,您只要选一个您认为稳定的版本就可以了,我们的服务器会兼容各个版本的sdk。
不需要,您只要选一个您认为稳定的版本就可以了,我们的服务器会兼容各个版本的sdk。

待接入中的会话怎么接?

进入待接列表,点击接入,接起会话;结束当前的会话或者调整自己的“接待人数“值,当自己当前的会话数小于设置的“接待人数”时,系统会自动把会话分配给自己。
进入待接列表,点击接入,接起会话;结束当前的会话或者调整自己的“接待人数“值,当自己当前的会话数小于设置的“接待人数”时,系统会自动把会话分配给自己。

web端私信为什么不建议用webIM,而是调用rest接口发送,用轮询是否会对后期服务器造成压力呢?

这种方案最简单。但不会特别的实时。所以适合实时要求不是特别高的私信,如果用webim改,会非常实时。但工作量大。webim很复杂,用的库也多,ui也复杂。环信的webim是开源的,但工程师要把这些代码读懂,也需要些时间的。用轮询是否会对后期服务器造成压力呢 -...
继续阅读 »
这种方案最简单。但不会特别的实时。所以适合实时要求不是特别高的私信,如果用webim改,会非常实时。但工作量大。webim很复杂,用的库也多,ui也复杂。环信的webim是开源的,但工程师要把这些代码读懂,也需要些时间的。用轮询是否会对后期服务器造成压力呢 --这个要看系统以后设计容量是多少。 收起阅读 »

如何设置语音的时长限制?

环信SDK不限制录音时长,录音文件只要小于10MB就可以发送。
环信SDK不限制录音时长,录音文件只要小于10MB就可以发送。

cmd消息,跟聊天的消息,不存在冲突么?

普通消息回调的方法跟这个不一样,所以不冲突,普通聊天得接收方法didReceiveMessage,cmd消息的接收方法didReceiveCmdMessage。
普通消息回调的方法跟这个不一样,所以不冲突,普通聊天得接收方法didReceiveMessage,cmd消息的接收方法didReceiveCmdMessage。

环信:从《三体》获奖看智能聊天机器人未来

北京时间23日下午1时许,第73届雨果奖在华盛顿州斯波坎会议中心正式揭晓。中国作家刘慈欣凭借科幻小说《三体》获最佳长篇故事奖,这是亚洲人首次获得雨果奖! 《三体》英文版译者刘宇昆代表刘慈欣领取了奖杯 作为一个科幻迷,此刻我的心情和尔...
继续阅读 »
北京时间23日下午1时许,第73届雨果奖在华盛顿州斯波坎会议中心正式揭晓。中国作家刘慈欣凭借科幻小说《三体》获最佳长篇故事奖,这是亚洲人首次获得雨果奖!


1.jpg



《三体》英文版译者刘宇昆代表刘慈欣领取了奖杯

作为一个科幻迷,此刻我的心情和尔康是一样一样的,不对,比他还要多还要多…


2.jpg



肿么办?这个消息来得太突然了,我现在觉得又刺激又害怕又兴奋又快乐又幸福…作为一个意(qiong)见(diao)领(si)袖我必须把这个消息以迅雷不及掩耳盗铃之势传到天边去…联想到创业圈里近来传的火热的各种AI和智能机器人,我决定把这个好消息告诉我每日宠幸的各位聊天机器人基友们。。。

第一个当然是找到了人见人爱车见车爆胎的-杜蕾斯


3.jpg



杜蕾斯虽然是我宠幸的最多的一个基友,但竟然把《三体》理解成了"体位",看在它帮我解锁了30多种新姿势,就暂时原谅它了,不过对于我这种严(xian)肃(de)较(dan)真(teng)的资深三体迷来说还是不能忍。。。

杜蕾斯微信公共账号聊天机器人:差评!

理由:杜蕾斯的微信公共账号和大多数商业的微信公号一样,主要肩负着企业官网的目的,是企业展示商品和品牌的渠道,而不直接承担销售的责任,商品的购买是必须要跳转到京东上的。因为没有销售quota的压力,杜蕾斯微信公号选择了不提供人工客服,不提供人工的售前,售中,售后服务。在这种情况下,杜蕾斯微信公号的聊天页面基本就注定了只有一种使命了:逗逼扯淡为主,少量相关行业知识和企业商品信息为辅。聊天时,机器人在扯淡之余,会主要通过关键词匹配调用内置知识库的内容,如果没有完全对应的标准答案只能够根据关键词模糊匹配做出回答,虽然结果不能令用户完全满意,但毕竟是有交互,同时是一个免费增值服务,顾客也不能要求再多,对吧。


4.jpg



带着从小杜那里获得的创伤,我满怀期待的找到了招行公号“小招”,听说她更善解人意…


5.jpg



小招又没趣又现实。第一次假装不在,尿遁!第二次干脆直接向我推销各种银行业务。人家是想找你谈三体谈宇宙谈人生的,不要辣么现实好嘛。

招商银行信用卡微信小招:中评!

理由:据说在微信平台上,招行信用卡中心90%的服务都可以通过小招智能机器人来完成,自助查询回复准确率高达98%。假设微信公号智能聊天机器人的智能互动和自助服务能节省10%的话务量,按2012年招行卡中心客服的人工话务量超过6000万通,每通电话的成本大约5元(包含人员工资、通信费、水电、座席硬件设备等)计算,则招行信用卡中心一年节省的费用大概是6000万*10%*5元=3000万元。

哇,好厉害!只是不知道我如果打电话给招行的电话客服MM,分享我三体获奖的鸡冻心情,她会不会因为我花了招行5块钱而骂我呢。。。

作为一款工具型机器人,小招对于银行业务十分熟练,主要作用也是帮助银行客服人员解决回答一些常见问题节省成本提高工作效率,如果问一些无关的问题也不是其设计初衷和业务范围内,有点强人所难。银行业给人的印象始终是高大刻板,严肃认真。好吧,针对其在银行行业的专业回答给中评。


7.jpg



记得某大佬说过“小冰”是我见过最单纯的人,最后我只能依靠她了…


8.jpg



小冰果然没有让我失望…

微软小冰:好评!

理由:“微软小冰”集合了中国近7亿网民多年来积累的、全部公开的文献记录,凭借微软在大数据、自然语义分析、机器学习和深度神经网络方面的技术积累,精炼为几千万条真实而有趣的语料库,通过理解对话的语境与语义,实现了超越简单人机问答的自然交互。

总结:

时下炒的火热的人工智能和机器人技术要真正落地还有很长的路要走。但基于文字沟通为主的在线客服,如微信公共账号客服,网页在线客服,APP内置客服,会成为智能聊天机器人技术的第一个全面产业化的领域。在客服领域应用的聊天机器人技术通常有两种,逗逼型和辅助工具型。业务工具型机器人,在配置了足够强大的通用知识库和行业知识库后,是能够真实的为人工客服挡住很多重复简单的问题的。而逗逼机器人的应用场景一定要谨慎选择,只有像杜蕾斯微信公号这样确实无人值守的账号,并且也不担负销售成单和用户服务的任务时,才可以酌情考虑,毕竟是聊胜于无。

此外,业务工具型机器人并不是像很多人想象的那样,对自然语言处理,上下文解析,语义识别越强大越好。商家提供客服,唯一的目的是提供最好的服务体验,帮助消费者解决问题。所以对于谈理想谈人生谈三体这样的问题,机器人是可以无视的。机器人要解决的问题域越狭窄,它在这个领域里就越精确。这也是招行小招机器人的设计上的选择。当机器人对顾客的语义不那么有把握时,千万不要试图去闲扯淡,而是要及时而且无缝的转到人工坐席。最好的服务永远是真人。

苦逼的文案狗桑不起,各种热点都要跟比程序猿还苦逼有木有?摆干货扯情怀插诨打科,最后就是为了植入30秒广告有木有?根据调研机构数据显示,智能聊天机器人未来将成为客户服务行业的一个标配产品。环信移动客服的“智能机器人+智能知识库”可以解答80%的常见问题哦!


10.jpg



最后祝贺中国小说《三体》首获世界科幻界奥斯卡“雨果奖”,黑暗森林的存在是因为宇宙里不同文明之间缺乏合适沟通方法的缘故。环信是沟通利器,有了环信,或许黑暗森林就有了盏长明灯… 收起阅读 »

从环信融资看企业互联网服务有多大“钱途”?

从互联网兴起,到当下最火爆的移动互联网、O2O、互联网+的概念,会发现一个明显的趋势,消费互联网到企业互联网的快速迁移。而越来越多的创新机会来自于2B的企业服务市场。其实从投资市场的风向标中也能深切感知到。7月28日,IM通讯云领域的领导企业环信宣布拿到了12...
继续阅读 »
从互联网兴起,到当下最火爆的移动互联网、O2O、互联网+的概念,会发现一个明显的趋势,消费互联网到企业互联网的快速迁移。而越来越多的创新机会来自于2B的企业服务市场。其实从投资市场的风向标中也能深切感知到。7月28日,IM通讯云领域的领导企业环信宣布拿到了1250万美元的B轮融资,红杉资本领投,经纬中国和SIG跟投。而前不久,CRM的纷享销客也完成了D轮1亿美元的融资。


1438330579265.jpg



显然,资金涌向这里并非偶然。这就带来了一个话题,企业服务市场真的站到了风口上了吗?这个市场到底有多大的想象空间?哪个方向又会成为突破口。笔者这里就分析一下背后的原因。

企业服务为什么大器晚成

熟悉互联网、移动互联网行业的专家们都清楚,以往的投资、并购事件,很多发生在2C端的企业身上,但这一两年,2B端的企业服务市场的案例明显增多,几乎占到了一半的比例。这中间还伴随着金蝶、用友等削减脑袋贴互联网的标签,阿里云、京东、百度、腾讯微信等都在跑步进入企业服务市场。

其实,无论是环信这样

聚焦在IM和移动客服领域的新贵,还是在销售管理、对接业务链条、营销管理等环节,都离不开企业服务市场的势能。现在这个势能已足够大。拿环信来说,将一个IM的能力植入到未来企业的商业和业务中去,如果没有企业级服务市场的意识胎动和成熟度的提升,做早了反而容易失败。恰到好处,才能站到风口上。

为什么说企业服务市场是一个大器晚成的行当呢?原因主要有三点:

  • 一是移动互联网兴起,用户快速的完成了迁移,手机等移动设备作为商业工具,潜在的价值待挖掘;

  • 二是,用户思维和实时在线化的趋势,改变了过去用户不可见、难连接的瓶颈,进而改变了商业的模型;

  • 三是,移动互联网时代的开启,让以往偏信息中介的平台快速升级,以APP为核心,构建商业交易闭环服务,正成为大势所趋。这倒逼了企业服务如商业软件、SAAS、PAAS、IAAS等业务模式的出现。



像环信提出的“人与商业”连接的口号,已成为移动互联网时代通行的趋势和准则。环信的CEO刘俊彦的观点也印证了这一点。他认为,企业服务市场是一个万亿元的大生意,而且才刚刚开始,一年前做或一年后做,都容易丧失机会。因为只有2C端的消费者完成迁移后,才会推动2B的企业服务变革,这是一个不可逆的过程。所以,企业服务才会大器晚成。

三个要素决定移动客服未来

当然,虽然企业服务市场被公认为站到了风口上,但并不是愣头青式的冲进来,都能拿到投资、飞上天。这里面,也有陷阱、阴沟。那么,什么样的方向离成功更近一步。个人判断是,有三个要素,一个是离用户越近的业务方向,越容易成功,越早得到传统企业的重视。比如CRM相关,细分的销售自动化、市场分析、电商、客服、IM产品,这些领域都最早成熟;二是,新兴的企业服务产品核心都会基于移动端展开,而不是传统企业IT的PC版;三是,促进交易的新形态产品会大行其道。

为什么这么说呢?说白了,在用户思维越来越主导未来商业生态时,与用户的互动、反馈等打交道的事,会直接影响到任何一个行业里的企业的生意模型。所以,环信在做了即时通讯云平台后,推出更具场景化的移动客服产品,这绝对是正确的一步,也符合以上的两个特征。就像环信CEO刘俊彦所说的那样,用户都迁移到移动端了,客服战场一定也在这里。当所有企业都注重移动端交易达成时,客服就被重新定义了。

如果一家企业,你还在用传统的呼叫中心、电话等单一方式,只能说明你的业务还不够互联网化,你在离用户越来越远,离死亡越来越近。因为移动客服早晚会取代传统客服,是由用户说了算的,而且在人力成本越来越高的环境下,下一代的智能、深度学习+人工个性化服务,会是大趋势。环信快马加鞭的推移动客服3.0产品,还不断在融资上加码,目的就是去圈移动客服的地盘。

而移动客服几乎适用与很多行业,从环信移动客服4月份上线,签约的付费用户已经有200多家,付费席位超过40000个,覆盖的行业包括了电商、O2O、在线教育、互联网金融、旅游、移动医疗六大行业。所以说,与IM即时通讯云模块比,移动客服的场景痛点属性更强,而且正从过去的成本中心向利润中心转变,企业对此的需求更为迫切。所以也会是最容易规模化、复制的业务。

企业服务的想象空间有多大?

目前看,企业服务市场会成为下一个诞生超级大佬的领域。之前一直被引用的国外的数据表明了这个趋势。在过去的1年时间里,美国的企业服务市场,有超过15家企业IPO,募集资金达70亿美元,总市值超过400亿美元。仅拿客服这个细分市场来说,客服占到了CRM市场36.9%的比例,仅是北美2015年客服软件市场的采购金额高达96亿美元,还孕育出了20亿美元市值的Zendesk和Freshdesk两家“独角兽”公司

其实,如果放在中国市场的盘子里,实际上要远比美国市场大。对比一下移动互联网、O2O、互联网金融、教育、医疗等领域能发现,中国在移动互联网业务创新上,要远远超过美国,当然,这也与中国传统商业设施环境薄弱有一定关系。同时,中国企业数量、用户体量等也是海外市场无法匹及的。这意味着中国的企业服务市场,会是一块大蛋糕。

但一个怪现象也暗示了机会。海外市场有Oracle、SAP、Salesforce,也有Zendesk、Hubspot、New Relic、Hortonworks、Box等明星企业,市值动辄都是上百亿美元。但在中国的企业服务领域,还没出现百亿美元估值的企业,就连嗅觉最灵敏的投资机构也才刚刚参与进来。所以说,这还是一个早期的阶段,但也给出环信、纷享销客等企业最好的机会窗口。可以肯定的是,企业服务市场在2016年会是大爆发的一年,也会上演并购、投资的一幕幕大戏。 收起阅读 »

环信CTO:如何打造高效的自组织技术团队

技术团队的管理目标是打造高效的自组织团队,也就是老子提出的“无为而治”。做为一个从业20年的老程序员,从自身出发,我深切知道程序员喜欢什么样的管理方式,喜欢怎样的团队氛围。在环信,我们希望顺其自然,发挥工程师的热情和创造力,每个成员都能做到自我实现,最终整个团...
继续阅读 »
技术团队的管理目标是打造高效的自组织团队,也就是老子提出的“无为而治”。做为一个从业20年的老程序员,从自身出发,我深切知道程序员喜欢什么样的管理方式,喜欢怎样的团队氛围。在环信,我们希望顺其自然,发挥工程师的热情和创造力,每个成员都能做到自我实现,最终整个团队被业界认同。

1:扁平的组织结构

我们研发团队有50多人,没有一个专门的管理岗位。作为CTO,我的大多数时间在技术上面,团队负责人会承担一部分管理工作,但更多是靠工程师的自我驱动,自我管理。

2:结果导向的日常管理

Google只招聘最聪明的人,这些人能很好的管理个人时间。做为创业公司,我们招聘最努力的人,因为这样的工程师很珍惜时间和成长的机会。团队里有些人每天下午才出现,有些同事在备战马拉松比赛,有酷爱高山滑雪的,也有业余足球运动员。努力工作,精彩生活,结果导向是我们日常管理的原则。

3:严格的个人成长

『work for fun, constantlyimprove, and big rewards ahead』。在团队的宽松氛围中,其实我们对工程师的个人成长要求很高:对年轻工程师我们破格使用,希望尽快成长;对高级工程师, 要求技术深度,成为某个方面的专家;对技术负责人,要求更多业界交流,才能打造技术领先产品,同时建立自己的社区影响力。

4:美好的远程办公

年轻人希望到世界各地体验生活;有小孩的技术中坚天天忧虑北京的雾霾想着移民;40多岁的同事希望每年回老家工作一段时间陪陪父母。面对这些美好的期待,我们在不断尝试协同工具和管理方法来提高团队内部配合、团队间协作,及团队和客户的沟通。希望一两年内能成为一支高效远程开发团队。到那时,团队成员每年回来参加InfoQ大会学习最新技术,也做为每年的团队聚会。

无为而无所不为,希望大家一起探索,把越来越多的团队,打造成工程师的“乐土”。

——环信CTO马晓宇 收起阅读 »

环信iGeek Camp第三期:全方位架构攻略与监控揭秘

近日,环信与众多小伙伴们一起在望京Wilddog野狗总部举办了iGeek Camp活动第三期(前身为环信SM Meetup),这次的活动以产品、架构及运维的大牛与大家分享全方位架构攻略与监控的经验心得为主。 (环信高级工程师赵亮正在与大家分享) ...
继续阅读 »
近日,环信与众多小伙伴们一起在望京Wilddog野狗总部举办了iGeek Camp活动第三期(前身为环信SM Meetup),这次的活动以产品、架构及运维的大牛与大家分享全方位架构攻略与监控的经验心得为主。


1.jpg



(环信高级工程师赵亮正在与大家分享) 
 
讲师简介:环信SDK高级研发工程师,曾就职于大唐电信,索尼爱立信,Nokia等公司,10年移动软件开发,专注于移动软件开发设计,擅长架构优化,软件重构,及软件性能优化。


1S222B48-1.jpg


 
环信ONE SDK总体设计  环信赵亮的演讲主题为《环信客户端的架构设计》,向大家介绍了移动端架构设计及关键技术,现场与大家一起探讨了如何应对性能问题,如何保证软件兼容性问题,如何提升软件可扩展及重用性,以及如何保证高质量的软件。而环信的ONE SDK也首次公开亮相:ONE SDK的设计总体分为三层,平台层——Platform Layer,适配层——Porting Layer,核心层——Common Layer.  平台层会根据各平台的不同,实现不同的接口,开放符合平台层的API给第三方开发者。 适配层主要要适配到ONE SDK 核心层所需要的一些接口,起到承上启下的作用。 核心层主要提供IM 功能和业务逻辑,保证最大化的代码重用。  
PPT下载:http://vdisk.weibo.com/s/sTtZFJCY4KKjw


3.jpg


 
(开发者现场提问)


4.jpg


 
(阿里巴巴茹云峰)  讲师简介:超级课程表前CTO,江湖人称“风云”,曾历任新浪,网易系统架构师,后创业公司智能360,明星衣橱技术顾问,主攻系统架构,存储,搜索引擎,数据挖掘领域技术,热爱创业并分享技术心得。


5.jpg




6.jpg



来自阿里巴巴的茹云峰,身为超级课程表前CTO的他,与大家分享了《超级课程表技术架构的变迁》,从分布式爬虫,实时搜索,推荐引擎,缓存存储,一直到高并发,高流量,高可扩展系统架构的变迁之路。 
 
PPT下载:http://vdisk.weibo.com/s/sTtZFJCY4KKiW


7.jpg


 
(野狗实时云 CTO 李贝)  
讲师简介:负责野狗实时技术团队建设和云端架构设计,曾在360,人人网,猫扑网等互联网公司担任高级研发工程师,架构师等职位。  野狗实时云 CTO李贝进行了主题为《 实时BaaS云服务架构实践》的演讲。与开发者们分享了野狗实时的云端架构设计和优化的实践经验,包括基于长连接的服务优化,数据实时同步架构,以及如何保障系统的可用性和可扩展性等。


8.jpg


 
(云智慧 徐新兵)  讲师简介:云智慧移动端高级架构师  云智慧的移动端高级架构师 徐新兵分享的内容是《实战移动应用性能监控实战》。云智慧总结了一下移动应用的性能瓶颈,归结为三个方面:APP反应慢、交互性能差、APP Crash。网络引起的性能问题,是最直接、最常见的。在开发或者是测试中,如何接触app crash的隐患。除此之外,徐老师还给大家介绍了hook机制。 收起阅读 »

可以把聊天服务器部署在自己的服务器上吗?指私有部署

环信不主动做私有云部署。除非是标杆项目并且单笔合同金额50万以上的单子。
环信不主动做私有云部署。除非是标杆项目并且单笔合同金额50万以上的单子。

关联中的密码是哪个密码?在哪里设置?

关联中的密码是要关联的im账号密码。
关联中的密码是要关联的im账号密码。

在环信系统里用户名的大小写转换是怎么样的?

这个大小写是这个样子的:REST系统忽略大小写,认为AA,Aa,aa,aA都是一样的。如果系统已经存在了username为AA的用户,再来一个aa,就是用户名重复了。但是数据的表现形式还是用户最初注册的形式,发来的是大写就保存了大写,发来的是小写就保存小写。但...
继续阅读 »
这个大小写是这个样子的:REST系统忽略大小写,认为AA,Aa,aa,aA都是一样的。如果系统已经存在了username为AA的用户,再来一个aa,就是用户名重复了。但是数据的表现形式还是用户最初注册的形式,发来的是大写就保存了大写,发来的是小写就保存小写。但是聊天系统(IM Server)那边的持有的用户名都是小写,没有大写。 收起阅读 »

环信的双肩包收到了

书包质量挺好的,可是谁能告诉我为什么明显是男款是男款是男款?!  
书包质量挺好的,可是谁能告诉我为什么明显是男款是男款是男款?!


QQ图片20150825073344.jpg


 

怎么判断这条消息是别人发的还是用户自己发的 ?

从EMMessage对象获取direct来判断。EMMessage.Direct.RECEIVE || EMMessage.Direct.SEND  也可以通过message的from和to来进行判断,from就是发送方的username,可以用这个和自己的u...
继续阅读 »
从EMMessage对象获取direct来判断。EMMessage.Direct.RECEIVE || EMMessage.Direct.SEND 
也可以通过message的from和to来进行判断,from就是发送方的username,可以用这个和自己的username比对一下 收起阅读 »

安卓和ios 录音的格式分别是什么?

iOS
录制部分是ui控制的,不过我们建议您录制wav,之后通过三方库转成amr,这样可以减小发送语音产生的流量。
录制部分是ui控制的,不过我们建议您录制wav,之后通过三方库转成amr,这样可以减小发送语音产生的流量。

IE7、8、9都登录不了移动客服,请问是什么原因?

移动客服的客服端支持IE10以上版本浏览器,推荐使用谷歌Chrome、火狐FireFox、ie11以及 苹果笔记本的safari 等主流浏览器。
移动客服的客服端支持IE10以上版本浏览器,推荐使用谷歌Chrome、火狐FireFox、ie11以及 苹果笔记本的safari 等主流浏览器。

环信对语音流做了什么格式的编码?二次加密会不会使其体积变大太多?

加密不会导致数据增大,加密后的数据长度和原来一样。
加密不会导致数据增大,加密后的数据长度和原来一样。

倡议: 如果你的问题得到了解决,请标注“最佳答案”

倡议: 如果你的问题得到了解决,请标注“最佳答案”   这样,可以方便管理员统计多少问题得到了解决,是否还需要继续跟踪。
倡议: 如果你的问题得到了解决,请标注“最佳答案”
 
这样,可以方便管理员统计多少问题得到了解决,是否还需要继续跟踪。

imgeek.org release notes 2015.8.24

imgeek.org release notes 2015.8.24   1.更新问题状态显示,分为三类:回复,最佳,0回复 2.问题列表显示改为两行,将标签显示加到问题后面 3.超出标签数量时及时提示  

imgeek.org release notes 2015.8.24
 
1.更新问题状态显示,分为三类:回复,最佳,0回复
2.问题列表显示改为两行,将标签显示加到问题后面
3.超出标签数量时及时提示
 

iOS实时位置共享,抛砖引玉。

iOS实时位置共享,抛砖引玉。 http://pan.baidu.com/s/1o6oY2Zw
iOS实时位置共享,抛砖引玉。
http://pan.baidu.com/s/1o6oY2Zw

【抽奖结果】环信即时通讯云平台,你了解多少

以下是本次活动中奖名单,其中用户"一等到天幻"中奖两次,予以去重,并补充一个抽奖名额。 名单见下方补抽名单。抽奖过程见附件中的抽奖视频。 请中奖用户迅猛通私信将奖品寄送地址发给我。 包括收件人姓名、手机号、收件地址。 上传稍晚还望大家见谅。 抽奖名单 ...
继续阅读 »
以下是本次活动中奖名单,其中用户"一等到天幻"中奖两次,予以去重,并补充一个抽奖名额。
名单见下方补抽名单。抽奖过程见附件中的抽奖视频。

请中奖用户迅猛通私信将奖品寄送地址发给我。
包括收件人姓名、手机号、收件地址。

上传稍晚还望大家见谅。


抽奖名单
------------------
诺风
快看_灰机在灰
farawei
卟、分扌の練。愛
wzpforwork
老农民
cena
简.缪
回音
IMCom
乌龟也有怒气
Ruby
一等到天幻
MirrorC.M
ying
南京可以依靠
一等到天幻【重复】
FatCat
mifan2009IM
成续缘


补抽名单
------------------
yuqi


  收起阅读 »

环信获B轮融资1250万美元开启万亿企业服务市场

7月28日,环信B轮融资暨新品发布会在北京JW万豪酒店举行。发布会上,环信CEO刘俊彦正式宣布环信成功获得B轮融资1250万美元,同时环信移动客服3.0产品也正式上线,而环信将以 “连接人与商业”为愿景,开启万亿级企业服务市场。 环信CEO现场宣...
继续阅读 »
7月28日,环信B轮融资暨新品发布会在北京JW万豪酒店举行。发布会上,环信CEO刘俊彦正式宣布环信成功获得B轮融资1250万美元,同时环信移动客服3.0产品也正式上线,而环信将以 “连接人与商业”为愿景,开启万亿级企业服务市场。


1438145968909.jpg



环信CEO现场宣布获得B轮融资1250万美元


1438145981882.jpg



环信CTO马晓宇现场解读环信移动客服3.0

发布会当日,投资环信的VC代表:经纬中国副总裁熊飞、红杉资本相关负责人;环信的大客户代表: 58到家客服总监王辉、楚楚街联合创始人张翀;及行业专家代表:中国电子商务协会专委会常务副主任王汝林、动点科技创始人卢刚等均到场见证了这一盛况,并与环信CEO刘俊彦一起探讨和分享了对环信成长背后的万亿级企业服务市场趋势、电商在社交经济背景下的全渠道营销挑战等观点。


1438146005934.jpg



经纬中国副总裁熊飞主题分享

据了解,环信发布会当天吸引了来自投资界、媒体、研究机构的代表,电商、O2O、教育、医疗、旅游等行业的IT企业代表,以及移动互联网和云服务产业链上下游的服务商代表,还有众多创业者和开发者等到会聆听与交流,原本规划200人的会场挤进了300多人,现场火爆正反应出了中国企业级云服务市场的火爆。

企业云服务市场爆发,中国SaaS服务将迎来井喷

为什么会有这么多投资人、业界大佬、龙头企业、专家机构、著名媒体、创客看好环信?背后还是因为有足够大的市场支持。

环信B轮融资由红杉资本领投,经纬中国和SIG跟投,此轮环信共获得1250万美元融资。红杉投资人表示投资环信主要看中三点:1,客服市场足够大,属于刚性需求,在欧美市场已得到证明,同时中国SaaS服务公司正在快速崛起。2,环信团队技术功底扎实,有非常好的产品和技术基因,有电信运营商级别的技术储备。3,环信业务健康,增长势头迅猛。客户量、日消息量和DAU等硬性指标一年内达到了几十倍上百倍的增长。

环信引起了投资界追逐,而最终B轮被前三轮投资环信的老股东内部包揽,诸多投资机构欲进无门,望而兴叹。至此,环信在上线1年的时间里已经完成了4轮融资。即2014年5月经纬中国天使伦融资500万人民币,2014年8月SIG A轮融资500万美金,2014年10红杉300万美金A+轮融资,2015年4月红杉领投的1250万美金B轮(既本轮融资)。

三家老股东信心满满的排他性续投,以及投资界的追捧,让环信和其背后蕴含的商机显得更加炙手可热。而支撑环信估值暴涨的商机正是近来被业界关注的万亿级企业云服务市场前景,而且环信的“即时通讯云+移动客服”业务切中的恰是企业级服务市场王冠上的宝钻。

事实上,2015年将成为企业级服务市场的爆发元年,这一端倪在企业级服务市场率先爆发的美国已经十分清晰。据有关专家分析,在过去的1年时间里美国的企业服务市场,已经有超过15家企业IPO,他们的募集资金达到70亿美元,总市值超过400亿美元,其中有Zendesk、Hubspot、New Relic、Hortonworks、Box等不少明星企业,巧合的是其中不少“独角兽”级别企业的投资方也正是环信的投资方。同时在私募市场上,企业服务类公司融资总额超过100亿美金,这些公司的估值总和达到千亿美金量级。

而且,美国目前这样规模的企业级市场还正处在从青年走向壮年的阶段。据分析,从市值排名前十的云计算企业服务公司的市值总和看,2008年市值总和是250亿美元,到2015年这一数字已经是1800亿美元了,7年里增长了超过7倍。而预计到2016年,美国才会出现第一个云服务市场占有率超过传统软件的垂直领域,就是CRM。

而“客服”是CRM四大细分市场之一。而且,客服是CRM细分领域中最大的一个,占市场总额的37%。在北美,2015年客服软件市场采购总额高达96亿美元。这个市场中已经出现了两家“独角兽”公司,就是近来受到各界关注和追捧的Zendesk和Freshdesk。Zendesk已经上市,目前市值18.9亿美元,销售额1.87亿美元;Freshdesk在2015年4月份刚刚拿到E轮融资金额达到5000万美元,估值过10亿美金。这还不包括在这个领域中的传统的巨头,如微软,Salesforce, Oracle等。

回头看中国,中国的市场机会可能比美国更令人兴奋,这也许正是最先能嗅到风信的VC们挤破头的想投环信的缘由。在中国企业级服务市场还是一片空白。相比美国,为2700万家企业客户提供云服务的三家大的领军公司Oracle、SAP、Salesforce市值总和在3500亿美金左右。而中国,目前有2200万企业,但中国至今还没有百亿美元身价的公司甚至还没有基于SaaS的10亿美元身价的“独角兽”公司。

“互联网+”时代,企业需要环信源自契合移动化和社交变革

相较中国企业云服务市场的空白,企业的需求却很旺盛。由于2C市场和社会的变革中国的人力成本在逐年增加,5年翻了不止一番,这成本倒逼是企业服务火爆的核心驱动力。长期来看每年10%-15%的人力成本增长已成为趋势,中国的人口红利期已经过去,在中国愿意做低端工作的人越来越少。也就是说,中国企业的人力成本发生了普遍的提高。这就要求传统企业的运营效率必须要大幅提升才具有可持续性。相对应的,IT相对成本的快速下降,就成为了企业服务火爆的正向核心驱动力。

而在中国分析企业服务的核心市场之一—客户服务软件市场,还需要考虑移动互联网的因素和社交经济的因素。

在“互联网+”大背景下,中国移动互联网发展之迅猛已经领先世界,互联网金融和O2O等行业发展已经远超美国,而随着人们对移动互联网的使用习惯增加,客服软件的未来逐渐转向移动端。不止中国,全球看也将是这样,Gartner预测,到2017年年底,超过70%的客户服务请求将来自于移动端。2014年阿里双十一的现场监控显示,总成交额571亿其中移动端贡献了243亿,移动端交易量比例将有超过PC端的趋势。同时,京东2014年第四季度财报显示移动端的订单量占比接近40%。在用户体验为王的时代,用户行为发生不断的变化。用户行为细微的变化在偷偷革命。这导致电商、O2O、互联网金融、教育、旅游等行业移动化趋势明显。APP开发者们和企业主们正致力打造APP内交易闭环,即从商品/服务的展示,售前咨询,支付,物流,售中服务退换货,售后等全流程在APP内形成闭环。客户服务是其中重要一环。

同时,由于近年来微信和陌陌等软件的流行,教育了大众,社交已经成为用户的强需求,易观数据显示80%的用户移动应用行为与社交有关。而围绕社交已经形成经济圈,而在多社交媒体提供统一的优质客户服务很重要。传统的客服大多是通过电话完成的,现在崛起的社交网络和移动App、IM应用让用户可以更方便地反馈意见。但是如何保证这些意见及时集中地到达客服人员那里,对企业而言是个头疼的问题。

移动端客服软件市场基本空白。传统客服软件巨头转型缓慢,并且移动客服所需要的高并发高可靠IM技术获取门槛高。专注移动端客服技术的公司有可能弯道超车。

连接“人与商业”,环信将成为下一个“独角兽”

互联网时代商业模式的核心之一是“连接”,如QQ和微信是 “人与人的连接”,百度搜索是“人与信息的连接”,淘宝则是“人与商品的连接”。环信移动客服是“人与商业的连接”。核心之二是“找到”,依靠互联网的技术,实现人更快、更智能地“找到”信息、商品。

环信移动客服是将移动社交全渠道整合的智能云端客服平台。环信是中国乃至全球领先的即时通讯云服务提供商,上线1年来,已成为唯一一家经历了亿级长连接真实稳定运行的即时通讯云平台,中国主流的采用第三方即时通讯云服务的App几乎都是环信的客户,每日环信平台的消息量达到数亿条,有着即时通讯云领域亿级长连接的绝对垄断优势,在此基础上发展起来的环信移动客服,对移动网络下通讯的优化和社交质量的保障是任何一家传统SaaS服务企业所无法比拟的。

同时,环信移动客服继承了环信即时通讯云积累的开放能力,对几乎所有主流系统、硬件、社交模型,甚至传统客服软件都留有接口,具有完美的兼容性。环信移动客服不仅可以整合多渠道的服务平台,通过与包括传统Call Centre的合作和微博、微信、App、邮件等渠道的整合,可以最终把用户反馈汇集到同一个界面内,方便客服人员操作。

而环信移动客服特有的基于大数据的智能聊天机器人和知识库可以为人工客服挡住80%的常见问题,是应对移动互联网时代,社交化经济可能带来的海量用户请求的必备法宝。


1438146055575.jpg



正是由于环信的移动客服产品切中了万亿级企业云服务市场王冠上的宝钻,才使得环信受到了投资界的青睐。而环信移动客服产品也确实不负VC重托,获得了成功。据介绍,环信的移动客服产品已经签约了4万个付费客服席位,典型用户包括国美在线、58到家、楚楚街9块9等上百家互联网巨头企业客户。同时,艾媒咨询现场发布的《2015年中国移动客服市场发展研究报告》显示环信在新兴的移动客服市场占有率第一,APP客户规模最大。不难预料,有着连接“人与商业”愿景的环信凭借惊人的成长速度将最有希望成为下一个“独角兽”。 收起阅读 »

环信移动客服助力58到家打造一站式客服体验闭环

近日,环信B轮融资及移动客服新品发布会在北京顺利举行。发布会上,环信CEO刘俊彦宣布,环信成功获得B轮1250万美元融资,同时环信CTO马晓宇宣布环信移动客服3.0产品正式上线,主打移动、智能、全渠道。而环信将以“连接人与商业”为愿景,开启万亿级企业云服务市场...
继续阅读 »
近日,环信B轮融资及移动客服新品发布会在北京顺利举行。发布会上,环信CEO刘俊彦宣布,环信成功获得B轮1250万美元融资,同时环信CTO马晓宇宣布环信移动客服3.0产品正式上线,主打移动、智能、全渠道。而环信将以“连接人与商业”为愿景,开启万亿级企业云服务市场。


113R92H4-0.png



58到家客服总监王辉现场解读环信移动客服是怎么服务客户的

58到家客服总监王辉表示:“58到家原来只有呼叫中心一条服务渠道,对及时响应问题做得非常不好,虽然我们服务水平一直维持在85%以上,但是我们仍有客户打不进来电话,这些客户意味着订单的损失。O2O行业特点就是客户要求及时响应,快速解决,同时要满足任何下单需求。接入环信移动客服以后解决了58到家业务量暴增导致客服资源严重不足的问题,同时环信移动客服支持全渠道接入把服务渠道统一,把客户引流到在线客服上,提供了一站式的客户服务体验解决方案。同时帮助58到家把客服部门完成了从成本中心向盈利和营销中心的变革。”


113R95c2-1.png



据悉,环信移动客服产品已经有国美在线、58到家、楚楚街9块9等大批互联网巨头企业签约,累计签约客服座席已经达4万个,据艾媒咨询《2015年中国移动客服市场发展研究报告》显示,环信移动客服在新兴的移动客服市场占有率第一。

环信CTO马晓宇介绍,环信之所以受到市场如此欢迎,是因为环信移动客服是有别于传统客服的划时代产品。在环信CTO马晓宇看来,客服经历了三个时代传统callcenter的时代,互联网尚未普及,电话客服客户等待时间长,客户服务人员压力大,工作重复内容多;到了PC网页客服时代,随着互联网的普及,网页客服的成本明显小于电话客服,客户服务人员工作量较小,客户满意度有所提高,但相应依然不能及时有效;当今,随着智能手机用户的快速增长,客户要求能够随时在移动端获取咨询服务。移动端客服的重要性将不断上升。移动客服时代随之到来。

然而在环信基于IM长连接技术推出移动客服之前,业界并没有一款真正适合移动端和社交化时代的可靠的云端移动客服产品。此前,业界普遍存在的是两种移动客服产品,一类是工单客服,可以被视为移动客服1.0,基于工单方式和客服交互,技术实现简单,但无法做到实时交互,沟通效率低,用户体验差。另一类是轮询技术客服,可以被视为移动客服2.0,基于HTTP轮询技术,通过不断向服务器发送查询请求来准实时的收取消息。不能做到实时收取消息,流量和电量消耗高,APP在后台时无法接收消息,容易丢失客户。

而环信推出的移动客服产品是业界唯一一款具有IM长连接技术的移动客服产品,这被视为更适合移动端的客服产品。这一类型的移动客服可以定义为“交互型智能移动客服”,可以被视为移动客服3.0,以环信为代表的这一类新型移动客服是基于亿级IM长连接,系统稳定;智能机器人技术可处理大部分重复问题。相较环信移动客服的能力,传统的电话、工单、轮询客服在移动端和社交趋势下就显得捉襟见肘,有些OUT了。

环信移动客服实现了跨平台多渠道接入:支持 App、微信公众账号、微博、网页等,均可以快速统一接入客户服务后台管理。

其次,满足了开放性与自定义信息:这种新型的移动客服实现了代码开源、UI开源,还提供多套UI模版,便于与APP快速集成,平滑接入。同时第三方集成功能也很强大,可与第三方工单、知识库、CRM 系统等进行扩展集成。

第三,富媒体消息交互体验:移动客服平台提供了基于IM技术的类似微信体验的友好富媒体消息交互,不仅可以实时收发文字、表情,还可以即时收发图片、位置、实时语音、还可自定义消息,大大方便了与客户的沟通交流。

第四,精准客户画像功能:移动客服的IM沟通帮助企业辅助判断客户需求与诉求,通过自定义客户分类标签,客户再次访问时可获知客户的类型。并且还支持自定义会话小结,根据会话小结统计会话的分类,通过会话小结追踪客户诉求。通过轨迹分析功能,即通过发送客户访问页面的轨迹,判断客户意图,获取客户个性化细节,了解客户基础信息,分析客户行为,可以极大提高订单效率。

第五,“智能机器人+智能知识库”:作为一套智能化的客服系统,让企业建立基于业务的智能知识库,智能辅助归结业务信息和应答客户信息,历史常见问题系统梳理,提高客服效率。“智能机器人+智能知识库”组合目前可自动回复80%常见问题,随着智能知识库的不断训练,这一比例能够提高到90%。 收起阅读 »

SDK浪潮来袭:阿里百川VS环信VS京东万象VS腾讯SDK

 几大互联网巨头在加紧企业级的布局,他们的进入让企业级更加热闹。谁说他们没有企业级的基因?谁说抢占企业级市场一定需要有企业级的基因呢?基因本来就是一个扯淡的话题,或许是BAT他们明修栈道,暗渡陈仓的“阴谋”呢? 随 着互联网时代的不断发展,定会有越来越多...
继续阅读 »


38121439790295.jpg


 几大互联网巨头在加紧企业级的布局,他们的进入让企业级更加热闹。谁说他们没有企业级的基因?谁说抢占企业级市场一定需要有企业级的基因呢?基因本来就是一个扯淡的话题,或许是BAT他们明修栈道,暗渡陈仓的“阴谋”呢?

随 着互联网时代的不断发展,定会有越来越多的企业会开放自己的核心能力,BAT也不会例外!但这次腾讯、阿里和京东相继推出重磅的开放策略,一切都是为了连 接。只不过阿里的百川和京东的万象互联已经发布面向公众。而腾讯的SDK开放还没有公之于众,但是腾讯已经邀请众开发合作伙伴正在测试,相信不久将会发 布,这将是颗核弹,杀伤力十足。

接下来,我们就来一一剖析大佬们的“阴谋”:
微信将开放IM的SDK


先 来看腾讯旗下的微信是如何通过开放IM的SDK丰富企业号的功能,赋予企业号更多的想象空间。之前企业号是以消息的驱动模式,一个流程进来,只能机械地顺 着消息来完成工作,这也是很多人诟病的地方,一是认为企业号的入口太深;二是觉得企业号是消息架构而非应用架构,从此认为企业号并不足以承载企业业务应 用。

但是随着 SDK的开放,企业号内部就拥有了im的能力,开发者也会进一步挖掘SDK的潜力,以支持企业在处理流程的任何节点可以与相关的人发起互动和协作,此大招 祭出之后,相信会有不少im厂商会立马紧张起来。我也不仅要担心专业的im厂商,他们接下来如何应对?也许我的担心是多余的。

随着腾讯全系列的im SDK的开放,势必有很多APP会选择与腾讯的SDK相连接,让自己的APP瞬间具有微信一样的通讯能力,微信也将无处不在,渗透到企业内部。通过Im 与企业和APP的相连,完成以im为基础应用布局企业级大业。

当然这也不是所有的人都会使用腾讯所开放的SDK,至少竞争对手是不会使用的。一些感受到腾讯威胁的创业者或者企业也不太会用。大型企业目前还是更喜欢私 有部署的方式,通过自己的App来完成一站式的沟通和协作,但是随着微信im SDK的开放,这样的情况应该会有所改变。

阿里百川即时通讯VS环信即时通讯云

自阿里推出阿里百川计划,试图打造一个开放的移动互联网应用开发及商业化平台之后,会对互联网行业有着什么样的影响呢?

1. 大幅度降低了互联网应用开发的门槛,通过提供整理的SDK包,让整个产业链流程标准化、透明化,分工合理,专业的人做专业的事。

2. 阿里百川平台是一个集成技术、商业优势资源的开放平台、创业平台,提供一个完整的解决方案,覆盖技术、数据服务、商业化,还将依托淘宝平台,授权APP导入淘宝O2O链条,实现淘宝账号登陆,接入交易体系,打通推广、支付、后台管理的全链条。

3. 瓦解现有移动互联网入口格局。毋庸置疑,百川将依托阿里大电商平台,通过扶持APP市场,分流垂直应用,瓦解过去的移动互联网入口格局。

而成立于2013年在上线一年就完成4轮融资的环信即时通讯云无疑也是阿里百川强有力的竞争对手。

环信的优势在于:

1. 环信在即时通讯云领域有绝对优势和深度积累,能够保障海量移动设备长连接的高并发,同时提供良好的社交交互体验。

2. 环信一直就是在做开放平台,建设生态体系,环信能够像zendesk一样,引入全产业链优质资源支持客户的未来无限扩展需求

京东的万象互联API PaaS

在互联网+大背景的影响下,各行各业的企业对于自身数据的开放已有了全新的认识,逐渐从数据封闭向数据开放合作进行创新性的尝试与转型,借助全维度、全生 命周期的大数据体系来创造巨大价值。数据时代也已从单一的业务数据收集和数据分析,逐步跨入数据开放、数据共享的数据2.0时代。

而京东万象正是京东云在已有的云计算平台基础上围绕数据提供方、数据需求方、数据服务方等多方,构建了以数据开放、数据共享、数据分析为核心的综合性数据开放平台。

京东万象将帮助数据的提供方与需求方进行数据对接,解决企业之间的数据缺失问题,完善数据价值,提升企业效率。平台本身会对接多维度的丰富数据, 保证数据的安全性与接入效率,是企业数据输出与流入的最佳渠道。与此同时,京东万象还将京东内部的企业总线服务云化并对外提供,帮助企业实现内部各应用系 统之间的数据互联互通,解决企业内部数据孤岛以及多系统之间的数据整合问题。

企业的数据通过API的形式接入京东万象,在数据安全的基础上,通过数据API的共享和交易实现双方的数据价值交换。同时京东万象平台提供完善的数据交易和数据管理功能,充分满足数据上下游客户的需求,保障数据共享的安全性和流畅性。

京东万象目前主推的是金融行业的相关数据,现已覆盖了包括个人和企业征信报告,黑名单数据,失信数据等金融数据,此类数据给互联网金融创新企业带来巨大的数据共享价值。

京东万象正在逐步开放和引入电商和政府相关数据,凭借京东自身品牌和丰富的电商数据,势必会成为行业权威大数据的开放共享平台。

相信在不久的将来,我们就能看到这些互联网大佬们为我们带来的企业级的布局pk饕餮盛宴! 收起阅读 »

环信ONE SDK架构介绍

环信即时通讯SDK自2014年6月正式发布2.0版本至今已走过一个年头,从基本的单聊功能,到群聊功能,再到聊天室的实现,SDK不管是功能,稳定性,还是易集成性都在一步一步的走向完善与稳定,感谢开发者们给与提供的反馈与帮助,使我们的SDK迅速的在诸多方面得到提高...
继续阅读 »
环信即时通讯SDK自2014年6月正式发布2.0版本至今已走过一个年头,从基本的单聊功能,到群聊功能,再到聊天室的实现,SDK不管是功能,稳定性,还是易集成性都在一步一步的走向完善与稳定,感谢开发者们给与提供的反馈与帮助,使我们的SDK迅速的在诸多方面得到提高与改进。

随着现在物联网的兴起,环信现在的SDK的架构对应对未来物联网平台还是略有不足,使我们不得不在今年年初就考虑到如何去改善我们的架构,使之能够较容易的适配到各个主流平台和物联网平台。

现在的Android, IOS, SDK都是各自维护了自己逻辑,给2.0开发带来了很多不便,相同的功能需要维护两份代码,同一个bug要在不同的平台修复两次,由于不同平台的实现,导致Android,IOS架构设计不统一,API不一致,再加上在不同的平台开发的工程师之间由于不同的实现导致沟通问题诸多,这样导致的问题就是,不同平台的开发进度大多数情况下都不相同。

所以针对以上的问题,我们今年年初就计划我们SDK3.0的开发,我们称之为ONE SDK,基本的理念就是我们实现共同IM 内核,使代码可被不同的平台最大化的重用,但是设计和实现却是面临着巨大的挑战,如何适配到不同的平台,如何最大化的重用代码都是要面临的问题。

ONE SDK 架构设计
总体设计


20150806175739849.png



ONE SDK的设计总体分为3层,平台层-Platfrom layer,适配层-Porting layer,核心层-Common layer.

平台层会根据各平台的不同,实现不同的接口,开放符合平台层的API给第三方开发者。

适配层主要要适配到ONE SDK 核心层所需要的一些接口,起到承上启下的作用。

核心层主要提供IM 功能和业务逻辑,保证最大化的代码重用。

考虑到跨平台共享代码,我们ONE SDK主要是用C++这种跨平台的语言来实现。

平台层

我们计划要支持的平台为Android,IOS,MAC OS,Windows,Windows phone, Linux,Embedded Linux, 还有较为广泛应用的物联网平台-IOT OS。

我们会针对不同平台提供给开发者,和平台一致API规范,使各平台的开发者无难度的集成SDK,例如我们会提供JAVA给Android,Objective-C 给IOS和MAC, C++ 给Linux, IOT平台。


适配层


20150806181806647.png



适配层主要就是各平台需要实现核心层所需要的一些接口类例如,上图给出的线程模型,定时器模型,数据库模型,还有HTTP模型。

这些模型都是和平台相关的,例如有的平台提供sqllite的访问,有的没有,有的线程模型和定时器模型都有自己的实现方式例如物联网IOT OS,所以实现了上述的模型,就可以使核心层可以工作,不过也可能会遇到一些问题,这都会在具体的实现中会具体的应对,但结构是清晰的。

其实例如Android,Linux, IOS, Mac OS,Windows都是支持C++11,也就是说都是支持C++11所提供的线程模型,所以这几个操作系统的线程模型的实现应该是同样的,所以代码是可以共享的, 但是数据库Anroid NDK是不支持sqlite访问,所以这部分Android有两种策略一个是集成sqlite源代码,二是回调给JAVA层,前一种策略是代码逻辑清晰,但坏处就是增加了代码量。

还有就是HTTP模型,默认的android,iOS,Mac OS,windows都有自己的API提供,所以ONE SDK策略就是如果有平台有原生的HTTP API 支持我们就会尽量用平台的,但是类似linux,就需要第三方库的支持例如libcurl.

所以综上所述适配层的意义重大,保证我们ONE SDK代码共享最大化的目的。

核心层

核心层是具体实现环信相关功能的模块,它里面也包含的几个部分,核心业务逻辑API实现,抽象协议层,和独立实时音视频模块。

Core Common


20150806191008517.png



业务逻辑层,负责提供基本的IM功能。

会话管理
消息收发
登录鉴权
连接管理

Audio/Video Call

实时音视频模块是一个独立的模块,可以单独存在,这样可以灵活处理,不需要时不用加载此模块。


20150806191418690.png



实时音视频
多人语音

Abstract Protocol Layer

协议抽象层,主要用来处理具体的IM底层协议,这层是比较独立的主要实现环信定义的IM传输协议,也为为日后协议改造,扩展提供承上启下的作用。


20150806192326297.png



  • 定义抽象消息载体

  • 基本的消息发送

  • 基本的消息回调

  • 定义基本的通知


上述ONE SDK架构是我们计划要实现的,现在一些基本的设计已经在Linux SDK上得到了实现,下面让我们继续了解下Linux SDK。

Linux SDK

经过几个月的开发,我们已经推出了Linux SDK测试版,有兴趣的开发者可以小试一下去我们的官网 http://www.easemob.com/downloads 下载。

通过EMChatClient Facade类开发者可以访问到任何IM停供的功能

  • 登录注册

  • 消息收发,支持TXT, IMAGE, VIDEO, AUDIO, FILE, LOCATION, 类型的message

  • 会话管理

  • 联系人管理



在开发linux SDK的时候我们利用了C++11提供的很多优良feature,例如lambda,shared ptr,thread等较新的功能,通过这些功能的使用,让我们能够迅速并且高效的开发出Linux SDK测试版。

Lambda是我们的代码逻辑阅读起来更清楚,shared ptr使我们对内存的管理更为简单,thread的使用使我们能迅速的建立好线程模型,加快开发的速度。

我们在Linux SDK porting layer实现了线程模型,数据库模型,定时器模型和HTTP模型

  • 线程模型,利用C++11的thread进行封装

  • 数据库模型,使用Linux的sqlite

  • HTTP模型,我们使用了Libcurl进行了封装

  • 定时器模型,我们使用了C++11进行了封装



我们对Linux SDK还在紧锣密鼓,夜以继日的紧张开发中,群组和实时音视频功能还在开发中,但是在开发过程中我们也遇到了些的问题,例如不linux平台对库的支持也不尽相同,所以势必会对我们的架构有些改变,有些重构的工作也在进行中,我们希望8月底能够实现大部分的功能。

选择linux SDK为开始主要是因为大多数的嵌入式智能平台还是以linux为主,所以首先开发Linux 版SDK也是必先的一步,感谢我们的工程师,我么的Linux SDK已经能够支持树莓派的开发环境,这对于很多开发者来说确实是个好消息。

如果想了解如何集成Linux SDK请参考环信IM Linux SDK 集成说明

展望

Linux SDK 只是实现我们ONE SDK 的第一步,我们下半年还要实现基于ONE SDK 的Android ,IOS,MAC OS, 还有主流物联网平台的SDK,通过借鉴Linux SDK的实现方式,我们认为实现ONE SDK是可以做到的。

我们还会进一步和主要IOT平台供应商合作,实现某个具体IOT平台的环信SDK,使环信即时通讯平台生态圈更加壮大。 收起阅读 »

环信Linux SDK测试版正式发布

万物互联时代,物联网创新方兴未艾。今日环信即时通讯云宣布环信Linux SDK测试版正式发布,作为环信生态圈重要的布局,环信Linux SDK测试版使用C++开发,原生支持Linux操作系统,适用于基于Linux系统的智能设备和硬件,在各种智能硬件设备和嵌入式...
继续阅读 »
万物互联时代,物联网创新方兴未艾。今日环信即时通讯云宣布环信Linux SDK测试版正式发布,作为环信生态圈重要的布局,环信Linux SDK测试版使用C++开发,原生支持Linux操作系统,适用于基于Linux系统的智能设备和硬件,在各种智能硬件设备和嵌入式系统上都可以快速移植和接入环信IM的通讯能力,全面对接物联网


165_150805154310_1.jpg



根据环信CEO刘俊彦描述的愿景:未来,当一台物联网时代的电冰箱坏了后,你还需要打开网页搜索厂家联系方式,然后打400电话解决问题吗?当然不!你只需要按冰箱上的一个红色小按钮,就可以立即接通厂家的客服,而且是视频的,客服可以一键将修复后的设置推送到冰箱上来。

不仅如此,客服还能够根据电冰箱存储食品提醒用户是否购买食材,保存和处理食材。如果和其他健康产品联系起来,还能提醒用户是否注意饮食健康等,成为“监测”和“服务”的前端设备。

这并不是很遥远的未来,万物互联正在成为现实。回到物联网冰箱的场景。当消费者按动红色按钮时,在按钮的背后是一个“环信Inside”芯片,烧制了环信的Linux版SDK。当消费者和客服视频通话时,使用的是环信提供的基于IP网络的视频通讯能力,而客服使用的工作后台,则是环信移动客服提供的。

今日,环信的Linux版移动客服SDK已经正式发布。“环信Inside”芯片也已经在实验室中紧张调试,生态圈也正在进一步建立中。环信已经在“连接人与商业”的愿景下又迈出了坚实的一步。


165_150805154519_1_lit.jpg



目前环信Linux SDK测试版版本支持单聊,各种富媒体消息,如文本消息,图片消息,语音/视频片段等,好友管理和黑名单管理等功能,下一个版本将全面支持群组,聊天室和实时音视频,敬请期待! 收起阅读 »

Ubuntu实现树莓派交叉编译

一、交叉编译 在一个平台上生成另一个平台上的可执行代码。为什么要大费周折的进行交叉编译呢?一句话:不得已而为之。有时是因为目的平台上不允许或不能够安装所需要的编译器,而又需要这个编译器的某些特征;有时是因为目的平台上的资源贫乏,无法运行所需要的编译器;有...
继续阅读 »
一、交叉编译

在一个平台上生成另一个平台上的可执行代码。为什么要大费周折的进行交叉编译呢?一句话:不得已而为之。有时是因为目的平台上不允许或不能够安装所需要的编译器,而又需要这个编译器的某些特征;有时是因为目的平台上的资源贫乏,无法运行所需要的编译器;有时又是因为目的平台还没有建立,连操作系统都没有,根本谈不上运行什么编译器。

要进行交叉编译,我们需要在主机平台上安装对应的交叉编译工具链(cross compilation tool chain),然后用这个交叉编译工具链编译源代码,最终生成可在目标平台上运行的代码。     
常见的交叉编译例子如下:
  1. 在Windows PC上,利用ADS(ARM 开发环境),使用armcc编译器,则可编译出针对ARM CPU的可执行代码。
  2. 在Linux PC上,利用arm-linux-gcc编译器,可编译出针对Linux ARM平台的可执行代码。
  3. 在Windows PC上,利用cygwin环境,运行arm-elf-gcc编译器,可编译出针对ARM CPU的可执行代码。

 
二、名词解释
 
Linux下的大多数软件包都使用Autoconf/Automake工具自动生成Makefile,只要使用“./configure”,“make”,“make install”就可以把程序安装到Linux系统中去了。编译第三方源代码时,可以看下工程中的readme和install文件,一般情况下都会写编译步骤。
 
 1、./configure 常用参数  [--build] | [--host] | [--target] | [--prefix] | [--help]

注意:host和--host不是一个意思,host是指宿主机,即编辑和编译程序的平台,是个名词;--host是设置执行文件所运行的主机,是个动词。
 
>> ./configure: 用来生成对应的 Makefile;
 
>> --build: 执行代码编译的主机,正常的话就是你的主机系统。若无指定使用host的值;
>> --host: 编译出来的二进制程序所执行的主机, 交叉编译工具链的前缀。因为绝大多数是如果本机编译就本机执行,所以这个值就等于build。但是交叉编译的时候build和host需要设置不同值,用host指定运行主机,即host != build的时候编译才是交叉编译。若无指定将会运行`config.guess'来检测;
 
>> --prefix: 安装目录,比如 --prefix=/usr 意思是将该软件安装在 /usr 下面,执行文件就会安装在 /usr/bin (而不是默认的 /usr/local/bin),资源文件就会安装在 /usr/share(而不是默认的/usr/local/share);
 
>> --help: 查看参数;
 
>> --target: 这个参数比较特殊,表示需要处理的目标平台名称,主要在程序语言工具如编译器和汇编器上下文中起作用,若无指定使用host的值。一般用来编译工具,比如给arm开发板编译一个可以处理mips程序的gcc,那么--target=mips;
 
>>>> 举例说明:编译gcc
 
>> ./configure --build=i386-linux --host=arm-linux --target=mipsel-linux --prefix=$(pwd)/_install
 
用i386-linux的编译器进行gcc的编译,编译出的gcc运行在arm-linux, 编译结果存放到$(pwd)/_install路径下,编译出的gcc用来编译能够在mipsel-linux下运行的代码。
 
2、Makefile包含了一些基本的预先定义的操作: 

  • >>make: 根据Makefile编译源代码,连接,生成目标文件,可执行文件;

  • >>make clean: 清除上次的make命令所产生的object文件(后缀为“.o”的文件)及可执行文件;

  • >>make distclean: 类似make clean,但同时也将configure生成的文件全部删除掉,包括Makefile;

  • >>make test / make check: 检查make,确保make没有出错,一般在make install之前执行;

  • >>make install: 将编译成功的可执行文件安装到指定目录中,一般为/usr/local/bin目录;

  • >>make dist: 产生发布软件包文件(即distribution package)。这个命令将会将可执行文件及相关文件打包成一个tar.gz压缩的文件用来作为发布软件的软件包。它会在当前目录下生成一个名字类似“PACKAGE-VERSION.tar.gz”的文件。PACKAGE和VERSION,是我们在configure.in中定义的AM_INIT_AUTOMAKE(PACKAGE, VERSION);

  • >>make distcheck: 生成发布软件包并对其进行测试检查,以确定发布包的正确性。这个操作将自动把压缩包文件解开,然后执行configure命令,并且执行make,来确认编译不出现错误,最后提示你软件包已经准备好,可以发布了; 



三、交叉编译源代码

1、环境
Ubuntu
 
2、树莓派交叉编译工具安装step
 

  • step1.下载树莓派交叉编译工具https://github.com/raspberrypi/tools

  • step2. 将源码放到各用户都能share的文件夹下,如/usr/tools

  • step3. 将交叉编译工具的路径加到环境变量中,为了以后启动不用再设置,我加到了bashrc中


1 $nano ~/.bashrc
2 #在文件的末尾加上: export PATH=$PATH:/usr/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin
3 $source .bashrc


  • step4. 检测是否安装成功


way1: 
$arm #双tab
显示以下内容


031616177676048.jpg

 
way2:
$arm-linux-gnueabihf-gcc -v 
#能显示正确信息

$arm-linux-gnueabihf-g++ -v
#能显示正确信息
注意:交叉编译时,如果出现arm-linux-gnueabihf-XXX找不到,确定arm-linux-gnueabihf-XXX -v 是否能输出正确信息,如果能,可以切到root下进行编译

三、编译源代码

1、在写编译脚本时,一定要确保编译器写的是交叉编译的编译器。比如比较常用的Makefile,
1 demo: $(obj)
2 $(CXX) -o $@ $^ $(LDFLAGS)
其中的CXX必须是arm-linux-gnueabihf-g++才能编译出正确的在树莓派上的可执行文件。

2、编译第三方库

如果你想设置全局的CC和CXX变量,在每次打开一个新的Terminal时,输入以下命令:
1 $export CC=arm-linux-gnueabihf-gcc  
2 $export CXX=arm-linux-gnueabihf-g++
其他的全局变量同上。

以下列几个常用的第三方库交叉编译步骤

1>> sqlite3 http://www.sqlite.org/download.html sqlite-autoconf-3081002.tar.gz

  • step1:  make clean

  • step2:  ./configure --host=arm-linux-gnueabihf --prefix=/usr/local/tools/sqlite3

  • step3:  make

  • step4:  make install



 

2>>curl http://curl.haxx.se/download.html  curl-7.43.0.tar.gz

  • step1:  make clean

  • step2:  ./configure --host=arm-linux-gnueabihf --prefix=/usr/local/tools/curl

  • step3:  make

  • step4:  make install



3>> openssl: http://www.openssl.org/source/ openssl-1.0.1p.tar.gz

  • step1: ./config no-asm shared --prefix=/usr/local/tools/openssl

  • step2:  a、修改Makefile CC=arm-linux-gnueabihf-gcc


           b、找到有-m64的地方,将-m64删除。  

  • step3: make

  • step4: make install


收起阅读 »

经验分享:PHP 安全编程建议

要提供互联网服务,当你在开发代码的时候必须时刻保持安全意识。可能大部分 PHP 脚本都对安全问题都不在意,这很大程度上是因为有大量的无经验程序员在使用这门语言。但是,没有理由让你因为对你的代码的不确定性而导致不一致的安全策略。当你在服务器上放任何涉及到钱的东西...
继续阅读 »
要提供互联网服务,当你在开发代码的时候必须时刻保持安全意识。可能大部分 PHP 脚本都对安全问题都不在意,这很大程度上是因为有大量的无经验程序员在使用这门语言。但是,没有理由让你因为对你的代码的不确定性而导致不一致的安全策略。当你在服务器上放任何涉及到钱的东西时,就有可能会有人尝试破解它。创建一个论坛程序或者任何形式的购物车,被攻击的可能性就上升到了无穷大。
为了确保你的 web 内容安全,这里有一些常规的安全准则:
  • 别相信表单
攻击表单很简单。通过使用一个简单的 JavaScript 技巧,你可以限制你的表单只允许在评分域中填写 1 到 5 的数字。如果有人关闭了他们浏览器的 JavaScript 功能或者提交自定义的表单数据,你客户端的验证就失败了。用户主要通过表单参数和你的脚本交互,因此他们是最大的安全风险。你应该学到什么呢?在 PHP 脚本中,总是要验证 传递给任何 PHP 脚本的数据。在本文中,我们向你演示了如何分析和防范跨站脚本(XSS)攻击,它可能会劫持用户凭据(甚至更严重)。你也会看到如何防止会玷污或毁坏你数据的 MySQL 注入攻击。
  • 别相信用户
假定你网站获取的每一份数据都充满了有害的代码。清理每一部分,即便你相信没有人会尝试攻击你的站点。
  • 关闭全局变量
你可能会有的最大安全漏洞是启用了 register_globals 配置参数。幸运的是,PHP 4.2 及以后版本默认关闭了这个配置。如果打开了 register_globals,你可以在你的 php.ini 文件中通过改变 register_globals 变量为 Off 关闭该功能:
register_globals = Off 
新手程序员觉得注册全局变量很方便,但他们不会意识到这个设置有多么危险。一个启用了全局变量的服务器会自动为全局变量赋任何形式的参数。为了了解它如何工作以及为什么有危险,让我们来看一个例子。假设你有一个称为 process.php 的脚本,它会向你的数据库插入表单数据。初始的表单像下面这样:
运行 process.php 的时候,启用了注册全局变量的 PHP 会将该参数赋值到 $username 变量。这会比通过 $_POST['username']或 $_GET['username'] 访问它节省击键次数。不幸的是,这也会给你留下安全问题,因为 PHP 会设置该变量的值为通过 GET 或 POST 的参数发送到脚本的任何值,如果你没有显示地初始化该变量并且你不希望任何人去操作它,这就会有一个大问题。看下面的脚本,假如 $authorized 变量的值为 true,它会给用户显示通过验证的数据。正常情况下,只有当用户正确通过了这个假想的 authenticated_user() 函数验证,$authorized 变量的值才会被设置为真。但是如果你启用了 register_globals,任何人都可以发送一个 GET 参数,例如 authorized=1 去覆盖它:
这个故事的寓意是,你应该从预定义的服务器变量中获取表单数据。所有通过 post 表单传递到你 web 页面的数据都会自动保存到一个称为 $_POST 的大数组中,所有的 GET 数据都保存在 $_GET 大数组中。文件上传信息保存在一个称为 $_FILES 的特殊数据中。另外,还有一个称为 $_REQUEST 的复合变量。要从一个 POST 方法表单中访问 username 字段,可以使用 $_POST['username']。如果 username 在 URL 中就使用$_GET['username']。如果你不确定值来自哪里,用 $_REQUEST['username']。
['post_value'];$get_value = $_GET['get_value'];$some_variable = $_REQUEST['some_value']; ?>  
$_REQUEST 是 $_GET、$_POST、和 $_COOKIE 数组的结合。如果你有两个或多个值有相同的参数名称,注意 PHP 会使用哪个。默认的顺序是 cookie、POST、然后是 GET。 推荐安全配置选项 这里有几个会影响安全功能的 PHP 配置设置。下面是一些显然应该用于生产服务器的:
  • register_globals 设置为 off
  • safe_mode 设置为 off
  • error_reporting 设置为 off。如果出现错误了,这会向用户浏览器发送可见的错误报告信息。对于生产服务器,使用错误日志代替。开发服务器如果在防火墙后面就可以启用错误日志。(LCTT 译注:此处据原文逻辑和常识,应该是“开发服务器如果在防火墙后面就可以启用错误报告,即 on。”)
  • 停用这些函数:system()、exec()、passthru()、shell_exec()、proc_open()、和 popen()。
  • open_basedir 为 /tmp(以便保存会话信息)目录和 web 根目录,以便脚本不能访问这些选定区域外的文件。
  • expose_php 设置为 off。该功能会向 Apache 头添加包含版本号的 PHP 签名。
  • allow_url_fopen 设置为 off。如果你能够注意你代码中访问文件的方式-也就是你验证所有输入参数,这并不严格需要。
  • allow_url_include 设置为 off。对于任何人来说,实在没有明智的理由会想要访问通过 HTTP 包含的文件。
  •  
  • 一般来说,如果你发现想要使用这些功能的代码,你就不应该相信它。尤其要小心会使用类似 system() 函数的代码-它几乎肯定有缺陷。
  • 启用了这些设置后,让我们来看看一些特定的攻击以及能帮助你保护你服务器的方法。
 SQL 注入攻击 由于 PHP 传递到 MySQL 数据库的查询语句是用强大的 SQL 编程语言编写的,就有了某些人通过在 web 查询参数中使用 MySQL 语句尝试 SQL 注入攻击的风险。通过在参数中插入有害的 SQL 代码片段,攻击者会尝试进入(或破坏)你的服务器。假如说你有一个最终会放入变量 $product 的表单参数,你使用了类似下面的 SQL 语句:
$sql = "select * from pinfo where product = '$product'";
如果参数是直接从表单中获得的,应该使用 PHP 自带的数据库特定转义函数,类似:
$sql = 'Select * from pinfo where product = '"'        mysql_real_escape_string($product) . '"';
如果不这样做的话,有人也许会把下面的代码段放到表单参数中:
39'; DROP pinfo; SELECT 'FOO 
那么 $sql 的结果就是:
select product from pinfo where product = '39'; DROP pinfo; SELECT 'FOO' 
由于分号是 MySQL 的语句分隔符,数据库会运行下面三条语句:
select * from pinfo where product = '39'DROP pinfoSELECT 'FOO' 
好了,你丢失了你的表。注意实际上 PHP 和 MySQL 不会运行这种特殊语法,因为 mysql_query() 函数只允许每个请求处理一个语句。但是,一个子查询仍然会生效。要防止 SQL 注入攻击,做这两件事:
  • 总是验证所有参数。例如,如果需要一个数字,就要确保它是一个数字。
  • 总是对数据使用 mysql_real_escape_string() 函数转义数据中的任何引号和双引号。
注意:要自动转义任何表单数据,可以启用魔术引号(Magic Quotes)。一些 MySQL 破坏可以通过限制 MySQL 用户权限避免。任何 MySQL 账户可以限制为只允许对选定的表进行特定类型的查询。例如,你可以创建只能选择行的 MySQL 用户。但是,这对于动态数据并不十分有用,另外,如果你有敏感的用户信息,可能某些人能访问其中一些数据,但你并不希望如此。例如,一个访问账户数据的用户可能会尝试注入访问另一个人的账户号码的代码,而不是为当前会话指定的号码。 防止基本的 XSS 攻击 XSS 表示跨站脚本。不像大部分攻击,该漏洞发生在客户端。XSS 最常见的基本形式是在用户提交的内容中放入 JavaScript 以便偷取用户 cookie 中的数据。由于大部分站点使用 cookie 和 session 验证访客,偷取的数据可用于模拟该用户-如果是一个常见的用户账户就会深受麻烦,如果是管理员账户甚至是彻底的惨败。如果你不在站点中使用 cookie 和 session ID,你的用户就不容易被攻击,但你仍然应该明白这种攻击是如何工作的。不像 MySQL 注入攻击,XSS 攻击很难预防。Yahoo、eBay、Apple、以及 Microsoft 都曾经受 XSS 影响。尽管攻击不包含 PHP,但你可以使用 PHP 来剥离用户数据以防止攻击。为了防止 XSS 攻击,你应该限制和过滤用户提交给你站点的数据。正是因为这个原因,大部分在线公告板都不允许在提交的数据中使用 HTML 标签,而是用自定义的标签格式代替,例如   和 [linkto]。让我们来看一个如何防止这类攻击的简单脚本。对于更完善的解决办法,可以使用 SafeHTML,本文的后面部分会讨论到。
function transform_HTML($string, $length = null) {// Helps prevent XSS attacks    // Remove dead space.    $string = trim($string);    // Prevent potential Unicode codec problems.    $string = utf8_decode($string);    // HTMLize HTML-specific characters.    $string = htmlentities($string, ENT_NOQUOTES);    $string = str_replace("#", "#", $string);    $string = str_replace("%", "%", $string);    $length = intval($length);    if ($length > 0) {        $string = substr($string, 0, $length);    }    return $string;} 
这个函数将 HTML 特定的字符转换为 HTML 字面字符。一个浏览器对任何通过这个脚本的 HTML 以非标记的文本呈现。例如,考虑下面的 HTML 字符串:
Bold Text
一般情况下,HTML 会显示为:Bold Text但是,通过 transform_HTML() 后,它就像原始输入一样呈现。原因是处理的字符串中的标签字符串转换为 HTML 实体。transform_HTML() 的结果字符串的纯文本看起来像下面这样:
Bold Text 
该函数的实质是 htmlentities() 函数调用,它会将 <、>、和 & 转换为 <、>、和 &。尽管这会处理大部分的普通攻击,但有经验的 XSS 攻击者有另一种把戏:用十六进制或 UTF-8 编码恶意脚本,而不是采用普通的 ASCII 文本,从而希望能绕过你的过滤器。他们可以在 URL 的 GET 变量中发送代码,告诉浏览器,“这是十六进制代码,你能帮我运行吗?” 一个十六进制例子看起来像这样:
 
浏览器渲染这个信息的时候,结果就是:
 
为了防止这种情况,transform_HTML() 采用额外的步骤把 # 和 % 符号转换为它们的实体,从而避免十六进制攻击,并转换 UTF-8 编码的数据。最后,为了防止某些人用很长的输入超载字符串从而导致某些东西崩溃,你可以添加一个可选的 $length 参数来截取你指定最大长度的字符串。 [b]使用 SafeHTML
 之前脚本的问题比较简单,它不允许任何类型的用户标记。不幸的是,这里有上百种方法能使 JavaScript 跳过用户的过滤器,并且要从用户输入中剥离全部 HTML,还没有方法可以防止这种情况。当前,没有任何一个脚本能保证无法被破解,尽管有一些确实比大部分要好。有白名单和黑名单两种方法加固安全,白名单比较简单而且更加有效。一个白名单解决方案是 PixelApes 的 SafeHTML 反跨站脚本解析器。SafeHTML 能识别有效 HTML,能追踪并剥离任何危险标签。它用另一个称为 HTMLSax 的软件包进行解析。按照下面步骤安装和使用 SafeHTML:
  • 到 http://pixel-apes.com/safehtml/?page=safehtml 下载最新版本的 SafeHTML。
  • 把文件放到你服务器的类文件夹。该文件夹包括 SafeHTML 和 HTMLSax 功能所需的所有东西。
  • 在脚本中 include SafeHTML 类文件(safehtml.php)。
  • 创建一个名为 $safehtml 的新 SafeHTML 对象。
  • 用 $safehtml->parse() 方法清理你的数据。
这是一个完整的例子:
alert('XSS Attack')";// Create a safehtml object.$safehtml = new safehtml();// Parse and sanitize the data.$safe_data = $safehtml->parse($data);// Display result.echo 'The sanitized data is 
' . $safe_data;?>
如果你想清理脚本中的任何其它数据,你不需要创建一个新的对象;在你的整个脚本中只需要使用 $safehtml->parse() 方法。 什么可能会出现问题? 你可能犯的最大错误是假设这个类能完全避免 XSS 攻击。SafeHTML 是一个相当复杂的脚本,几乎能检查所有事情,但没有什么是能保证的。你仍然需要对你的站点做参数验证。例如,该类不能检查给定变量的长度以确保能适应数据库的字段。它也不检查缓冲溢出问题。XSS 攻击者很有创造力,他们使用各种各样的方法来尝试达到他们的目标。可以阅读 RSnake 的 XSS 教程http://ha.ckers.org/xss.html ,看一下这里有多少种方法尝试使代码跳过过滤器。SafeHTML 项目有很好的程序员一直在尝试阻止 XSS 攻击,但无法保证某些人不会想起一些奇怪和新奇的方法来跳过过滤器。注意:XSS 攻击严重影响的一个例子 http://namb.la/popular/tech.html,其中显示了如何一步一步创建一个让 MySpace 服务器过载的 JavaScript XSS 蠕虫。 用单向哈希保护数据 该脚本对输入的数据进行单向转换,换句话说,它能对某人的密码产生哈希签名,但不能解码获得原始密码。为什么你希望这样呢?应用程序会存储密码。一个管理员不需要知道用户的密码,事实上,只有用户知道他/她自己的密码是个好主意。系统(也仅有系统)应该能识别一个正确的密码;这是 Unix 多年来的密码安全模型。单向密码安全按照下面的方式工作:
  • 当一个用户或管理员创建或更改一个账户密码时,系统对密码进行哈希并保存结果。主机系统会丢弃明文密码。
  • 当用户通过任何方式登录到系统时,再次对输入的密码进行哈希。
  • 主机系统丢弃输入的明文密码。
  • 当前新哈希的密码和之前保存的哈希相比较。
  • 如果哈希的密码相匹配,系统就会授予访问权限。
主机系统完成这些并不需要知道原始密码;事实上,原始密码完全无所谓。一个副作用是,如果某人侵入系统并盗取了密码数据库,入侵者会获得很多哈希后的密码,但无法把它们反向转换为原始密码。当然,给足够时间、计算能力,以及弱用户密码,一个攻击者还是有可能采用字典攻击找出密码。因此,别轻易让人碰你的密码数据库,如果确实有人这样做了,让每个用户更改他们的密码。 加密 Vs 哈希 技术上来来说,哈希过程并不是加密。哈希和加密是不同的,这有两个理由:不像加密,哈希数据不能被解密。是有可能(但非常罕见)两个不同的字符串会产生相同的哈希。并不能保证哈希是唯一的,因此别像数据库中的唯一键那样使用哈希。
function hash_ish($string) {    return md5($string);}
上面的 md5() 函数基于 RSA 数据安全公司的消息摘要算法(即 MD5)返回一个由 32 个字符组成的十六进制串。然后你可以将那个 32 位字符串插入到数据库中和另一个 md5 字符串相比较,或者直接用这 32 个字符。 破解脚本 几乎不可能解密 MD5 数据。或者说很难。但是,你仍然需要好的密码,因为用一整个字典生成哈希数据库仍然很简单。有一些在线 MD5 字典,当你输入 06d80eb0c50b49a509b49f2424e8c805 后会得到结果 “dog”。因此,尽管技术上 MD5 不能被解密,这里仍然有漏洞,如果某人获得了你的密码数据库,你可以肯定他们肯定会使用 MD5 字典破译。因此,当你创建基于密码的系统的时候尤其要注意密码长度(最小 6 个字符,8 个或许会更好)和包括字母和数字。并确保这个密码不在字典中。 用 Mcrypt 加密数据 如果你不需要以可阅读形式查看密码,采用 MD5 就足够了。不幸的是,这里并不总是有可选项,如果你提供以加密形式存储某人的信用卡信息,你可能需要在后面的某个地方进行解密。最早的一个解决方案是 Mcrypt 模块,这是一个用于允许 PHP 高速加密的插件。Mcrypt 库提供了超过 30 种用于加密的计算方法,并且提供口令确保只有你(或者你的用户)可以解密数据。让我们来看看使用方法。下面的脚本包含了使用 Mcrypt 加密和解密数据的函数:
mcrypt() 函数需要几个信息:
  • 需要加密的数据
  • 用于加密和解锁数据的口令,也称为键。
  • 用于加密数据的计算方法,也就是用于加密数据的算法。该脚本使用了 MCRYPT_SERPENT_256,但你可以从很多算法中选择,包括 MCRYPT_TWOFISH192、MCRYPT_RC2、MCRYPT_DES、和 MCRYPT_LOKI97。
  • 加密数据的模式。这里有几个你可以使用的模式,包括电子密码本(Electronic Codebook) 和加密反馈(Cipher Feedback)。该脚本使用 MCRYPT_MODE_CBC 密码块链接。
  • 一个 初始化向量-也称为 IV 或者种子,用于为加密算法设置种子的额外二进制位。也就是使算法更难于破解的额外信息。
  • 键和 IV 字符串的长度,这可能随着加密和块而不同。使用 mcrypt_get_key_size() 和 mcrypt_get_block_size() 函数获取合适的长度;然后用 substr() 函数将键的值截取为合适的长度。(如果键的长度比要求的短,别担心,Mcrypt 会用 0 填充。)
如果有人窃取了你的数据和短语,他们只能一个个尝试加密算法直到找到正确的那一个。因此,在使用它之前我们通过对键使用md5() 函数增加安全,就算他们获取了数据和短语,入侵者也不能获得想要的东西。入侵者同时需要函数,数据和口令,如果真是如此,他们可能获得了对你服务器的完整访问,你只能大清洗了。这里还有一个数据存储格式的小问题。Mcrypt 以难懂的二进制形式返回加密后的数据,这使得当你将其存储到 MySQL 字段的时候可能出现可怕错误。因此,我们使用 base64encode() 和 base64decode() 函数转换为和 SQL 兼容的字母格式和可检索行。 破解脚本 除了实验多种加密方法,你还可以在脚本中添加一些便利。例如,不用每次都提供键和模式,而是在包含的文件中声明为全局常量。 生成随机密码 随机(但难以猜测)字符串在用户安全中很重要。例如,如果某人丢失了密码并且你使用 MD5 哈希,你不可能,也不希望查找回来。而是应该生成一个安全的随机密码并发送给用户。为了访问你站点的服务,另外一个用于生成随机数字的应用程序会创建有效链接。下面是创建密码的一个函数:
 0) &&        (! is_null($num_chars))) {        $password = '';        $accepted_chars = 'abcdefghijklmnopqrstuvwxyz1234567890';        // Seed the generator if necessary.        srand(((int)((double)microtime()*1000003)) );        for ($i=0; $i<=$num_chars; $i++) {            $random_number = rand(0, (strlen($accepted_chars) -1));            $password .= $accepted_chars[$random_number] ;        }        return $password;     }}?> 
使用脚本 make_password() 函数返回一个字符串,因此你需要做的就是提供字符串的长度作为参数:
 
函数按照下面步骤工作:
  • 函数确保 $num_chars 是非零的正整数。
  • 函数初始化 $accepted_chars 变量为密码可能包含的字符列表。该脚本使用所有小写字母和数字 0 到 9,但你可以使用你喜欢的任何字符集合。(LCTT 译注:有时候为了便于肉眼识别,你可以将其中的 0 和 O,1 和 l 之类的都去掉。)
  • 随机数生成器需要一个种子,从而获得一系列类随机值(PHP 4.2 及之后版本中并不需要,会自动播种)。
  • 函数循环 $num_chars 次,每次迭代生成密码中的一个字符。
  • 对于每个新字符,脚本查看 $accepted_chars 的长度,选择 0 和长度之间的一个数字,然后添加 $accepted_chars中该数字为索引值的字符到 $password。
  • 循环结束后,函数返回 $password。

作者:SamarRizvi 译者:ictlyh来源:http://www.codeproject.com/Articles/363897/PHP-Security
收起阅读 »

开发经验:如何优雅的进行页面间的跳转

在你的开发过程中,是否遇到过如下的需求: 在tableView类型的展示列表中,点击每个cell中人物头像都可以跳转到人物详情,可参见微博中的头像,同理包括转发、评论按钮、各种链接及linkcard。跳转到任意页面 产品要求,某个页面的不同banner图,点击...
继续阅读 »
在你的开发过程中,是否遇到过如下的需求:
  1. 在tableView类型的展示列表中,点击每个cell中人物头像都可以跳转到人物详情,可参见微博中的头像,同理包括转发、评论按钮、各种链接及linkcard。
  2. 跳转到任意页面

  • 产品要求,某个页面的不同banner图,点击可以跳转到任何一个页面,可能是原生的页面A、页面B,或者是web页C。
  • 在web页面,可以跳转到任何一个原生页面。
  • 在远程推送中跳转到任意指定的页面。
以上2种需求,我想大多数开发者都遇到过,并且可以实现这种功能。毕竟,这是比较基础的功能。但是代码未必那么优雅。一般处理办法针对1.,一般初学者会用target或者block等方法在tableView的代理方法拿到事件,并把要执行的跳转写到controller里。功能是可以实现的,但问题是这种cell及相似的cell(布局有些变化,或者多几个少几个控件)一般出现在多个页面。这样的话相同的代码就会出现在多个地方。就算把跳转方法抽取出来写成category,但是target或者block总是每个地方都要写的。针对2.,初级的方法是每个地方写一坨判断及跳转,高级一些是抽取出来写在基类或者category。优雅的解决办法纵观上面各种情况,总结起来就是一句话,在任意的地方触发事件(可以是推送,拦截的js跳转,各种控件的点击事件)可以跳转到任意界面。所以我们可以统一用一个控制跳转的manager来完成跳转。
  • 与后端约定好数据结构,例如:
NSDictionary *target = @{@"action" : @"user",                         @"data"   : @{@"user_id" : @(123456)}};
就是跳转到id为123456的用户页面,如果跳转需要更多的数据,可以在data的value里面继续添加。
  • 创建一个用来跳转的类,可以起的牛x的名字,XXCoreActionManager。
创建一个类方法:
+ (BOOL)doActionForTarget:(NSDictionary *)target{    //根据你的app结构,来取得你当前的controller,由它来进行跳转    UIApplication *application = [UIApplication sharedApplication];    AppDelegate *myAppDelegate = (AppDelegate *)[application delegate];    UIViewController *viewController;    if ([myAppDelegate getTabbarSelectedView]) {        viewController = [myAppDelegate getTabbarSelectedView].visibleViewController;    }else {        return NO;    }    if([json[@"action"] isEqualToString:@"film_view"]){        MFMaterialListViewController *materialListVC = [[MFMaterialListViewController alloc] initWithNibName:@"MFMaterialListViewController" bundle:nil];        materialListVC.hidesBottomBarWhenPushed = YES;        materialListVC.filmId = json[@"data"][@"film_id"];        [viewController.navigationController pushViewController:materialListVC animated:YES];        return YES;    }else if([json[@"action"] isEqualToString:@"home"]){        [myAppDelegate getTabbar].selectedIndex = 0;        [viewController.navigationController popToRootViewControllerAnimated:YES];        return YES;    }    return NO;}
在刚才定义的数据结构中,action的值为需要跳转的页面,data的值跳转所需要要的参数,比如id、type等。服务器只需要传入相应的数据就可以用
[XXCoreActionManager doActionForTarget:target];
  • 针对头像、评论、转发等多处使用的子控件,可以把事件由自己接收,通过XXCoreActionManager来进行跳转。即做到了代码分离,使之成为真正独立的控件,便于复用。
下面是一个简单例子:
implementation MFUserHeadButton-(void)awakeFromNib{    [self addTarget:self action:@selector(toUserDetail) forControlEvents:UIControlEventTouchUpInside];}- (void)toUserDetail{    NSDictionary *target = @{@"action":@"user",                           @"data":@{@"user_id":@(self.tag)}};    [XXCoreActionManager doActionForTarget:target];}
这就是一个简单的实现跳转到个人页功能的头像控件实现。如果你问user_id的值怎么来的?当然是configCell的时候传给view的tag的。你可能会说,我的跳转需要多个参数啊,你一个tag不够用啊亲。可以定义一个NSDictionary属性接收啊。如果你用原生的UI控件,那让强大的runtime给你加喽
- (void)setDict:(NSDictionary *)dict {        objc_setAssociatedObject(self, dictKey, dict, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}- (NSDictionary *)dict {        return objc_getAssociatedObject(self, dictKey);}
总结[list=1]
  • 通过XXCoreActionManager,你可以做到无论你身在何处(哪一个controller),要到何处去(跳转到哪一个controller),你只需要叫来XXCoreActionManager,告诉它你的目的地(target)。你就可以做到想跳就跳。真正的write once,use anywhere。
  • 针对各种有跳转功能的控件,可以做到真的解耦。只需要把它放到他需要显示的位置。告诉它对应的参数就可以了。方便复用和后期的维护。
  • 这次想说的只是一个思路,代码很简单。其实可以使用的地方还有很多。不只是跳转各位童鞋可以自己思考。有什么不明白的可以留言,如果觉得那里不合适更欢迎留言指教或交流。


  • 写在后面的废话

    从读大学接触到计算机技术这一领域,我就被这个圈子的氛围深深的触动了,这是一个如此自由、分享、开放的圈子。我从无数人的的分享中汲取着知识(开源的代码,分享的博客),我受益于这种环境,我就想对它做出回馈,写出这篇文章,即希望能帮助一些人,也希望能与大家有更多的交流。最后,谢谢那些无私的做出各种奉献的人。
     
    来源:csdn 收起阅读 »

    环信移动客服“智能知识库+智能机器人”技术开启3.0时代

    7月28日,环信B轮融资及移动客服新品发布会在北京JW万豪酒店举行。发布会上,环信CEO刘俊彦宣布环信成功获得B轮融资1250万美元。同时环信CTO马晓宇宣布环信移动客服3.0产品也正式上线,而环信移动客服凭借IM长连接垄断技术结合“智能知识库+智能机器人” ...
    继续阅读 »
    7月28日,环信B轮融资及移动客服新品发布会在北京JW万豪酒店举行。发布会上,环信CEO刘俊彦宣布环信成功获得B轮融资1250万美元。同时环信CTO马晓宇宣布环信移动客服3.0产品也正式上线,而环信移动客服凭借IM长连接垄断技术结合“智能知识库+智能机器人” 组合技术将开启移动客服3.0新时代。


    1.png



    环信CTO马晓宇现场解读环信移动客服3.0

    传统的客服行业是一个劳动密集型企业,因为人力成本的不断提高,导致传统呼叫中心已经从北上广转移到大连、成都等地,未来甚至将要迁往新疆、西藏、青海等人力成本更低的地方。环信CEO马晓宇表示环信希望通过技术来解决人力成本不断升高的问题,所以环信适时推出了智能的移动客服系统。


    2.png



    智能的两个要素
    • 一个是智能知识库;
    • 一个智能机器人。

    智能知识库环信移动客服3.0版本会内置几个标准的行业知识库,基于人工智能深度挖掘技术,比较容易维护这个知识库,大家如果用得越多,知识库会更敏感,更能够快速回答问题。如果有一个用户说我要重置密码,智能知识库系统自动在客服工作端显示出重置密码的流程,客服就可以根据标准流程走下来。还有一个智能机器人技术,环信移动客服将智能机器人技术和知识库结合,能够解决回答80%的常见问题,剩下的20%才需要人工来解决

    另外,环信在移动客服里开始逐渐部署了大数据技术,环信会提供15个新的数据统计报表,从最简单的客服当前工作状态,客服每天工作量,客服会话小结等。在这基础上提供渠道统计报表,就可以知道你的客服用户需求,比如是来自微信还是移动APP还是网页,做一些渠道分析。另外我们还提供用户满意度报表,这样不光能提高整个用户满意度,同时我们希望这个产品是能帮助APP运营者,开发者能快速迭代,能真正尽快改进产品,不断满足客户需求。帮助客户将客服系统从成本中心向营销中心和盈利中心转换

    最后马晓宇表示环信移动客服是一个开放平台,整个内部是平台插件化可扩展化体系,通过插件形式打造可扩展的平台,希望基于这个满足SaaS服务成千上万客户不同需求,可以进行二次开发。同时在这个基础上环信还有一个生态圈部署。现在环信有几个合作伙伴,私有云部署有两家私有云授权认证集成商,移动客服领域有两家做增值服务的授权认证集成商,我们希望环信能继续发展下去,发展过程中和合作伙伴一起把市场做好,让我们的合作伙伴也的确能挣到钱。

    据悉,环信移动客服典型用户包括国美在线、58到家、楚楚街9块9等上百家互联网巨头企业客户,累计签约客服座席已经达4万个。根据艾媒咨询现场发布的《2015年中国移动客服市场发展研究报告》显示环信在新兴的移动客服市场占有率第一,APP客户规模最大。不难预料,有着连接“人与商业”愿景的环信凭借惊人的成长速度将最有希望成为下一个“独角兽”。 收起阅读 »

    环信移动客服3.0上线签约国美在线、58到家、楚楚街9块9等龙头企业

    7月28日,环信B轮融资及移动客服新品发布会在北京JW万豪酒店举行。发布会上,环信CEO刘俊彦宣布,环信成功获得B轮融资,同时环信移动客服3.0产品也正式上线,而环信将以“连接人与商业”为愿景,开启万亿级企业云服务市场。 据悉,环信移动客服产品已...
    继续阅读 »
    7月28日,环信B轮融资及移动客服新品发布会在北京JW万豪酒店举行。发布会上,环信CEO刘俊彦宣布,环信成功获得B轮融资,同时环信移动客服3.0产品也正式上线,而环信将以“连接人与商业”为愿景,开启万亿级企业云服务市场。


    5.png



    据悉,环信移动客服产品已经有国美在线、58到家、楚楚街等大批龙头企业签约,累计签约客服座席已经达4万个,而按艾媒咨询的报告显示,环信已占据市场份额第一的宝座

    发布会现场,据启动环信移动客服3.0产品上线的环信CTO马晓宇介绍,环信之所以受到市场如此欢迎,是因为环信移动客服是有别于传统客服的划时代产品。在环信CTO马晓宇看来,客服经历了三个时代——
    1. 传统 call center的时代: 互联网尚未普及,电话客服客户等待时间长,客户服务人员压力大,工作重复内容多;
    2. 到了PC网页客服时代,随着互联网的普及,网页客服的成本明显小于电话客服,客户服务人员工作量较小,客户满意度有所提高,但相应依然不能及时有效;
    3. 当今,随着智能手机用户的快速增长,客户要求能够随时在移动端获取咨询服务。移动端客服的重要性将不断上升。移动客服时代随之到来。



    9.png


    然而在环信基于IM长连接技术推出移动客服之前,业界并没有一款真正适合移动端和社交化时代的可靠的云端移动客服产品。此前,业界普遍存在的是两种移动客服产品
    1. 一类是工单客服,可以被视为移动客服1.0,基于工单方式和客服交互,技术实现简单,但无法做到实时交互,沟通效率低,用户体验差。
    2. 另一类是轮询技术客服,可以被视为移动客服2.0,基于HTTP轮询技术,通过不断向服务器发送查询请求来准实时的收取消息。不能做到实时收取消息,流量和电量消耗高,APP在后台时无法接收消息,容易丢失客户。

    而环信推出的移动客服产品是业界唯一一款具有IM长连接技术的移动客服产品,这被视为更适合移动端的客服产品。

    这一类型的移动客服可以定义为“交互型智能移动客服”,可以被视为移动客服3.0,以环信为代表的这一类新型移动客服是基于亿级IM长连接,系统稳定;智能机器人技术可处理大部分重复问题。相较环信移动客服的能力,传统的电话、工单、轮询客服在移动端和社交趋势下就显得捉襟见肘,有些OUT了。
     
    • 环信移动客服实现了跨平台多渠道接入:支持 App、微信公众账号、微博、网页等,均可以快速统一接入客户服务后台管理。

    8.png

    • 其次,满足了开放性与自定义信息:这种新型的移动客服实现了代码开源、UI开源,还提供多套UI模版,便于与APP快速集成,平滑接入。同时第三方集成功能也很强大,可与第三方工单、知识库、CRM 系统等进行扩展集成。
    • 第三,富媒体消息交互体验:移动客服平台提供了基于IM技术的类似微信体验的友好富媒体消息交互,不仅可以实时收发文字、表情,还可以即时收发图片、位置、实时语音、还可自定义消息,大大方便了与客户的沟通交流。
    • 第四,精准客户画像功能:移动客服的IM沟通帮助企业辅助判断客户需求与诉求,通过自定义客户分类标签,客户再次访问时可获知客户的类型。并且还支持自定义会话小结,根据会话小结统计会话的分类,通过会话小结追踪客户诉求。通过轨迹分析功能,即通过发送客户访问页面的轨迹,判断客户意图,获取客户个性化细节,了解客户基础信息,分析客户行为,可以极大提高订单效率。
    • 第五,“智能机器人+智能知识库”:作为一套智能化的客服系统,让企业建立基于业务的智能知识库,智能辅助归结业务信息和应答客户信息,历史常见问题系统梳理,提高客服效率。“智能机器人+智能知识库”组合目前可自动回复80%常见问题,随着智能知识库的不断训练,这一比例能够提高到90%。
    • 第六、真正实现不丢订单:环信是中国乃至全球领先的即时通讯云服务提供商,上线1年来,已成为唯一一家经历了亿级长连接真实稳定运行的即时通讯云平台,中国主流的采用第三方即时通讯云服务的App几乎都是环信的客户,每日环信平台的消息量达到数亿条,有着即时通讯云领域亿级长连接的绝对垄断优势。环信基于IM长连接技术,帮助企业实现超线拉取排队会话,让等待时间过长或有订单需求的客户得到优先服务,提升客服效率,即使客户关闭会话,退出App,甚至关闭手机,基于IM长连接技术依然能找回客户会话,提升客服效率,不丢客户订单。同时,基于IM长连接技术,即使在断网或复杂网络切换时也依然能找回客户会话,不丢客户订单。
    • 第七、实现了质检系统透明管理:移动客服自带实时监控系统,可实时监控当前所有会话,管理员在线质检,在线查看会话信息,还提供了历史会话查询、质检考核。通过实时与历史查看,可以统计出客服代表的接入量、在线时间及应答等待时间。



    6.png


    环信CTO Johnson向大家介绍客服产品

    总之,通过部署环信移动客服,较于传统客服产品可以节省成本约60%,在移动端省电省流量高达80%,同时留住70%会话客户,订单量和客单价均可以获得不同幅度提升。 收起阅读 »

    环信移动客服受电商青睐背后:社交经济时代的全渠道营销变革

    2015年7月28日,环信B轮融资发布会如期召开了。据了解,此轮环信共获得1250万美元融资。至此,环信已经在1年内完成了4轮融资,前三轮分别是2014年5月经纬中国天使伦融资500万人民币,2014年8月SIG A轮融资500万美金,2014年10红杉300...
    继续阅读 »
    2015年7月28日,环信B轮融资发布会如期召开了。据了解,此轮环信共获得1250万美元融资。至此,环信已经在1年内完成了4轮融资,前三轮分别是2014年5月经纬中国天使伦融资500万人民币,2014年8月SIG A轮融资500万美金,2014年10红杉300万美金A+轮融资。


    QQ截图20150729110432_conew1.png



    这一轮融资依然被前几轮老股东“三巨头”内部瓜分,领头的是红杉资本、经纬中国和SIG跟投,诸多投资机构欲进无门,望而兴叹。发布会现场,依然有VC代表赶来想碰碰运气,追着环信的人问未来还有没有进入的可能。


    3_conew1.png



    经纬副总裁 熊飞 给环信刘俊彦 颁发融资支票

    这现象的不同寻常之处在于,这是一个做2B领域的创业项目,此前受到业界如此猛烈追捧的一般都是2C的企业。为何环信一个做2B业务的企业会猛然间冒出来受到如此关注?
     
    据了解,让环信炙手可热的是其背后蕴含的巨大商机。而支撑环信估值暴涨的商机正是近来被业界关注的万亿级企业云服务市场前景,而且环信的“即时通讯云+移动客服”业务切中的恰是企业云服务市场王冠上的宝钻。
     
    2015年将成为企业云服务市场的爆发元年,这一端倪在企业云服务市场率先爆发的美国已经十分清晰。据有关专家分析,在过去的1年时间里美国的企业服务市场,已经有超过15家企业IPO,他们的募集资金达到70亿美元,总市值超过400亿美元,其中有Zendesk、Hubspot、New Relic、Hortonworks、Box等不少明星企业。而且,美国目前这样规模的企业云市场还正处在从青年走向壮年的阶段。据分析,从市值排名前十的云计算企业服务公司的市值总和看,2008年市值总和是250亿美元,到2015年这一数字已经是1800亿美元了,7年里增长了超过7倍。而预计到2016年,美国才会出现第一个云服务市场占有率超过传统软件的垂直领域,就是CRM。而“客服”是CRM四大细分市场之一。而且,客服是CRM细分领域中最大的一个,占市场总额的37%。在北美,2015年客服软件市场采购总额高达96亿美元。这个市场中已经出现了两家“独角兽”公司,就是近来受到各界关注和追捧的Zendesk和Freshdesk。


    1_conew1.png


    环信北美对标公司
     
    中国的市场机会可能比美国更令人兴奋,在中国企业云服务市场还是一片空白。相交美国,为企业2700万家企业客户,提供云服务的三家大的领军公司Oracle、SAP、Salesforce市值总和在3500亿美金左右。而中国,目前有2200万企业,但中国至今还没有百亿美元身价的公司甚至还没有基于SaaS的10亿美元身价的公司。这也许正是最先能嗅到风信的VC们挤破头的想投环信的缘由。

    有意思的是,据记者发现,由于无法进入环信的投资圈,VC们并没有放弃这一领域的赌胜机会和投资热情。因而,自从环信变得越来越炙手可热但却望而兴叹后,业界“类环信”项目在连带效应下成为VC们宣泄相对过剩资金的一个突破口。近来有不少作为环信影子的公司,或者学环信的公司获得了融资,甚至有创业者表示:环信成功之前,“类环信”公司想拿融资,得跟投资人费一番口舌,而环信成功后,“类环信”只要拿换新的概念改一改说自己做的跟环信一样就通过了。

    更有意思的是,在环信的IM云+客服模式被证明获得成功之后,百度、阿里、腾讯、金蝶、个推等相继跟随,推出了自己的IM业务,虽然,被大平台追逐,但在环信CEO刘俊彦看来这并没有什么可怕的,环信积累的技术优势和市场优势不是一两天能追得上的。据了解,环信的根基——即时通讯云能达到亿级稳定长连接并不容易,以环信网罗的中国IT界最顶尖的IM技术精英,需要至少1年时间了解服务器架构,真实稳定积累千万、亿万系统的维护经验。但一家100人的创业企业得到BAT带头的互联网巨头公司的特别“关照”,还是人感到兴奋的。

    还有值得关注的是,环信也引起了美国Zendesk和layer的足够重视,在环信公布“连接人与商业”的愿景后,我们可以看到Zendesk的官网增加了一句类似的话:Zendesk brings companies and their customers closer together.

    同时,也传闻Zendesk正在收购整合提供IM服务的公司,而layer也有被传闻称将推类似环信的业务。 收起阅读 »

    一个双网卡导致的网络故障

    内网有个机器有2个网卡,并且是不同的网段和网关。 其中的B服务器有2个网卡。这个时候我们就只有默认网关为10.1.1.1 那查看路由表就是如下[root@localhost ~]# ip route show table all 10.1.1.0/...
    继续阅读 »
    内网有个机器有2个网卡,并且是不同的网段和网关。


    network.png


    其中的B服务器有2个网卡。这个时候我们就只有默认网关为10.1.1.1 那查看路由表就是如下
    [root@localhost ~]# ip route show table all
    10.1.1.0/24 dev eth0 proto kernel scope link src 10.1.1.247
    10.1.2.0/24 dev eth1 proto kernel scope link src 10.1.2.239
    169.254.0.0/16 dev eth0 scope link metric 1002
    169.254.0.0/16 dev eth1 scope link metric 1003
    default via 10.1.1.1 dev eth0

    [root@localhost ~]# ip rule show
    0: from all lookup local
    32766: from all lookup main
    32767: from all lookup default

    这个时候我们可以发现,从1网段到1网段来回都没有问题,2网段来回也没有问题。但是从server A到server B的2网段是不通的。 因为你去到2网段后,server B的默认路由是10.1.1.1。
    所以我们需要设置server B上,来自哪个网卡的路由就从哪个网卡出去。这样server A到server B的2网段就没有问题了。

    首先添加2个route table
    $ cat /etc/iproute2/rt_tables
    #
    # reserved values
    #
    255 local
    254 main
    253 default
    252 lan1
    251 lan2
    0 unspec

    然后再添加ip route和ip rule
    ip route flush table lan1
    ip route add default via 10.1.1.1 dev eth0 src 10.1.1.247 table lan1
    ip rule add from 10.1.1.247 table lan1

    ip route flush table lan2
    ip route add default via 10.1.2.1 dev eth1 src 10.1.2.239 table lan2
    ip rule add from 10.1.2.239 table lan2

    这个时候我们再查看路由表如下
    [root@localhost ~]# ip route show all
    10.1.1.0/24 dev eth0 proto kernel scope link src 10.1.1.247
    10.1.2.0/24 dev eth1 proto kernel scope link src 10.1.2.239
    169.254.0.0/16 dev eth0 scope link metric 1002
    169.254.0.0/16 dev eth1 scope link metric 1003
    default via 10.1.1.1 dev eth0

    [root@localhost ~]# ip rule show
    0: from all lookup local
    32764: from 10.1.2.239 lookup lan2
    32765: from 10.1.1.247 lookup lan1
    32766: from all lookup main
    32767: from all lookup default

    这个时候从表面上似乎解决了问题,从server A访问server B的2网段也能正常返回,从server C访问server B的1网段也可以正常返回。
    但是我们发现,这个时候从server B访问server A的1网段的时候,一直网络状态在SYN的状态。


    half-tcpdump.png


    上面tcpdump的结果我们发现是有很多的TCP重传。这个时候我们发现,上面的ip rule只是设定了,来自2网段的走lan2(又设定了src为自己), 来自1网段的走lan1(又设定了src 为自己的IP)。而没有设定如果主动出去是怎么样的。
    因此我们把上面的ip rule加了2条.
    ip route flush table lan1
    ip route add default via 10.1.1.1 dev eth0 src 10.1.1.247 table lan1
    ip rule add from 10.1.1.247 table lan1
    ip rule add from 10.1.1.247 to 10.1.1.0/24 table main

    ip route flush table lan2
    ip route add default via 10.1.2.1 dev eth1 src 10.1.2.239 table lan2
    ip rule add from 10.1.2.239 table lan2
    ip rule add from 10.1.2.239 to 10.1.2.0/24 table main

    然后我们查看路由表如下:
    [root@localhost ~]# ip route show table all
    default via 10.1.1.1 dev eth0 table lan1 src 10.1.1.247
    10.1.1.0/24 dev eth0 proto kernel scope link src 10.1.1.247
    10.1.2.0/24 dev eth1 proto kernel scope link src 10.1.2.239
    169.254.0.0/16 dev eth0 scope link metric 1002
    169.254.0.0/16 dev eth1 scope link metric 1003
    default via 10.1.1.1 dev eth0
    default via 10.1.2.1 dev eth1 table lan2 src 10.1.2.239

    [root@localhost ~]# ip rule show
    0: from all lookup local
    32762: from 10.1.2.239 to 10.1.2.0/24 lookup main
    32763: from 10.1.2.239 lookup lan2
    32764: from 10.1.1.247 to 10.1.1.0/24 lookup main
    32765: from 10.1.1.247 lookup lan1
    32766: from all lookup main
    32767: from all lookup default

    从上面这个例子中可以窥见,平时我们用netstat -rn这样来查看路由是没有问题的,但是当出现自定义route table的时候,我们需要注意的一些东西,一个是route table本身,还有是ip rule去定义使用哪个table。
    作者:崔永强
      收起阅读 »

    luckyOne - HTML5&CSS3抽奖小程序

    程序可用于各类活动,如年会、发布会等。 支持回车和空格键控制。   附件中是环信本次发布会使用的版本。 空格/回车控制抽奖的启动和开始,由于中奖者大图弹出是现场第二轮抽奖时临时加的,不完善。每次启动停止后需F5刷新重新开始新的一轮。最后按键盘"o"键有...
    继续阅读 »
    程序可用于各类活动,如年会、发布会等。
    支持回车和空格键控制。
     
    附件中是环信本次发布会使用的版本。
    空格/回车控制抽奖的启动和开始,由于中奖者大图弹出是现场第二轮抽奖时临时加的,不完善。每次启动停止后需F5刷新重新开始新的一轮。最后按键盘"o"键有个结束特效幻灯片。

    通用版请访问Github库:https://github.com/haozki/luckyOne
    欢迎大家下载使用和交流。 收起阅读 »

    wordpress静态化

    下面这个是结合了很多参考加上自己实践最终确认能用的。不过这个还是跟主题有很大关系。不是所有主题都是可以完全转成静态的。下面这个配置文件是nginx的,apache的用户就没有这样的烦恼了。 大部分主题都是可以使用的,但是有些加了一些动态验证这样代码的,要那样的...
    继续阅读 »
    下面这个是结合了很多参考加上自己实践最终确认能用的。不过这个还是跟主题有很大关系。不是所有主题都是可以完全转成静态的。下面这个配置文件是nginx的,apache的用户就没有这样的烦恼了。
    大部分主题都是可以使用的,但是有些加了一些动态验证这样代码的,要那样的就只能用fastcgi cache来进行处理了。
    这里使用的是wordpress的supercache模块。
    upstream php-fpm {
    server unix:/var/run/phpfpm.sock;
    }

    server {
    listen 80;
    server_name timo.piqiu.me;

    root /opt/web/wordpress;
    index index.php;

    access_log logs/timo.piqiu.me.access.log proxy;
    error_log logs/timo.piqiu.me.error.log;

    location = /favicon.ico {
    log_not_found off;
    access_log off;
    }

    location = /robots.txt {
    allow all;
    log_not_found off;
    access_log off;
    }

    location ~ /\.svn/* {
    deny all;
    }

    location ~ /\.git/* {
    deny all;
    }

    location /nginx_status {
    stub_status on;
    access_log off;
    }

    set $cache_uri $request_uri;

    # POST requests and urls with a query string should always go to PHP
    if ($request_method = POST) {
    set $cache_uri 'null cache';
    }
    if ($query_string != "") {
    set $cache_uri 'null cache';
    }

    # Don't cache uris containing the following segments
    if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|/wp-(app|cron|login|register|mail).php|wp-.*.php|/feed/|index.php|wp-comments-popup.php|wp-links-opml.php|wp-locations.php|sitemap(_index)?.xml|[a-z0-9_-]+-sitemap([0-9]+)?.xml)") {
    set $cache_uri 'null cache';
    }

    # Don't use the cache for logged in users or recent commenters
    if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_logged_in") {
    set $cache_uri 'null cache';
    }

    # Use cached or actual file if they exists, otherwise pass request to WordPress
    location / {
    try_files /wp-content/cache/supercache/$http_host/$cache_uri/index.html $uri $uri/ /index.php ;
    }
    location ~ \.php$ {
    try_files /wp-content/cache/supercache/$http_host/$cache_uri/index.html $uri $uri/ /index.php ;
    fastcgi_pass php-fpm;
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /opt/web/wordpress$fastcgi_script_name;
    fastcgi_intercept_errors on;
    include fastcgi_params;
    #
    # fastcgi_cache cache_fastcgi;
    #
    # fastcgi_cache_valid 200 302 301 24h;
    # fastcgi_cache_valid any 1m;
    #
    # fastcgi_cache_min_uses 1;
    #
    # fastcgi_cache_use_stale error timeout invalid_header http_500;
    # fastcgi_cache_key $request_method://$host$request_uri;
    }

    # Cache static files for as long as possible
    location ~* .(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
    expires max; log_not_found off; access_log off;
    }

    location ~ ^/(status|ping)$ {
    include /opt/server/nginx/conf/fastcgi_params;
    fastcgi_pass unix:/var/run/phpfpm.sock;
    fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
    allow 127.0.0.1;
    deny all;
    }
    }
    收起阅读 »

    redis replication问题一解

    公司有个redis比较大,同时又是跨IDC同步,但是最近发现一旦连接断了之后,好久都不能完全同步。 查看了一下log。[12826] 01 Apr 16:54:37.675 # I/O error trying to sync with MASTER: co...
    继续阅读 »
    公司有个redis比较大,同时又是跨IDC同步,但是最近发现一旦连接断了之后,好久都不能完全同步。

    查看了一下log。
    [12826] 01 Apr 16:54:37.675 # I/O error trying to sync with MASTER: connection lost
    [12826] 01 Apr 16:54:38.555 * Connecting to MASTER 10.x.x.x:6379
    [12826] 01 Apr 16:54:38.555 * MASTER <-> SLAVE sync started
    [12826] 01 Apr 16:54:38.621 * Non blocking connect for SYNC fired the event.
    [12826] 01 Apr 16:54:38.692 * Master replied to PING, replication can continue...
    [12826] 01 Apr 16:54:45.229 * MASTER <-> SLAVE sync: receiving 390598473 bytes from master

     
    通过info观察也是一直去master上同步,有时候看着马上就完成了,就报以上的错误。 以前使用redis很老的版本2.4一直都没有这样的问题,自从换了2.6以后才出现这样的问题的。
    放狗查了下原来是 client-output-buffer-limit  这个参数导致的。默认是:
    client-output-buffer-limit slave 256mb 64mb 60

    但是不是很明白这个参数的含义,看了redis文档还正有说这个的。

    大体意思就是如下:

    hard limit是一旦redis到达这个值后会马上关闭client连接。
    soft limit是一种依赖于时间的。 比如一个soft limit被设置为32MB 10s, 那就意味着当client的output buffer超过32MB,并且持续10秒钟,那这个连接就会被断开。

    默认值就是hard 为256M, soft为 32M 60秒

    普通客户端的默认limit为0, 就是任何时候都没有limit,因为普通的client使用阻塞来实现发送命令和接收完整的返回,在发送下一个命令之前,所以在普通的client的情况下关闭连接是不合适的。

    但是要特别注意pub/sub客户端,这种方式一次处理和输出的数据都会特别大。

    我们可以使用config set 来进行设置,但是注意使用config set的时候不支持MB,GB 这样的单位。
    下面这个是redis官网的一个具体说明:

    http://redis.io/topics/clients
    Output buffers limits

    Redis needs to handle a variable-length output buffer for every client, since a command can produce a big amount of data that needs to be transferred to the client.

    However it is possible that a client sends more commands producing more output to serve at a faster rate at which Redis can send the existing output to the client. This is especially true with Pub/Sub clients in case a client is not able to process new messages fast enough.

    Both the conditions will cause the client output buffer to grow and consume more and more memory. For this reason by default Redis sets limits to the output buffer size for different kind of clients. When the limit is reached the client connection is closed and the event logged in the Redis log file.

    There are two kind of limits Redis uses:
    • The hard limit is a fixed limit that when reached will make Redis closing the client connection as soon as possible.
    • The soft limit instead is a limit that depends on the time, for instance a soft limit of 32 megabytes per 10 seconds means that if the client has an output buffer bigger than 32 megabytes for, continuously, 10 seconds, the connection gets closed.
    Different kind of clients have different default limits:
    • Normal clients have a default limit of 0, that means, no limit at all, because most normal clients use blocking implementations sending a single command and waiting for the reply to be completely read before sending the next command, so it is always not desirable to close the connection in case of a normal client.
    • Pub/Sub clients have a default hard limit of 32 megabytes and a soft limit of 8 megabytes per 60 seconds.
    • Slaves have a default hard limit of 256 megabytes and a soft limit of 64 megabyte per 60 second.


    It is possible to change the limit at runtime using the CONFIG SET command or in a permanent way using the Redis configuration file redis.conf. See the exampleredis.conf in the Redis distribution for more information about how to set the limit.
    作者:戚俊奇 收起阅读 »

    gcm推送

    一.gcm前期准备   Apple有apns推送,Google有gcm推送,iOS接收通知调用系统通知栏提示,Android接收通知启动应用调用通知栏提示。 相对于apns,gcm则多了一些限制,需要一些必备条件达到才可以使用。 1.在国内,首先就...
    继续阅读 »
    一.gcm前期准备


    20150727113000901_(1).jpg


     
    Apple有apns推送,Google有gcm推送,iOS接收通知调用系统通知栏提示,Android接收通知启动应用调用通知栏提示。
    相对于apns,gcm则多了一些限制,需要一些必备条件达到才可以使用。
    1.在国内,首先就是Google被墙,无法连接到Google服务器,需要你走VPN或者其它方式可以连接到Google服务器。
    2.在你的开发环境下,需要通过Android SDK Manager—>Extras下安装Google Play services,成功之后在你的SDK文件/sdk/extras/google/google_play_services/libproject下会看到google-play-services_lib类库,可以从里面直接复制jar包到你的项目libs下
    3.Android客户端,要求安装了Google核心服务Google Play服务,Google Play 商店才能使用gcm


    20150727113107623.jpg


    以上是Google官方文档描述:
    大意就是gcm要求设备运行在Android系统2.2或更高版本并且安装了Google play商店应用,或者虚拟机运行在Android系统2.2版本的并且支持Google API,但是并不限制你的应用必须部署在Google play 商店。
    然而,如果你想要使用gcm 新的API就需要设备运行在Android系统2.3或更高版本,或者使用虚拟机运行在Android系统2.3并且支持Google API
    在一个现有连接Google服务的设备上,对于前置3.0的设备,就要求在Android设备上设置Google账号,4.0.4或者更高版本则不需要设置Google账号
    注:gcm只是简单的推送一个通知到客户端,其消息内容应小于4Kb,Google服务器存储时间为4个星期。在客户端,gcm是通过客户端设备注册一个系统广播来唤醒应用并发出通知提示,所以这个时候客户端不需要一直运行来接收消息,gcm一次发送最多可发送100个用户
     
    二.官网创建项目获取信息

    去Google Developers Console(https://console.developers.google.com/project)创建项目,输入你的project name和project id,创建成功如下图:


    6.jpg


    在应用中我们会用到这个project number,再去Credentials下创建一个server key,得到的api key会在自己的服务器端用到,如图

    7.jpg


    顺便说一下,默认Cloud Messaging for Android是可用的,如果不能用,就需要去API & auth—> API下查看Cloud Messaging for Android是否disable

    三.创建一个客户端app

    首先要在AndroidManifest.xml文件配置gcm权限等信息
      
    //当GCM需要谷歌账户(设备版本低于4.0.4时需要)


    android:protectionLevel="signature" />

    applicationPackage要改成自己的报名

    android:minSdkVersion="8"不得低于8


    8.jpg


    根据官网文档介绍:

    1.我们应该在配置文件注册一个系统广播
    
               android:name="com.google.android.gms.gcm.GcmReceiver"  
    android:exported="true"
    android:permission="com.google.android.c2dm.permission.SEND" >





    2.注册监听通知服务(在app中创建一个服务类并继承GcmListenerService类)
    
                android:name="com.example.MyGcmListenerService"  
    android:exported="false" >





    public class MyGcmListenerService extends GcmListenerService {

    @Override
    public void onMessageReceived(String from, Bundle data) {
    String message = data.getString("message");
    /**
    * Production applications would usually process the message here.
    * Eg: - Syncing with server.
    * - Store message in local database.
    * - Update UI.
    */

    /**
    * In some cases it may be useful to show a notification indicating to the user
    * that a message was received.
    */
    sendNotification(message);
    }
    // [END receive_message]

    /**
    * Create and show a simple notification containing the received GCM message.
    *
    * @param message GCM message received.
    */
    private void sendNotification(String message) {
    Intent intent = new Intent(this, MainActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
    PendingIntent.FLAG_ONE_SHOT);

    Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
    .setSmallIcon(R.drawable.ic_stat_ic_notification)
    .setContentTitle("this is a new new GCM Message")
    .setContentText(message)
    .setAutoCancel(true)
    .setSound(defaultSoundUri)
    .setContentIntent(pendingIntent);

    NotificationManager notificationManager =
    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }
    }

     
    3.注册监听token改变的服务(在app中创建一个服务类继承InstanceIDListenerService类,本服务存在于新的Google play服务版本上)
     android:name="com.example.MyInstanceIDListenerService"  
    android:exported="false">





    public class MyInstanceIDListenerService extends InstanceIDListenerService {

    @Override
    public void onTokenRefresh() {
    // Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
    }
    }

     
    gcm通过注册的系统广播可以自行启动GcmListenerService类,所以不需要在app创建一个广播类

    注册token

    App发送 project number到GCM Server注册接收推送信息。 

    GCM Server 向App返回token(token是GCM服务器自行生产的,能够保证某一终端设备上的某一个应用,很重要)。 

    在设备上应该先判断是否安装了Google play 服务
    int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);  
    if (resultCode != ConnectionResult.SUCCESS) {
    if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
    GooglePlayServicesUtil.getErrorDialog(resultCode, this, PLAY_SERVICES_RESOLUTION_REQUEST).show();//会提示错误对话框,其他错误信息可参考官网API
    } else {
    Log.i(TAG, "This device is not supported.”);
    }

     
     
    Google play服务存在,那接下来就需要去注册token了,在上边创建项目得到的project number在这里就需要用它来注册token


    10.jpg




    9.jpg


     
    InstanceID instanceID = InstanceID.getInstance(this);  
    String token = instanceID.getToken(PROJECT_NUMBER,
    GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);

     
    对于旧版本还是要使用以下方式来注册token(用于Google play 服务7.5版本之前)
    GoogleCloudMessaging.getInstance(Context).register(PROJECT_NUMBER);  

     
    在自己的服务器端注册api key

    App向我们自己服务器发送token(推送消息的时候要使用token,GCM服务器是使用token来确定某一终端设备上的某一个应用接收消息的,所以第三方服务器需要保存它,需要注意的是token很长,存数据库时需要注意字段长度) ,将我们在上边create new key 得到的apikey添加到自己的服务器端保存,我们的服务器向GCM Server发送消息,传递apikey和token ,GCM Server把消息推送给App 
    最后注意一下,关于app卸载出现的问题,看一下官方的介绍


    11.jpg



    app会发生卸载过程并不能很快完成,卸载app需要花时间从GCM移除当前关联的token,这个过程就会出现发送消息是成功的,但是不能到达app客户端,在最后,token被移除了,服务器端发送的消息失败,得到一个NotRegistered错误,这个时候就应该在服务器端删除相对应的token 收起阅读 »

    凡信(超仿微信Android版)后台代码

    不知道什么鬼的看这个帖子http://www.imgeek.org/question/763?notification_id=226&column=log。   关于该项目的讨论群为437758366;   我的QQ:84543217.。。。。欢迎交流和一起学...
    继续阅读 »
    不知道什么鬼的看这个帖子http://www.imgeek.org/question/763?notification_id=226&column=log。
      关于该项目的讨论群为437758366;
      我的QQ:84543217.。。。。欢迎交流和一起学习。
    服务器端代码,回复可见。帮忙顶一下。
    另外需要朋友圈的朋友可以找我,做了套独立系统,支持嵌入任何有好友关系的android APP.
      收起阅读 »

    开发实战:Android自定义标题栏

    本文要讲自己定义一个标题栏,能加事件。然后可以移值到不同的手机上,基本上不用改什么,调用也很简单 在layout文件夹下,新建一个XML。名字叫做layout_title_bar.xml然后来看看布局: ...
    继续阅读 »
    本文要讲自己定义一个标题栏,能加事件。然后可以移值到不同的手机上,基本上不用改什么,调用也很简单

    在layout文件夹下,新建一个XML。名字叫做layout_title_bar.xml然后来看看布局:
      
    android:layout_width="fill_parent"
    android:layout_height="45.0dip"
    android:background="@drawable/bg_title_bar"
    android:gravity="top" >

    android:id="@+id/title_bar_menu_btn"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_marginLeft="3.0dip"
    android:layout_marginRight="3.0dip"
    android:layout_marginTop="3.0dip"
    android:gravity="center"
    android:src="@drawable/ic_top_bar_category" />

    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:layout_toRightOf="@id/title_bar_menu_btn"
    android:background="@drawable/ic_top_divider" />

    android:id="@+id/title_bar_name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:ellipsize="end"
    android:gravity="center"
    android:paddingLeft="75.0dip"
    android:paddingRight="75.0dip"
    android:singleLine="true"
    android:text="Java学习宝典"
    android:textColor="#ffffff"
    android:textSize="22sp" />

    看下效果:


    20150220004910963.png


    接下要就是要用了,在要用到的地方:我这里是activity_main.xml文件中:

    加上一句:  这样就行了,

    然后我们要给标题栏上的按钮添加事件,这个更加简单了:

    在MainActivity.java(对应activity_main.xml)中,onCreate函数中添加:事件可以自己改,我这里是让它控制左右滑动的功能。
    ImageView menuImg = (ImageView) findViewById(R.id.title_bar_menu_btn);  
    menuImg.setOnClickListener(new View.OnClickListener() {

    @Override
    public void onClick(View arg0) {
    if (!menuIsShow)
    showMenu();
    else {
    hideMenu();
    }

    }

    });
    这样就可以了:

    我们来看看效果


    20150220004942958.gif



    这就是效果了,很简单吧,想用直接把上面的布局复制过去就OK了!
     
    作者:林炳文Evankaka 收起阅读 »

    中国互联网大会感受:技术人员最好的创业时代

    “年年岁岁花相似,岁岁年年人不同”,用这句千古名句来形容中国互联网大会的发展历程可以说再贴切不过了。在经历了互联网的1.0时代(PC互联网)、2.0时代(移动互联网)后,互联网的发展正快速步入下一个迭代周期,你可以认为是3.0时代,也可以给这个时代打上一个互联...
    继续阅读 »
    “年年岁岁花相似,岁岁年年人不同”,用这句千古名句来形容中国互联网大会的发展历程可以说再贴切不过了。在经历了互联网的1.0时代(PC互联网)、2.0时代(移动互联网)后,互联网的发展正快速步入下一个迭代周期,你可以认为是3.0时代,也可以给这个时代打上一个互联网+的标签。总之,当下这个时代互联网已不再是某个或某些企业的专属,谈全民互联网甚至也不觉得夸张。 在日前举办的第十四届中国互联网大会上,笔者也选取了三个非常有代表性的企业进行采访报道,看看透过它们是否能觉察出一些互联网+的典型特征。这三家企业分别是传统互联网的代表百度、传统制造业的代表联想,以及新兴的科技型创业企业环信。要说本次中国互联网大会上三家企业的所讲所展,有一个共同点是它们都在做云相关的内容,当然不同就多了去了,这里也不细说了,毕竟是三家几乎不搭杠的企业。 

    首先,我们来聊聊环信。 

    作为一家刚刚成立不过2年多的创业型企业,可能很多人还不太熟悉,这里先做个介绍。环信即时通讯云成立于2013年4月,是一家提供移动即时通讯能力的云计算 PaaS (Platform as a Service, 平台即服务) 平台服务商。 

    这么听起来可能还是有些难懂,我们举个例子来进一步说明一下,即时通讯相信大家并不陌生,电话、QQ、微信之类的都算是即时通讯工具,即时通讯云简单理解就是用于承载这些工具的平台。而基于该平台,环信有自己开发的即时通讯工具移动客服。


    lij5o8EpD9NFA_600.jpg


     
    环信CEO刘俊彦
     
    据环信CEO刘俊彦介绍,目前其即时通讯云平台上线已一年多时间,SDK(Software Development Kit,软件开发工具包)覆盖用户近1个亿,有3万余个APP集成了该平台的即时通讯能力,终端用户覆盖超3个亿。而另一款拳头产品移动客服上线仅3个月,已签约数百家企业,包括国美在线、58到家在内的众多龙头企业都已是环信的用户。 

    关于即时通讯云前文已有相应的解释,这里不再赘述,而是介绍下何谓移动客服顾名思义,移动客服就是主要面向移动终端的客服,更准确地讲就是针对各种APP打造的客服工具。相信大家都打过400、800之类的客服电话,估计也用过PC端的网页客服,但随着移动互联网的兴起,这些方式在应对移动端客户的需求时已变得捉襟见肘。 

    为什么呢?
     
    • 一是移动端的量大,一个APP同时在线的人数可能在数十上百万;
    • 二是一旦APP打开,与客服之间的连接就是一直长期保持的关系。而在PC端,网页一旦关闭,与客服之间的对话就已经中断。无疑,移动客服后台数据中心所承载的压力和成本是要远高于传统客服方式的。刘俊彦表示,这也是移动客服市场的主要门槛之一。 


    显然,作为国内较早进入该行业的企业,环信无疑已经占领了先机,前文已经提到了环信目前的用户情况,可以说非常不错,而更关键的是环信基本已经实现了收支平衡,要知道这在创业一两年的企业中可是为数不多的。 

    放眼未来,环信也有着明确的规划。当前,其B轮融资已经到位,至于具体数额会于下周公布,但这些钱用在什么地方,他们早就想清楚了。刘俊彦表示,公司下一步的拓展方向主要是两个方面,一是由现在更多面向服务电商、O2O、互联网金融、互联网教育、医疗、旅游行业的移动客服向覆盖传统客服和移动客服的全领域扩张,二则是向物联网领域发展。 

    具体来说,一是为了向用户提供客服的整体解决方案,而这么做的规划其实也是客户需求促使。据刘俊彦介绍,现在就有客户问他是不是能提供一整套完整的解决方案,而不需要移动客服找你们,网页客服找另一家,电话客服再找一家。二则是面向未来广阔的物联网市场,用不了几年,冰箱、洗衣机坏了的时候你已经无需再查找厂商的客服电话,而可能通过电器上的一个按钮就能实现报修,想一想是不是很美好。 

    但话说回来,作为一个具有广阔市场前景的行业,环信所不可避免的要面临竞争,而且随着市场的不断扩大,竞争也会愈发剧烈。不过在笔者将这个问题抛给刘俊彦时,他倒是相当坦然。要说技术出身的人总是那么的质朴,可能是被问的多了回答的也多了,他很平淡地说,“市场这么大(美国大概是100亿美金,中国市场比这个还要大),我们能拿下个位数的份额,已经是足够大的体量了。现在更重要的是有更多的人进来,把这个行业先做大,做好用户服务。”

    在写有关环信内容的最后,加一点刘俊彦的个人履历,17年研发,先后任职IONA、RedHat,专注于高并发消息中间件,实时消息系统,异构分布式企业系统集成,应用服务器。联想到最近一两年兴起的一批批创业公司,包括很多都在本次互联网大会上亮了相,笔者只想说,这是技术人员最好的创业时代。  收起阅读 »

    iOS开发生涯的初恋:详解Objective-C多项改进

    对于许多iOS开发者而言,Objective-C就是开发生涯中的初恋。如今,Swift正在以迅雷不及掩耳之势碾压Objective-C的份额,但Objective-C多项性能改进依然让开发者非常激动,本文作者对OC的提升进行了详解。   The Setup ...
    继续阅读 »
    对于许多iOS开发者而言,Objective-C就是开发生涯中的初恋。如今,Swift正在以迅雷不及掩耳之势碾压Objective-C的份额,但Objective-C多项性能改进依然让开发者非常激动,本文作者对OC的提升进行了详解。
     
    The Setup

    下面的代码你们一定再熟悉不过了,我们来重温一下吧:
    @property (strong, nonatomic) NSArray *someViews;  
    这绝对符合Objective-C完美主义开发者的标准。对它表示的属性,不同人有不同观点。但是,其中仍然存在着一些难以察觉的缺陷。

    是否可能返回nil?

    除非有现成的文件,或开发者全程都在一旁,否则光凭看是无法获取信息的。

    除了UIView之外还有什么?

    还是那句话——不确定。也许答案是reflection? 或许问题可以改成:除了UIView,有可能出现UIView子类吗?

    看样子会出现诸多转换(casting)

    因为是一队列……东西,知道那东西是什么之后,经过cast后才能利用。

    会弱化Swift代码和可读性

    很遗憾,Swift支持泛型(generics)就意味着(Objective-C )只会以optional的AnyObject集合的形式出现。如此一来,开发者要使用该属性就必须在Swift和Objective-C之间进行转换。

    Nullability Annotations

    单单一个属性就引发了这么多担忧,还挺让人不安的。如果代码本身引发很多质疑,出现error的可能性就大大增加,更别提在广为熟知的Objective-C和语言新秀Swift之间相互调用(interoperability)了。现在有了nullability annotations——我最爱的Objective-C新功能之一,问题就简单多了,编程也会省下很多麻烦。

    intent.

    现在谈到API,(intent.)可能会,也可能不会返回nil。简而言之,终于不用花费数小时来排除漏洞了。以下有三个选项:
    • nullable — Think UIView?
    • nonnull — Think UIView
    • null_unspecified — Think UIView!


    再回到实例属性。假设在运行时迭代这个属性来创建某个用户界面,在相应的位置应该有UIButton和UIView。

    但是,天哪!——不论怎么样它们也不应该是nil啊。现在出现如下的信息:
    @property (strong, nonatomic, nonnull) NSArray *someViews; 
    intent.大大提升了Objective-C,而且这个属性也不会在Swift里满满都是optional了。

    开发者看看代码就知道有没有nil pointer了,太棒了!

    计算机的静态检验和Swift的可用性都得到了提升,最重要的是实现了API的intent通讯。

    泛型

    ……Objective-C开发者们举国欢庆。呜呼,泛型的恩泽终于笼罩大地,这无疑是那些开发者勇士们的功劳。

    如果把Cocoa Touch比作孩子们的睡前故事,那么Objective-C就好比是主演,故事书肯定是以上面那段话结尾的。泛型的缺席一直以来是Objective-C开发者心头之痛,而诞生32年之后,Objective-C终于也支持泛型了。2015 WWDC上Swift 2成为了镁光灯下的宠儿,而Objective-C这一巨大的跨越却被忽视了,实在委屈。支持泛型将带来诸多改变,而且都是积极的改变。

    现在可以定义属性,下指令给编译器来显示所有UIView:
    @property (strong, nonatomic, nonnull) NSArray *someViews;  
    向属性强加UIView之外的东西时,编译器会报错。而且如今不用做大量头痛的转换(cast)了。

    Objective-C支持泛型对Swift而言也是好消息。上次更新时,我们让Swift知道对象不应该是optional的,现在Swift还知道它们是UIViews,如此一来含混不清的AnyObject声明就不需要了。如今的Objective-C可以像C#、C++、Swift等语言一样通过<>括号来表示类型了。虽然通常是对协议表示一致性(conformance),但编译器知道何时、何地以及如何运用它们,且运用是经过推理的。

    再进一步,可以用参数来表示扩展(extensions)、类别(categories)和类(classes),好处不仅仅体现在集合(collections)上。泛型的强大体现在整个Objective-C之中,集合仅仅是结果而已。举个例子,看看NSDictionary,开发者肯定会偷着乐吧:
    @interface NSDictionary (Lookup)  
    - (nullable ObjectType)objectForKey:(KeyType)aKey;
    @end
    刚开始知道类型擦除(type erasure)是为了这个的时候,我有点儿不满意,但考虑到老旧的Objective-C程序堆积在一起的问题,也就释怀了。

    类型擦除(type erasure)不但能实现二进制兼容,而且不改变Objective-C的执行时间。所以亲爱的开发者们,C#的泛型的确胜过其他语言,皱皱眉头,发几句牢骚就算了,日子还得继续呢。

    KindOf Types

    啊,这是最后一部分重要内容。再次调用之前定义的属性,就会显示UIView。判断里面包含着views和buttons是再正常不过的事。

    这种情况下,添加如下代码会发生什么呢?
    [self.someViews[0] addTarget:self action:selector(aMethod:) forControlEvents:UIControlEventTouchUpInside];  
    啊,编译器警告。

    这就对啦,因为即便可以在这个属性里插入一个button,就算可以假设是个UIView,button也不一定没有经过转换。

    新的KindOf特性能够轻松解决这种始料未及的情况。我们再回到实例属性上:
    @property (strong, nonatomic, nonnull) NSArray<__kindof UIView *> *someViews;  
    实际上我们已经告诉编译器:属性及其集合会出现一些UIView。这样在类型协议里显示更多我们之前看不到的信息。其本质向下转型(downcasting)。

    这意味着上述代码编译没什么问题,因为编译器知道集合里肯定会出现一个button。

    现在那些担忧就都解释得清了。

    虽然不喜欢Swift的人可能会刻意夸大Objective-C的优点,但如今两种语言实现了互相调用,这是Objective-C所有提升的最大价值所在,我们应该心存感激。

    毋庸置疑,Objective-C的确比以往更加强大。

    总结

    对我来说,Objective-C是开发生涯中的初恋,相比其他语言,它是那么与众不同——直到今天都是如此,它的好、它的坏都让我欲罢不能。虽然如今Swift正以迅雷不及掩耳之势征服着我的心,我还是希望Objective-C陪伴在身边。

    Objective-C的提升能够帮助开发者写出更好的代码,这是好事。而且这些优势已经在Foundation中随处可见了。
     
    来源:csdn 收起阅读 »

    招人不易留人更难 创业团队要闯哪些关?

    嘉宾简介:马晓宇,环信CTO,18年的老程序员, 先后从事过 IC设计软件,短信网关、电信网管、中间件、手机操作系统和手机App的研发。从2004年开始从事开源软件的开发,参与了Apache,Eclipse,Symbian fundation等开源社区。在创办...
    继续阅读 »
    嘉宾简介:马晓宇,环信CTO,18年的老程序员, 先后从事过 IC设计软件,短信网关、电信网管、中间件、手机操作系统和手机App的研发。从2004年开始从事开源软件的开发,参与了Apache,Eclipse,Symbian fundation等开源社区。在创办环信之前,先后在Symbian、Nokia、微软等公司工作。
    公司简介:环信即时通讯云是移动即时通讯能力的云计算PaaS (Platform as a Service, 平台即服务) 平台服务商。环信将基于移动互联网的即时通讯能力,如单聊、群聊、发语音、发图片、发位置、实时音频、实时视频等,通过云端开放的Rest API 和客户端SDK 包的方式提供给开发者和企业。让App内置聊天功能和以前网页中嵌入分享功能一样简单。环信全面支持Android、iOS、Web等多种平台,在流量、电量、长连接、语音、位置、安全等能力做了极致的优化,让移动开发者摆脱繁重的移动IM通讯底层开发,极大限度地缩短产品开发周期,极短的时间内让App拥有移动IM能力。
    现场速记:
    马晓宇:大家好,我是环信的马晓宇 Johnson, 很高兴这个机会和大家交流。
    18年的老程序员,先后做过IC软件,电信系统,中间件,手机系统等;重度开源参与者,从2004年从事开源软件开发,参与了Apache,Eclipse,Symbian Foundation 等社区。创办环信前,在Iona,Nokia,Symbian,Microsoft 等公司工作,2001到2004年在美国工作,见证了第一次的互联网泡沫。

    个人是从何时开始的创业之旅,请分享下创业心得。

    马晓宇:2013年初看到移动互联网的爆发,结合我们在服务器端的长期积累,开始做一个移动互联网的BaaS平台,到最后聚焦在IM云平台创立环信。我们做的是面向企业的SaaS,确切的说是toD,对企业的SaaS服务.

    体会是两个:
    • 一是市场巨大:这两年在环信平台上,我们见证了新兴移动互联网app的爆发式增长,有些客户已经开始准备IPO,更多的公司经过各轮融资得到了快速发展。20%+的app都有付费能力,另外,大量的传统企业,像国美,链家等也开始使用我们的saas 服务,市场”钱景”广阔。
    • 第二个体会是过程刺激。心脏不好的没法做企业SaaS。尤其是像我们的IM 云服务和移动客服产品,都是和客户的业务系统紧耦合的,是他们服务的关键一环。对稳定性要求比人力资源评测,后台数据分析等服务要求高的多。从上线以来,用户每月增长100%造成的容量压力;PaaS 服务商的宕机;DDoS攻击;DNS 域名污染,甚至线上运维错误操作。
    介绍下环信目前的情况以及团队构成。在创业方向上环信是如何选择的呢?马晓宇:环信平台2014年5月上线,目前服务2万多App,日活几千多万,每天消息超过1亿条。公司现有100人,其中研发团队50多人。分为:移动端,IM后台,运维,音视频,大数据,移动客服几个team。起步是做移动互联网的BaaS(backend as service),在上面又做了企业IM产品,但发展不顺利,13年年底几个创始人闭门开会,决定聚焦在 IM 云服务。在即时通讯云发展起来之后,发现很多我们的客户都有移动客服的需求,去年年底开始开发移动客服saas 服务。您怎么看移动即时通讯平台技术的现状及发展趋势?马晓宇:两个趋势:融合通信和连接平台。即时通讯从只提供发送短信,图片到实时语音,实时视频。虽然现在还有牌照限制,最逐渐终会取代传统的移动网络。基于此技术的公共平台,现在是微信和Facebook主推的业务。不光是一个IM服务,而是用来连接生活的方方面面。环信的创新产品及重点项目有哪些?产品竞争力体现在哪些方面?下一步重点发展方向是什么?马晓宇:环信是第一个即时通讯云平台。但我们认为,接入IM,提供即时通讯服务只是第一步。我们在定义一个社交模型,通过定量定性分析,来帮助客户增加用户黏性,更好的做社交。同时我们也在重点推荐移动客服平台的开发。我们是开放的即时通讯云平台,支持千万级并发。环信下一步重点在IM方面是提供增值服务,包括反垃圾,数据挖掘等。同时,我们也在重点开发移动客服云服务。环信在开发移动即时通讯平台中经历过哪些经验教训?马晓宇:最主要是经验教训是用户爆发性增长和平台容量的矛盾,和由此推动的平台架构快速演进和扩容。从去年6月上线以来,每月用户量环比增长100%,推动平台快速演进。一年时间,后台架构演化到第6个版本。从教训角度来看,架构演化是无法一步到位的,一个比较实际的措施是压力测试。应该尽早的,经常性的做系统的压力测试,并且要保持比线上环境高几倍的压力。请您谈谈环信与开源技术的渊源,环信技术中都涉及哪些开源技术?马晓宇:环信的三个创始人都是开源社区的重度参与者,我们的平台也用到了大量优先的开源软件,从Kafka 消息队列,Storm 实时处理,到Spark 大数据挖掘。我们在开源方面的目标是在即时通信领域,结合我们的海量用户,打造一个开源的基础软件项目,并逐渐成为一个流行的开源项目,回馈技术社区。技术团队是什么样的氛围?工作模式是怎样的?马晓宇:总结一下就是压力、乐观、坦诚。创业团队事比人多,每个人都有足够的技术挑战。虽然遇到各种大大小小的困难,但大家每天工作气氛是乐观而幽默的。我们研发团队50多人,没有专门的管理人员,我是CTO,但每天主要大部分时间也是写程序。基本是工程师文化,没有KPI,讲究code wins。举几个具体了例子:有些同事一般下午才出现在公司,有的同事喜欢跑步,一看天气好,就去奥森跑步去了,当然跑完再继续工作。我们希望打造自组织的高效团队。下半年开始周三,周六work from home。希望到明年,team 更加成熟,实现有些同事期待在海南、普吉岛等地remote 办公,每年会北京开两次会。在培养技术人才方面,环信有哪些举措?马晓宇:我们有三个措施:
    • 第一内部交流:再忙也要做每周的技术分享,而且要高质量的,充分准备的。这个对年轻工程师帮助很大;
    • 第二外部交流。我们自己主办 技术沙龙meetup. 也鼓励技术人员多参加各种会议和线下活动,和同行交流,和比自己更优秀的人交流,这个有助于核心工程师的技术提高;这块其实一直有人提醒我,小心优秀的工程师被挖走。但帮助他们更优秀,在社区更认同是我的责任,如果留不来了,也是我工作中的不足了。
    • 第三是梯队培养:对重点的苗子,要越级使用,给比较大的技术挑战和压力,同时由技术负责人对他重点给予相关的指导和帮助。对年轻工程师,我们允许失败,但不允许犯同一个错误。
    现在创业公司大批量招人,在招聘过程中您遇到过怎样的瓶颈吗?如何找到优秀的技术人才,有什么好的建议?马晓宇:招聘上我们走了一些弯路。现在总结看,通过社招,通过猎头效果都不够好。团队本身就人手紧张,每周安排几个面试,但没有收获,比较浪费时间。我总结通过内部推荐、介绍和线下交流长期跟进最有效。比如我们移动端团队,就是symbian,nokai 同事逐渐互相推荐来的。对出色的技术人才,要长期跟进。最近我们有两个都是跟进了1年多,有了机会,邀请加盟的。另外,我们看好的候选人,都是优秀的技术人才,很容易得到 BAT的offer。这种情况下,就要靠工作内容、技术挑战打动他们,一起打造一个业界领先的SaaS平台。还有一个细节的地方是:JD中对要求和岗位责任描述要尽量清楚。每个岗位需要写一个专门的JD。创业团队该如何留住人?(换血问题)马晓宇:工作的吸引力主要有三点,不同工程师内心排序不同。
    • 第一是待遇。兄弟们没日没夜的跟你干几年,工资要above market rate。即便没时间花,但给家里有个交待。期权更要多给,公司如果能成功,主要原因是团队每天的拼搏和贡献的积累,而不是因为创始人或投资人。
    • 第二是发展。员工在环信的这2,3年技术水平等能不能有比较大的发展,跟上甚至超过公司的发展速度。我们是要求技术团队每人都得有一个6个月的发展目标,根据此目标,我和 team lead 来具体看怎么安排相关工作,并经常给予指导。
    • 第三是快乐。个人觉得最重要。团队成员每天能不能高兴的来上班,enjoy 工作中的各种挑战。另外,我一直尽量创造轻松幽默的工作氛围,team内部提倡简单直接的沟通方式。
    在公司发展过程中,“换血”也无法避免。不少创业公司都有类似问题,起步阶段创始人和各个team技术比较强,但整个团队技术水平和经验比较欠缺。环信2年前从车库咖啡起步,那时候还没有高大上的创业大街。水平不错的应聘者一来,一看是在一个咖啡馆办公,一般转身就走。再加上经费有限,那个阶段,我们只能招到大专毕业,甚至培训班毕业的员工。这样的团队结构,只能把产品做出来。公司发展起来后,对人员标准的目标变成要能做出技术领先的产品,并且能服务世界各地的用户,能用英语和海外开发者流利交流。为了解决人才瓶颈,最近一年我们逐渐对开发团队进行了“换血”。比如移动端team,开发的主力变成了 计算机专业研究生毕业工作10多年的经验丰富的工程师为主力。这样的中间力量才能支撑我们今后2,3年的快速发展。在团队逐渐调整过程中,早期的技术人员也没用流失,而是在更合适自身经验和能力的岗位成长。还是我们移动端的例子,核心的sdk core部分是几位10多年经验的Linux C++背景的同事负责,其他工程师负责在此基础上开发Android,iOS sdk 和App,也做的很出色。创业团队如何创造条件来更好的协调工作和家庭?马晓宇:环信团队平均年龄30多岁,很有几个40几岁的老程序员。大家都是上有老下有小,更好的协调工作和家庭是决定大家每天能不能来公司开心工作的关键。我们的经验有几点事业要获得家庭的理解和支持。让家里人理解我们做的事情,感受到整个团队的拼搏,也能看到我们未来3年的目标和可期待的收获。我多次给核心技术团队的家人们打电话,一打就是1,2个小时,主要是让他们理解外人开来一群酷爱编程的疯子每天在干的事情,汇报我们的发展和我们的目标。切实关心团队的家庭。家庭遇到什么具体问题,我们能怎么帮助。比如父亲病重,可以安排回老家远程工作1,2个月,边工作边照顾家人;买房首付不够,我们帮助借些钱周转;虽然平时我们没时间照顾小孩,环信工作时间比较灵活,孩子开家长会什么的,倒是爸爸去的比较多。推行work from home。我们是一周6天工作,但周六在家办公。下半年开始进一步推进周三也在家办公。一方面能节省路上的时间,另一方面能让大家在家的时间多一些,帮帮忙。要招聘合适创业团队的员工。我们自己的经验看,女生有小孩的,不适合创业公司的开发岗位。但能在销售、市场、人事等岗位做得很好。不过这些都是对团队来说的。做为创始人,根本无法协调工作和家庭了。我每天晚上11,12点下班,除了周日,都见不到小孩。互动环节: 
    • 最近腾讯云也推出了即时通讯产品,环信的产品和他们产品对比,有哪些不同?
    马晓宇:对,阿里去年年底开始搞openim,腾讯云最近也推出了类似服务,我们的区别主要开放和专注。他们的产品是云平台下面的一个小team 在搞,我们是一个整个公司focus 在上面。 
    • 请问一下没有KPI,那么你们怎么做绩效考核或者说激励的呢?
    马晓宇:我们每月会统计代码提交,但那是做为reference。team 每个人的效率和output,其实不需要领导打分,大家都知道。奖励是 team lead 给input,由管理层商量。 
    • 环信做为im平台,会切入移动办公类的工具或系统开发吗,类似阿里钉钉之类的。

     马晓宇:不会,我们只做平台,不做产品。我们希望借鉴开源团队的管理方式。每个人完成的feature,做的技术分享,checkin 的代码质量,其实team 都在看着。 收起阅读 »

    2015中国SaaS生态“元素周期表”

    去年以来,SaaS市场持续火爆,吸引了无数创业者或者投资机构的关注,为此我们特别策划了这期2015中国SaaS生态“元素周期表”的专题,希望从一个比较直观的角度勾勒出2015年中国SaaS大生态,共谱中国SaaS大势。以SaaS为代表的企业云端应用,正在改变着...
    继续阅读 »

    去年以来,SaaS市场持续火爆,吸引了无数创业者或者投资机构的关注,为此我们特别策划了这期2015中国SaaS生态“元素周期表”的专题,希望从一个比较直观的角度勾勒出2015年中国SaaS大生态,共谱中国SaaS大势。以SaaS为代表的企业云端应用,正在改变着整个IT的格局。各种各类的SaaS的应用,这两年就从来没有离开过人们的眼球。今年以来,融资超过千万美金的SaaS企业比比皆是,包括今目标、销售易、雅座等,而主打企业SaaS应用的众多初创企业也纷纷拿到数额巨大的融资,可以看到,中国SaaS市场从来没有像今天一样火热。其实,深究SaaS为什么可以得到投资人和用户的青睐,这和SaaS本身的特点是分不开的,由于其资费、用户体验等方面相对传统应用而言,具有不可比拟的优势,使得SaaS应用的用户积累速度要远远超过传统应用的拓展速度。

    SaaS市场投融资市场的火爆也催生了众多不同类型的SaaS企业的出现、包括OA协同、CRM、HR、ERP、安全等等,另外,我们也看到SaaS模式在物流交通、医疗、教育、农业等领域同样得到越来越多的应用。因此,我们特别策划了2015中国SaaS生态“元素周期表”,希望从一个比较直观的角度勾勒出2015年中国SaaS大生态,共谱中国SaaS大势。


    1.jpg


    通过前后一个月左右的时间,我们绘制了这张中国SaaS生态“元素周期表”,我们征求过很多业界专家的意见,反复修改,终于成型,在此一并谢过。当然,国内SaaS企业众多,无法全部囊括,我们只是筛选出其中的典型代表,后续我们会继续完善。

    当然绘制这张SaaS生态“元素周期表”并不是我们的全部,我们还从时下最火的SaaS企业中邀请到一些CTO给我们分享了他们企业自己在SaaS实践过程中的一些实战经验以及爬过的坑。 当然,无论企业级市场有多火,我们的用户才是真正有发言权的,所以我们还特别邀请到一线的SaaS用户,让他们谈谈自己在使用SaaS过程中的体验,实践经验和面临的一些问题。我想,这些干货是很多沙龙和meetup上看不到的,而这正是目前SaaS企业的领导们和技术客们喜闻乐见的,这就是价值。
     
    实战解读

    团队协作工具Worktile技术架构揭秘: Worktile自上线两年多以来,以良好的用户体验和稳定的服务,获得了用户的认可和喜爱。目前,已经有超过10万家团队在使用Worktile。作为团队协作工具,从技术上分析首先要解决如下几个问题:

    • 基于Web的跨平台设计,让用户在任何地方都可以随时通过浏览器访问

    • Web形态的产品要具有原生客户端的体验,如任务的拖拽等

    • 具有高效的实时消息系统,每个团队成员在Worktile中所做的任何操作,都要实时在其他成员的客户端中自动刷新

    • 服务要稳定,稳定压倒一切那么Worktile是如何做到这几点的?点击上面蓝色字体,有你想知道的。


    让餐厅放心的云服务-雅座CRM技术解密:雅座CRM历经9年的成长,累计为超过15000家餐饮门店提供精准营销服务,管理超过5000万会员数据,日交易流水超百万笔,年交易额达200亿以上。 雅座提供专业的企业级SaaS云服务,对系统的安全性、稳定性、可靠性要求极高,这是企业的基本诉求。同时,基于用户交易和消费行为的数据分析,是精准营销的核心,如何快速处理海量数据,进行多维度、低延时的统计分析、数据挖掘,对系统性能和可伸缩性提出了更高的挑战。CRM的目标是数据营销,需要提供各种纬度的灵活的查询分析。举例来说,餐厅一个简单的需求,希望根据消费时间、性别、消费金额筛选出目标客户,随着数据量增大,仅靠关系数据库分库分表和索引优化已经难以满足企业的效率要求。高弹性、易扩展的大数据处理能力,在CRM云服务中日趋重要。本文雅座CTO对其CRM系统架构做了深度分享。
     
    以下内容节选自《程序员》电子刊:

    移动端企业IM系统优化:imo在PC端IM领域有很强的积累,但在做移动端时遇到了不少的挑战。在移动端相对恶劣的运行环境加上企业IM的特殊性(高及时性,大数据量),使得许多之前行之有效的经验水土不服,引发了若干问题,通过一些系统重构以及针对性的定位处理,问题得到了解决,本文重点介绍imo遇到的这些问题以及相应的处理经验。

    聚焦用户体验,dayHR云存储技术背后思考:dayHR是理才网公司的核心产品,是基于移动互联、云计算和 SaaS服务的人才资本管理云平台。作为一家典型的SaaS供应商,并且是提供企业级应用的SaaS供应商,主机是理才网最重要的核心资产,肩负着向用户提供接入服务,存储用户关键业务数据的使命,其重要性不言而喻。在众多的主机部署方案中,主机托管和云主机租用是众多SaaS供应商最主流的两种选择。到底是主机托管还是云主机租用呢?本文分享了dayHR是如何抉择的,并提出了自己的思考。

    基于公有云平台打造TB级海量文件备份系统:企业业务稍微上点规模的,IT系统产生的数据很容易就超过TB级,并且资料文档等很容易超过亿级别的规模,如果用手动复制的方案来备份,基本是非常困难的;这种情况下,即使购买一些专业系统,随着数据量日益增大,跑起来也非常吃力。本文重点讨论如何基于云平台来实现对应的解决方案。

    SaaS用户心声

    泛OA,2B-SaaS的主场:OA系统基本上是国内产品的天下,这在IT领域非常少见,大多数领先的IT产品和IT技术都源自美国,学自美国。不知是不是因为没有美国榜样,总之中国的OA系统市场巨大,没有霸主,需求广泛,成功罕见。 作为一个企业的信息化负责人,想找到一款满意的OA系统非常困难。不论是百里挑一,还是一见钟情,选择了OA之后,总会发现实施难度比计划中大很多,使用效果比想象中差很多,难堪大用,游走在用和停用的边缘。虽说信息系统项目实施本就困难重重,需要一把手支持,需要打破部门墙,但我认为根本原因其实是OA产品不够好。 OA系统梦想很大,现实很小,说OA的痛点,其实就是说OA的方向。能解决这些痛点的OA,将是管理系统领域的王者,不论是私有部署的传统OA还是SaaS版泛OA。以上节选自金山软件CIO的分享。

    传统企业SaaS应用的五个误区:随着互联网快速普及和发展,进一步加速了企业的数字化建设,作为较慢拥抱互联网的传统企业也越来越多的加入到企业数字化升级转型行列。提升效率,降低成本,增强软实力,成为吸引众多传统企业实施 SaaS应用的重要因素,然而不同企业的实施结果却大相径庭,很多传统企业走入了SaaS应用的五个重要误区。本文来自味多美集团味多美集团首席电子商务官的深度分享。

    结语

    中国的中小企业的运营情况和美国并不一样。在美国,很多企业即使只有很小规模,也都可以稳定的运行几十年,因此他们有能力持续购买相应的SaaS服务。但是在中国,短期的(1-3年的)企业占据了中小企业数量的绝大多数,而这就造成了SaaS软件繁荣的假象,虽然前期会花很大的成本获取了客户,但是由于这些客户很短的生命周期,不见得能够在较长时间之内获得稳定的收入,甚至不足以平衡早期的客户获取成本。

    虽然进入2015年以来,各种企业级SaaS应用的投资热潮一浪高过一浪,但是我们还是坚持认为,国内的SaaS目前还是早期阶段,需要更多的培育和成长引导。在资本的驱动下,未来几年内会有更多的传统软件厂商以及新的SaaS厂商进入这个领域,为企业级应用市场带来百花齐放的变革,真正能够为客户提供更专业、更全面的企业信息化服务。
     
    内容来源:csdn 收起阅读 »

    WorktileCTO揭秘:团队协作工具Worktile技术架构

    Worktile自上线两年多以来,以良好的用户体验和稳定的服务,获得了用户的认可和喜爱。截止笔者写这篇文章的时候,已经有超过10万家团队在使用Worktile。作为团队协作工具,从技术上分析首先要解决如下几个问题: 基于Web的跨平台设计,让用户在任何地方...
    继续阅读 »
    Worktile自上线两年多以来,以良好的用户体验和稳定的服务,获得了用户的认可和喜爱。截止笔者写这篇文章的时候,已经有超过10万家团队在使用Worktile。作为团队协作工具,从技术上分析首先要解决如下几个问题:

    • 基于Web的跨平台设计,让用户在任何地方都可以随时通过浏览器访问

    • Web形态的产品要具有原生客户端的体验,如任务的拖拽等

    • 具有高效的实时消息系统,每个团队成员在Worktile中所做的任何操作,都要实时在其他成员的客户端中自动刷新

    • 服务要稳定,稳定压倒一切



    那么Worktile是如何做到这几点的?今天笔者在这篇文章里一一为大家揭秘。

    SPA设计

    先来说说Worktile中SPA(单页应用程序)设计,作为团队协作工具,需要尽可能减少用户在不同页面之间的跳转,所以从一开始我们就决定Worktile必须是单页应用程序,当时面临的选择有很多,首先我们考虑使用大名鼎鼎的Backbone.js,但是很快又抛弃了,因为在实际使用中Backbone.js太复杂,另一方面开发效率太低,最终我们选择了Google出品的AngularJs,下面这幅图是AngularJS的结构图:


    1.jpg


    选择它主要基于以下几点考虑:

    1. 自动化双向数据绑定功能,这一点在Worktile中非常重要,如任务的状态变化都要实时变更到其他成员,如果具有自动化双向数据绑定功能,只需要绑定到UI的数据源发生变化,UI会自动发生改变,不需要工程师再通过代码去修改UI元素的改变,如下面这段代码:
    ng-class="{1:'task-completed-style'}[task.completed]">
    id="task_check_{{ task.tid }}"
    wt-click="js_complete_task($event, entry, task)">


    {{task.name}}
    2. 语义化标签,AngularJS在设计之初信奉的理念就是:当编写UI的同时又需要编写业务逻辑时,声明式的代码远比命令式代码要好,命令式的代码更适合写业务逻辑,AngularJS在设计上就通过语义化的标签把对DOM元素的操作和逻辑代码分离,如我们需要展现一个任务列表,只需要下面这段代码即可:

    class="slide-trigger"
    hide_action="true"
    ng-click="locator.openTask(task.pid, task.tid)">

    3. 模块化设计,AngularJS堪称模块化设计方面的典范,通过模块化设计我们可以非常好的实现Worktile的工程化,在Worktile中涉及的元素非常多,如有项目、任务、日程、文件、话题、文档等等,而这每一个元素都可以设计为一个模块,如下所示:
    (function () {
    'use strict';
    angular.module('wtApp', [
    'wt.project.ctrl',
    'wt.team.ctrl',
    'wt.task.ctrl',
    'wt.event.ctrl',
    'wt.post.ctrl',
    'wt.file.ctrl',
    'wt.page.ctrl',
    'wt.mail.ctrl'
    ]);
    }());
    4. 引入依赖注入,依赖注入是面向对象中比较成熟的设计模式之一,为了解决面向对象中依赖问题,得到了广泛的应用,AngularJS中大胆使用了依赖注入,极大的减少了各个模块之间的依赖问题:
    taskListCtrl.$inject = ['$scope', '$stateParams', 
    '$rootScope', '$popbox',
    '$location', '$timeout',
    'bus', 'globalDataContext',
    'locator'];
    结合以上特点,我们最终决定了前端框架使用AngularJS来实现,从Worktile上线两年多的表现来看,我们的选择无疑是正确的。当然AngularJS也有一些缺点,在实际使用中还是要根据具体的产品类型来选择使用,另外AngularJS 2.0也已经初见端倪,和AngularJS 1.0有很大的不同,感兴趣的同学可以先去尝鲜一下。
     
    服务设计

    我们再来看看Worktile的后台服务设计,Worktile的整体服务架构设计如下图所示:


    2.jpg



    其中前端部分在上面的SPA一节中我们已经说过了,下面一一分析下其他的服务:

    1.  API服务,包括Web API、Mobile API、Open API,这些都运行于NodeJS之上,选用NodeJS的原因主要是它的异步事件驱动,对于高并发的支持比较好,另外一个原因是使用简单,对于前后端可以使用同一门语言去开发。

    2.  缓存和队列服务,Worktile中的缓存和队列服务都是基于Redis来实现,Redis是一款非常优秀的开源缓存服务,并且可以选择基于内存还是进行数据持久化,它提供的pub/sub模型对于Worktile来说非常重要,对于一些实时性要求不高的处理,我们都是在Redis中pub一条消息,告知其他服务有数据发生了变化,那些服务在接收到Redis中的消息后,根据消息的类型决定应该如何做出处理。

    3.  数据库服务,Worktile产品本身的特点决定了它是一个对实时性和性能的要求,远超过对事务性要求的产品,所以在选择数据库时,我们选用了MongoDB数据库,性能高,集群方便,数据以BSON结构存储,和Node.js天生完美结合。

    4.  文件预览服务,使用Worktile的同学肯定知道在Worktile中所有的文件都可以做到无需下载到本地,而直接在线查看,这一切都是预览服务的功劳,因为文件类型的各种各样,在实现文件预览时也要根据文件的类型做出不同的处理,针对txt、pdf、代码片段等文本型的文件,我们只需要读取文件中的内容,然后再前端用相应的视图展现出来即可,相对比较简单。但是对于Office类型的文件,如ppt、doc、xls等文件,就不能这么简单的处理,我们希望文件在Worktile中查看的效果和用户在本地使用Word、Excel、PowerPoint查看的效果差不多,经过我们的调研,最终选用了微软官方提供的Office Web App服务。

    消息推送

    消息推送服务是Worktile最核心的服务之一,前面提到过作为一款团队协作工具,要能够实现非常好的实时性,任何数据的变化都需要及时变更到团队所有成员当前所在的视图,如下面这幅图,是一个典型的任务看板,团队所有成员可能同时在操作当前项目中的任务,每个操作引起看板的变化都会实时更新,不需要用户做任何刷新操作:


    3.jpg


    为了达到这种效果,需要在Web客户端和服务器之间维持一个长连接,当有任何改变发生时,给客户端发送不同的消息,告知客户端哪些数据发生了变化,如下面是我们为任务定义的消息中的其中几个:

    实现实时消息推送,有以下几种方式可供选择:
    on_task_trash            : "on_task_trash",
    on_task_complete : "on_task_complete",
    on_task_move : "on_task_move",
    on_task_update : "on_task_update",
    on_task_comment : "on_task_comment",
    on_task_badges_file : "on_task_badges_file",
    on_task_unarchived : "on_task_unarchived",
    on_task_badges_check : "on_task_badges_check"
    1.  短轮询,页面端通过js定时异步刷新,这种方式优点在于实现简单,但实时效果较差。

    2.  长轮询。页面端通过js异步请求服务端,服务端在接收到请求后,如果该次请求没有数据,则挂起这次请求,直到有数据到达或时间片(服务端设定)到,则返回本次请求,客户端接着下一次请求,这种方式对于服务的要求较高,尤其在并发量很大的情况下,对服务端的压力很大。

    3.  Websocket。浏览器通过websocket协议连接服务端,实现了浏览器和服务器端的全双工通信。需要服务端和浏览器都支持websocket协议。

    在Worktile一开始我们选用了Socket.IO作为消息服务,但是随着访问量的增大,需要做集群化的时候感觉到力不从心,尤其对于Socket.IO状态数据的存储,由于并没有官方的解决方案,当时我们采用了一个第三方的开源项目,使用Redis来存储,引起了一些性能上的问题,在后来重构时选用了基于Erlang语言的开源XMPP服务ejabberd作为我们的消息服务。

    ejabberd是xmpp协议的一种实现, xmpp广泛应用于即时通信领域。Xmpp协议的实现有很多种,比如java的openfire,但相较其他实现,ejabberd的并发性能无疑使最优秀的。Xmpp协议的前身是jabber协议,早期的jabber协议主要包括在线状态(presence)、好友花名册(roster)、IQ(Info/Query)几个部分。现在jabber已经成为rfc的官方标准,如rfc2799, rfc4622, rfc6121,以及xmpp的扩展协议(xep)。Worktile就是基于XEP-0124、XEP-0206定义的BOSH扩展协议。

    由于自身业务的需要,我们对ejabberd的用户认证和好友列表模块的源码进行修改,通过redis保存用户的在线状态,而不是mnesia和mysql。另外好友这块我们是从已有的数据库中(mongodb)中获取Worktile中项目或团队的成员。Web端通过strophe.js来连接(http-bind),strophe.js可以以长轮询和websocket两种方式来连接,由于ejabberd还没有好的websocket的实现,就采用了BOSH的方式模拟长连接。整个系统的结构如下:


    4.jpg


     
    作者:李会军 收起阅读 »

    值得推荐:理解 JavaScript 的原型链和继承

    instanceof 运算符可以用来判断某个构造函数的prototype属性是否存在另外一个要检测对象的原型链上1   什么意思呢? 来个题Function instanceof Object;用高中数学的话就是把x,y代入公式得: insta...
    继续阅读 »
    instanceof 运算符可以用来判断某个构造函数的prototype属性是否存在另外一个要检测对象的原型链上1
     
    什么意思呢?

    来个题Function instanceof Object;用高中数学的话就是把x,y代入公式得:

    instanceof 运算符可以用来判断Object的 prototype属性 是否存在Function的 原型链 上。
    等等,斜体字的这俩到底是什么鬼意思?

    prototype属性是原型链吗?

    JS是基于原型链面向对象语言,也就是说所有对象都是以对象为模板创建实例的。如果是其他oo语言的背景比如Java或Ruby,都习惯于创建一个class模板,class创建object实例。比如ruby:
      class A
    def initialize name @name = name end
    def to_s
    @name
    end
    endputs A.new('hehe') # => hehe
    这里的类A就是所有 A.new 创建出来的实例的模板而已。而对于原型链语言JS来说,同意的事情要这样做
    function A(name){  this.name = name
    }
    A.prototype.toString = function(){ return this.name
    }var a = new A('hehe')
    console.log('object name is:' + new A ('hehe')) // => object name is: hehe


    • 这里的怪怪的函数其实就是constructor,相当于ruby例子里的initialize

    • 而prototype上的方法toString也就是类似class模板上的方法。


    为什么要把方法绑到prototype上?直接 A.toString…= 不行吗?
    在解释prototype之前,先解释一下 new A 到底发生了什么2:
    1: // var a = new A('hehe') =>2: var a = new Object();3: a.__proto__ = A.prototype; (proto)4: A.call(a, 'hehe');
    其中 A.call 的意思是先把A的this设置为a,然后执行A的body也就是this.name=name

    但是 __proto__ 又是什么

    __proto__ 才是原型链

    __proto__ 是内部 [ [Prototype ]] (说了半天原型链这就是牛逼闪闪的 原型链, 指向对象或者null)的getter和setter方法(已加入ES6规范3,但是还是建议只使用Object.getPrototypeOf())

    JS对象能使用它原型链对象的所有方法,比如所有的对象的原型链(的原型链的原型链的原型链…)都最终会指向Object(或null)。因此,所有的对象都能使用Object.prototype上的方法,比如我之前覆盖掉的 toString 本身就是Object.prototype上的方法,如果没有覆盖,它是可以拿到所有Object上的方法的:
    a.toString === A.prototype.toString // truea.toLocalString === Object.prototype.toLocalString // truea.__proto__ === A.prototype // true
    所以,现在是否可以理解这句话了呢
    instanceof 运算符可以用来判断Object的 prototype属性 是否存在Function的 原型链 上。

    所以instanceof其实就是
    Function.__proto__ === Object.prototype// false
    擦,假设失败了呢,让我们来看看为什么不对,Function.__proto__到底指哪去了
    Function.__proto__ === Function.prototype//true
    原来指向自己的prototype了呢,那就意味着…
    Function instanceof Function//true
    yes,然而 Function instanceof Object似乎也能解释了
    Function.__proto__ === Function.prototypeFunction.__proto__.__proto__ === Object.prototype
    所以如果我们让
    Function.__proto__.__proto__ = nullFunction instanceof Object//false
    这回知道为什么不要用 __proto__ 了吧,一不小心重写了会导致所有继承自它的对象都受影响。
    为了养成良好的习惯,实际项目最好使用 getPrototypeOf 取原型链,这里只是为了方便我采用__proto__
    下面来看第二个题
    Object instanceof Function
    难道可以互相链吗?这意味着
    Object.__proto__ === Function.prototype// true// 但是Firefox取不到Object.__proto__, 看来做了保护,必须要用// Object.getPrototypeOf(Object) === Function.prototype
    要晕了, 忍不住要画个图


    1.png

    多简单呢,一共就分别有两类:

    原型链指向Function.prototype的函数们

    原型链指向Object.propotype的对象们

    而原型链顶端的Object.prototype就再没有原型链了,所以是空

    现在再回头看题目是不是so easy了。

    也没什么卵用得 contructor

    如果你好奇的在FireFox Console中看一下 a 除了刚才那些玩意,还有一个奇怪的东西


    2.png

    话说 A 里面这个constructor是个什么鬼,我们来玩它一下
    a.constructor === A.prototype.constructor
    A.prototype.constructor === A
    A.prototype.constructor = nulla.constructor // => nulla instanceof A // true
    这只是函数都有的一个玩意而已, 由于js的函数可以作为构造器,也就是可以 new ,所以所有的 函数的prototype.constructor都指向自己,因此所有的 new 出来的对象也都有一个reference能找到自己的构造器。

    然而除了这个功能也并没有什么卵用嘛。

    真的是这样吗?
    .

    ..



    ….

    …..

    ……

    …….
    恩,真的!

    Bonus 继承

    下面这个是babel 从es6 class
    class A{
    constructor(name) { this.name= name
    }
    toString() { return this.name
    }
    }class B extends A {
    toString(){ return this.name + 'b'
    }
    }
    编译出来的ES5继承
    function _inherits(subClass, superClass) { 
    // 密}var A = (function () { function A(name) { this.name = name;
    }

    A.prototype.toString = function toString() { return this.name;
    }; return A;
    })();var B = (function (_A) { function B() { if (_A != null) {
    _A.apply(this, arguments);
    }
    }

    _inherits(B, _A);

    B.prototype.toString = function toString() { return this.name + 'b';
    }; return B;
    })(A);
    其他地方都不用看了,inherits 函数用到了之前学到的所有玩意,要求实现要满足下列所有的cases,就当是课后练习了:
    var a= new A('A');var b= new B('B');
    a.constructor === A &&
    b.constructor === B &&
    a instanceof A &&
    b instanceof A &&
    b instanceof B


    • https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/instanceof

    • 这里只是意思,但是如果真的改变 __proto__ 是非常低效的https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto

    • http://www.ecma-international.org/ecma-262/6.0/#sec-additional-properties-of-the-object.prototype-object



    Author: Jichao Ouyang 收起阅读 »

    不算“真正的语言”?详说Swift 2.0中的错误处理

    苹果公司在今年的全球开发者大会(Worldwide Developers Conference, WWDC)上宣布推出Swift2.0,该语言的首席架构师Chris Lattner表示,Swift 2.0主要在语言基本语法、安全性和格式美观度这三方面进行了改进...
    继续阅读 »
    苹果公司在今年的全球开发者大会(Worldwide Developers Conference, WWDC)上宣布推出Swift2.0,该语言的首席架构师Chris Lattner表示,Swift 2.0主要在语言基本语法、安全性和格式美观度这三方面进行了改进。除了这些新的功能特性,还有对语法的优化、修饰及美化,最后是Swift 1.x中最具影响力的错误处理机制。
     
    历史一瞬:不起眼的开端

    我们都知道,Swift语言作为Objective-C当前替代语言被推出,是OS X和iOS应用程序开发的“通用语”。在最初的版本中,Objective-C没有原生的异常处理机制。后来通过添加NSException类,还有 NS_DURING, NS_HANDLER和 NS_ENDHANDLER宏才有了异常处理。这种方案现在被称为“经典的异常处理”,还有这些宏都是基于setjmp()和longjmp()这两个C语言函数的。

    异常捕获(exception-catching)看起来如下所示,在NS_DURING和NS_HANDLER宏之间抛出的任何异常都将会导致在NS_HANDLER和NS_ENDHANDLER宏之间执行相应的代码。
    NS_DURING  
    2. // Call a dangerous method or function that raises an exception:
    3. [obj someRiskyMethod];
    4.NS_HANDLER
    5. NSLog(@"Oh no!");
    6. [anotherObj makeItRight];
    7.NS_ENDHANDLER
    下面是立刻能触发抛出异常的方法(现在仍然可用):

    [cpp] view plaincopy
    1.- (void)someRiskyMethod
    2.{
    3. [NSException raise:@"Kablam"
    4. format:@"This method is not implemented yet. Do not call!"];
    5.}
    可以想象,这种手工处理异常的方式戏弄的是早期Cocoa框架程序开发人员。但是这些程序员还不至于到这份儿上,因为他们很少使用这种方式。无论在Cocoa还是Cocoa Touch框架下,异常通常都被归为灾难性的,不可恢复的错误,比如程序员造成的错误。上面的-someRiskyMethod就是很好的例子,由于实现部分没有准备好而引发了异常。在Cocoa和Cocoa Touch框架中,可恢复的错误由稍后讨论的NSError类来处理。

    原生的异常处理

    我想由于Objective-C中的经典异常处理机制对应的手工处理方式让人感觉闹心,于是苹果公司在Mac OS X 10.3(2003年10月)中发布了原生的异常处理机制,彼时还没有iOS系统。这本质上是将C++的异常处理嫁接到了Objective-C。异常处理的结构目前看起来是这样的:
    @try {  
    2. [obj someRiskyMethod];
    3.}
    4.@catch (SomeClass *exception) {
    5. // Handle the error.
    6. // Can use the exception object to gather information.
    7.}
    8.@catch (SomeOtherClass *exception) {
    9. // ...
    10.}
    11.@catch (id allTheRest) {
    12. // ...
    13.}
    14.@finally {
    15. // Code that is executed whether an exception is thrown or not.
    16. // Use for cleanup.
    17.}
    原生的异常处理使你有机会为每个异常类型指定不同@catch部分。无论@try结果如何,@finally都要执行其对应的代码。

    尽管原生的异常处理如所预期的那样抛出一个NSException异常,但是最明确的方法还是“@throw ;”语句。通常你抛出的是NSException实例,但说不定什么对象会被抛出。

    NSError

    尽管Objective-C原生与经典的异常处理有许多优点,但Cocoa和Cocoa Touch框架应用程序开发人员仍然很少使用异常,而是限制程序出现程序员所导致的不可恢复的错误。使用NSError类处理可恢复的错误,这种方法早于使用异常处理。Swift 1.x也继承了NSError的样式。

    在Swift 1.x中,Cocoa和Cocoa Touch的方法和函数可能不会返回一个布尔类型的false或者nil来表示一个失败(failure)的对象。另外,NSErrorPointer对象会被当作一个参数返回特定的失败信息。下面是个典型的例子:

    cpp] view plaincopy
    1.// A local variable to store an error object if one comes back:
    2.var error: NSError?
    3.// success is a Bool:
    4.let success = someString.writeToURL(someURL,
    5. atomically: true,
    6. encoding: NSUTF8StringEncoding,
    7. error: &error)
    8.if !success {
    9. // Log information about the error:
    10. println("Error writing to URL: \(error!)")
    11.}
    程序员所导致的错误可以用Swift标准库(Swift Standard Library)函数fatalError("Error message”)来标记,将其在控制台记录为错误消息并无条件中止执行。还可以使用assert(), assertionFailure(), precondition()和preconditionFailure()这些函数。

    Swift第一次发布时,一些非苹果平台开发人员已经准备好了火把和干草叉。他们声称Swift不能算是“真正的语言”,因为它缺乏异常处理。但是,Cocoa和Cocoa Touch社区对此不予理睬,我们知道NSError和NSException那个时候就存在了。就我个人而言,我相信苹果公司仍然在思考实现错误和异常处理的正确方式。我还认为直到问题解决了,苹果公司才会公开Swift源码。这一切问题在Swift 2.0中全被扫清了。 
     
    Swift 2.0中的错误处理

    在Swift 2.0中,如果想要抛出错误,那么抛出的对象必须符合ErrorType协议。可能正如你所愿,NSError就符合该协议。枚举在这里用来给错误进行分类。
    enum AwfulError: ErrorType {  
    2. case Bad
    3. case Worse
    4. case Terrible
    5.}
    然后如果一个可能抛出一个或多个错误的函数或方法会被throws关键字标记:
    func doDangerousStuff() throws -> SomeObject {  
    2. // If something bad happens throw the error:
    3. throw AwfulError.Bad
    4.
    5. // If something worse happens, throw another error:
    6. throw AwfulError.Worse
    7.
    8. // If something terrible happens, you know what to do:
    9. throw AwfulError.Terrible
    10.
    11. // If you made it here, you can return:
    12. return SomeObject()
    13.}
    为了捕获错误,新型的do-catch语句出现了:
    do {  
    2. let theResult = try obj.doDangerousStuff()
    3.}
    4.catch AwfulError.Bad {
    5. // Deal with badness.
    6.}
    7.catch AwfulError.Worse {
    8. // Deal with worseness.
    9.}
    10.catch AwfulError.Terrible {
    11. // Deal with terribleness.
    12.}
    13.catch ErrorType {
    14. // Unexpected error!
    15.}
    这个do-catch语句和switch语句有一些相似之处,被捕获的错误详尽无遗,因此你可以使用这种样式来捕获抛出的错误。还要注意关键字try的使用。它是为了明确地标示抛出的代码行,因此当阅读代码的时候,你能够立刻找到错误在哪里。

    关键字try的变体是“try!”。这个关键字大概也适用于那些程序员导致的错误。如果使用“try!”标记一个被调用的抛出对象中的方法,你等于告诉编译器这个错误永远不会发生,并且你也不需要捕获它。如果该语句本身产生了错误(error),应用程序会停止执行,那么你就要开始调试了。
    let theResult = try! obj.doDangerousStuff()  
    与Cocoa和Cocoa Touch框架间的交互

    现在的问题是,你如何在Swift 2.0中处理爷爷级的NSError API呢?苹果公司已经在Swift 2.0中为统一代码行为作了大量工作,并且已经为未来写入Swift的框架准备方法。Cocoa和Cocoa Touch中可以产生NSError实例的方法和函数有苹果公司的签名( signature),可以自动转换为Swift新的错误处理方式。

    例如,这个NSString的构造器( initializer)在Swift 1.x中就有以下签名:
    convenience init?(contentsOfFile path: String,  
    2. encoding enc: UInt,
    3. error error: NSErrorPointer)
    注意:在Swift 2.0中,构造器不再被标记为failable,它并不需要NSErrorPointer来做参数,而是使用抛出异常的方式显式地指示潜在的失败。

    下面的例子使用了这种新的签名:
    do {  
    2. let str = try NSString(contentsOfFile: "Foo.bar",
    3. encoding: NSUTF8StringEncoding)
    4.}
    5.catch let error as NSError {
    6. print(error.localizedDescription)
    7.}
    注意错误是如何被捕获的,并且如何被转换成了一个NSError实例,这样你就可以获取与其相似API的信息了。事实上,任何ErrorType类型的实例都可以转换成NSError类型。

    最后说说@finally

    细心的读者可能已经注意到,Swift 2.0引入了一个新的do-catch语句,而不是do-catch-finally。不管是否捕捉到错误的情况下,你如何指定必须运行的代码呢?为此,现在可以使用defer语句,用来推迟代码块的执行直到当前的作用域结束。
    // Some scope:  
    2.{
    3. // Get some resource.
    4.
    5. defer {
    6. // Release resource.
    7. }
    8.
    9. // Do things with the resource.
    10. // Possibly return early if an error occurs.
    11.
    12.} // Deferred code is executed at the end of the scope.
    Swift 2.0将Cocoa和Cocoa Touch的错误处理机制凝聚为具有现代风格的用法,这是一项伟大的工作,也会使许多程序员倍感亲切。统一行为是不错的定位,会使Swift语言和其所继承的框架逐步发展。
     
    文章来源:Big Nerd Ranch 收起阅读 »

    大家怎么实现自定义表情的 有谁说说吗 我是这么实现的 不完美啊

    但是不完美  有人有更好得方法吗  求分享
    但是不完美  有人有更好得方法吗  求分享

    全球扫货指南集成环信移动客服:订单量客单价双丰收

    移动互联网时代,同时迎来了全民创业的时代,虽然这两者不能划上等号,但不能否认,移动互联网的普及,给全民创业提供了更多的创新灵感,也赋予了电商更多活力。笔者了解的一些电商,已完全摒弃PC端接入口,而只从移动端进行接入。 在传统大型平台电商的窗口已经被...
    继续阅读 »
    移动互联网时代,同时迎来了全民创业的时代,虽然这两者不能划上等号,但不能否认,移动互联网的普及,给全民创业提供了更多的创新灵感,也赋予了电商更多活力。笔者了解的一些电商,已完全摒弃PC端接入口,而只从移动端进行接入。


    1.jpg


    在传统大型平台电商的窗口已经被逐渐关闭的时候,新入场的玩家必须借助移动端和社交实现弯道超车,移动电子商务公司“全球扫货指南”便是中国移动互联网发展的其中一家受益企业,其市场总监左小禛便认为:电子商务的未来是移动电商,而移动电商必须重视移动客服。

    移动电商的三个关键点

    的确,百度无线数据报告显示,移动互联网创业者开发经验不足1年的人数比例为38.3%,个人开发者比例明显上升,同时11—20人团队开发比例下降,移动开发者生态从量变向质变迁移。此外,移动互联网创业者对商业模式的探索和创新尚无特定模式可以借鉴。上述状况下,移动电商创业者如何实现弯道超车?笔者认为,以下三个关键点需要重点把握:

    1、转变思维,认清客户在哪?

    移动互联网时代用户数的迅猛增长,已是必然趋势。用户数的急速增长,意味着巨大的机会,同时也意味着巨大的挑战,终端的小型化、多样化,接入方式的多样化都意味着我们处在全新的互联网生态环境中。

    Gartner预测,到2017年年底,超过70%的交易将来自于移动端。2014年阿里双十一的现场监控显示,总成交额571亿其中移动端贡献了243亿,移动端交易量比例将有超过PC端的趋势。同时,京东2014年第四季度财报显示移动端的订单量占比接近40%。

    因此,移动互联网时代,电商行业应转变思维,认清客户来源趋势,应在移动端的各个接口做好整体布局,无论是营销、服务还是流程,应进行相应梳理。

    2、移动互联网的营销,社交为王!

    但在移动互联时代,营销渠道越来越多。过去的营销是通过电视、报纸等渠道跟消费者沟通,但移动互联网时代则是分享的时代,免费思维已成为主流,为了让用户喜欢,愿意分享,消费者和商家会直接面对面进行免费试用与体验,通过各种活动进行赠予、使用,增强体验。这也使移动互联网时代的电商营销成本非常巨大。

    移动互联网时代的营销除了普通的宣传、引导、试用、免费等传统方式外,更多的具有社交化属性,用户体验变得如此重要,即时通讯所具有的实时性、互动社交性让移动电商更具活力。甚至很多商家都搭建了基于兴趣社交的板块辅助自身电商平台,通过社区导购来降低用户的购买决策成本,在非标品等方面与传统大电商平台竞争获取优势实现弯道超车。

    3、移动互联网的客户服务,体验为王!

    营销的成功,只能带来一定的流量,但真正的交易与再次销售,则一定是产品本身具有的价值及客户服务所带给客户的体验。我们经常说,客户在哪,客户服务就要跟到哪。客户在移动端,移动端的客户服务如果不到位,不但订单丢失,客户丢失,甚至公司也可能被那些更重视移动端的用户服务体验的公司,更能迅速把握时代大趋势的公司所颠覆。一项研究报告指出,如果做不好客服,辛辛苦苦通过各种渠道引流到自己App、网站、平台、账号的客户,95%都会流失掉。

    因此,电商已从PC端转战到了移动端,移动端有其特定的消费属性,无论是营销与服务,应从移动端的消费属性来研究。

    移动电商的客服趋势

    如果说电商的移动性趋势已得到行业认可,各个大、中型电子商务公司正在奋力奔跑在移动端,正在全力争夺消费者手机上不多的APP安装上。但笔者需要提醒大家的是:太多企业过于重视营销,而对客户服务有所忽视。

    客户服务的重要性已不需要赘述,笔者认为移动电商客服有几个趋势将带动电商企业的发展:

    1、 多渠道融合,尤其以移动端为主的客服请求将占主导

    客户服务请求来源包括传统呼叫中心的语音、基于网页的实时在线聊天系统、工单系统、微博、微信等等。客户来源的多样性,让多渠道融合客服成为必须。另一方面,正如上文所述,如今的消费者正在远离PC和电话,消费者都去了移动端,所以客户服务将以移动端客服请求为主导。

    2、 即时通讯(IM)将是最适合移动设备的客服服务形式

    微信已成为我们最重要的日常沟通形式,界面简单易操作,不需要任何培训,人人都会使用,最重要的是,这是最适合移动设备的沟通方式。互联网女皇发布的《2015互联网趋势报告》也认为: IM不仅是世界上标准化程度最高的互联网产品,而且是世界上下载和使用量最大的互联网产品,也是用户交流体验最好的产品。异步又实时、个性化又主流、表达能力很强但又迅速等等。

    传统400电话虽然也方便迅速,但笔者也经常因为400电话的无尽等待而挂机。虽然对12306这样的订票刚需企业影响不大,但如是电商企业,那客户流失率就太高了。因此,即时通讯式的客服形式非常适合移动设备,一个发送就能即时接送信息,按一个按钮就得到服务,可以秒级接通,并且可以得到7X24小时随时随地的解答。不用去填写工单,也不用在APP中遇到问题的时还要跳出APP外通过电话,邮件,微信,QQ等方式才能后被解决。

    3、智能客服技术将得到大量应用

    上文提到了即时通讯式的客服形式非常适合移动设备,移动互联网时代,客户手机24 小时随身携带的属性决定了传统5 X8小时的服务形式早已满足不了客户需求。客户需要实现一个发送就能即时接送信息,可以秒级接通,并且可以得到7X24小时随时随地的解答。我们可以想象的是,这个7X24小时随时随地的服务并不是企业派了足够多的人工座席在为客户提供服务,而是智能客服技术的一项应用。

    智能客服技术是实时聊天的一种技术应用,因为即时通讯沟通方式最大的优势是可以一对多,即一个客服坐席可以同时和多个人聊天,使用自动菜单导航,语义分析,机器人智能应答,智能知识库等技术的大面积应用,“智能机器人+知识库”可以帮助回答80%的常见问题,可大量减少传统座席人员数。

    移动电商客服的三大难点透析

    通过笔者对移动电商客服的几个趋势的梳理,我们看到,移动电商的消费群体的特定性,让移动客服与传统客服具有很多的不一致性,移动客服如需要做精做透,以下流程是难点:
     1、 集中的质检系统

    传统语音客服因为可以通过录音、检索等方式进行客户服务质量检测,移动客服的即时通讯性、多渠道接入等属性,使客服的质量把控具有一定的难度。

    2、 交易行业的大数据积累与分析

    大量的移动端客服数据与传统来自于呼叫中心、Web端、微博、微信的客服数据,如何进行统一接入、积累与分析,进行数据挖掘实现商业转化,这是较大的难点也是最重要的商机,客户趋动才是需求的起点,是创新的动力。

    3、 即时客服需要即时的信息管理

    移动互联网时代,服务的即时性也对管理的即时性提出了很高的要求。移动电子商务公司全球扫货指南市场总监左小禛便深有体会:“移动电商经常会定期或者不定期举行一些活动,活动举办期间,服务请求较平常可能会有十倍甚至更多倍的增长,这样的环境下,如何去调配座席人员?如果知道何种渠道来源的增长比例?服务过程中出现了哪些问题?哪些是共性问题等等。移动环境下,即时客服要求有即时的信息管理。我们采用了环信移动客服,解决了我们客服过程中的很多难题。“

    全球扫货指南的移动客服初体验

    全球扫货指南是全球首家时尚买手制购物平台。平台上有各类买手推荐的奢侈单品,产品的价格搜索引擎可以帮助用户一键比价,比完之后觉得划算就可以找靠谱买手下单购买。全球扫货指南作为交易平台,实行第三方担保机制,若买卖双方发生纠纷,提供先行赔付。在CEO肖宇眼里,随着这几年电商的蓬勃发展,用户线上消费习惯正在快速被培养。目前客单价千元以上的电商玩家并不多,另一方面用户的消费升级不断加速,奢侈品购买呈年轻化,因此在手机上消费的客单价越来越高,将会给轻奢市场带来巨大的机会。
     
    据左小禛介绍,全球扫货指南接入了这种智能移动客服产品后,可以实现快速注册、根据体验指南一两分钟内即可对接商家完成会话体验,同时实现了跨平台多渠道接入:支持 App、微信公众账号、微博、网页等,均可以快速统一接入客户服务后台管理。

    其次,满足了开放性与自定义信息:这种新型的移动客服实现了代码开源、UI开源,还提供多套UI模版,这样便于与全球扫货指南自身的APP快速集成,平滑接入。同时第三方集成功能也很强大,可与第三方工单、知识库、CRM 系统等进行扩展集成。

    第三,富媒体消息交互体验:移动客服平台提供了基于IM技术的类似微信体验的友好富媒体消息交互,不仅可以实时收发文字、表情,还可以即时收发图片、位置、实时语音、还可自定义消息,大大方便了与客户的沟通交流。

    第四,精准客户画像功能:移动客服的IM沟通帮助全球扫货指南辅助判断客户需求与诉求,通过自定义客户分类标签,客户再次访问时可获知客户的类型。并且还支持自定义会话小结,根据会话小结统计会话的分类,通过会话小结追踪客户诉求。通过轨迹分析功能,即通过发送客户访问页面的轨迹,判断客户意图,获取客户个性化细节,了解客户基础信息,分析客户行为,可以极大提高订单效率。

    第五,“智能机器人+智能知识库”:作为一套智能化的客服系统,全球扫货指南建立了基于业务的智能知识库,智能辅助归结业务信息和应答客户信息,历史常见问题系统梳理,提高客服效率。“智能机器人+智能知识库”组合目前可自动回复80%常见问题,随着智能知识库的不断训练,这一比例能够提高到90%。

    第六、真正实现不丢订单:环信基于IM长连接技术,帮助全球扫货指南实现超线拉取排队会话,让等待时间过长或有订单需求的客户得到优先服务,提升客服效率,即使客户关闭会话,退出App,甚至关闭手机,基于IM长连接技术依然能找回客户会话,提升客服效率,不丢客户订单。同时,基于IM长连接技术,即使在断网或复杂网络切换时也依然能找回客户会话,不丢客户订单。

    第七、实现了质检系统透明管理:移动客服自带实时监控系统,可实时监控当前所有会话,管理员在线质检,在线查看会话信息,还提供了历史会话查询、质检考核。通过实时与历史查看,可以统计出客服代表的接入量、在线时间及应答等待时间。

    通过销售部和技术部返回的数据报告显示,左小禛判断,通过部署这种新型智能移动云客服,较于传统客服产品节省成本约60%,省电省流量高达80%,同时留住了70%会话客户,订单量和客单价均获得了不同幅度提升。目前全球扫货指南覆盖全球100个顶级奢侈品品牌,超过10万个热门单品。根据贝恩咨询的数据,中国人去年一年消费奢侈品3800亿元,其中70%在海外消费,仅代购市场就超过750亿元,奢侈品的海淘电商无疑是块很诱人的蛋糕。

    移动客服的魅力,从上述数据的发布可看出,已超出了大家的想象!原因在于:传统客服体系下,客服只是成本中心,辅助部门;而在移动互联网时候下,客服俨然已成为核心流程之一,竞争力关键要素之一。

    一位客服领域大佬曾这样总结这个时代:“伴随着客户互动的革命,从呼叫中心演变到的客户中心作为不断扩展的客户交互平台概念一直经历着深刻的变革。运营日益规模化,精准化、多通路化、智能化和普适化。作为集语音和非语音渠道为一体,人工与智能服务共协同,物理与数字的通路大融合,随着以客户理念,人文为中心时代的来临,客户服务中心正从企业价值链的一测走向价值传递的中央,与惊艳的产品研发一起发挥着客户体验创造的核心角色。”

    移动客服,你已不能再等待! 收起阅读 »