Ease3.0SDK 与EaseUI3.0 集成汇总 (卡壳的朋友们可以看看,已顺利集成成功)
首先 ,SDK 集成 ,很多人集成用cocoapods 来集成。一开始 我也是用的Cocoapods.但是出了很多问题。捯饬了很长时间也没有弄出个所以然,所以果断放弃了。目前状况,建议朋友们不要用Cocoapods来集成 。
在SDK 集成的时候 要注意这样几点:
1、注意一下SDK 下的 lib文件夹 因为 里边有两个SDK 一个是有实时语音的 一个是没有实时语音的 。你用哪个就删掉另一个。
2、 注意Build settings下的 bitcode 要设置为NO ,因为 暂时 环信SDK 不支持bitcode编码。
3、注意Build settings 下的other linker flags 这里 如果你设置了-ObjC 就不要设置 文档里-force_load 路径
关键是要注意other linker flags下的其他设置。我之前是因为 里边 cocoapods 加载了一个-all_load字段 我删除这个 ,就解决问题了 。我相信 有很多朋友 也有这个字段 删掉就可以了 。
总体来讲 SDK 集成 成功与否 ,只需要看这三点就够了。
下面说下 EaseUI集成 。我按照视频走到建完.pch文件。发现出现了8个错误 。这里 我去3.0EaseUI Demo 里 搜了下 .pch文件 发现有两个 居然 然后 参考了一下 发现有很多错误 具体 怎么试的 就不说了 直接上代码吧 .pch代码如下 :
#import <Availability.h>
#ifndef __IPHONE_3_0
#warning "This project uses features only available in iOS SDK 3.0 and later."
#endif
#ifdef __OBJC__
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "EMSDKFull.h"
#import "EaseUI.h"
#define NSEaseLocalizedString(key, comment) [[NSBundle bundleWithURL:[[NSBundle mainBundle] URLForResource:@"EaseUIResource" withExtension:@"bundle"]] localizedStringForKey:(key) value:@"" table:nil]
#define DEMO_CALL 1
#endif
以上就是 新建的PrefixHeader.pch中的代码 。
建完这个 你会发现 错误变成了一个。EaseMob 引用头文件not find 直接删掉这个头文件引用 。你会发现 又有了一个新的错误 NSObject +EaseMob 这个类中 出现了N个错误 。这里 不管它 直接删掉这个类 这个类是P作用都没有的 (我是挨个对比3.0Demo 的类 才发现 Demo 中 根本没有这个类)
做完了这步 。运行 ,恭喜你 集成环信3.0SDK,环信EaseUI 成功!!!!
收起阅读 »
【有奖调查】环信编程大赛奖品建议征集
编程大赛开赛距今已有半月,在这半个月时间里,感谢为此奋斗的每位小伙伴。
今天已经公布了决赛提交地址,不知道各位小伙伴们的项目是否已经完成?
还没写完的小伙伴也不要着急,时间还很充裕,项目提交截止是4月15日。刚来的小伙伴现在报名还来得及^_^^_^^_^
今天刚公布就已收到数十份项目,写的都很不错(这可怎么评呀o(╯□╰)o),这里就不一一表扬了!
这里给大家分享一个数据
大赛开赛前一周,每天近一百的报名量
幸福与烦恼共存着
编程大赛已公布奖品
大奖有限的几个,怎么能辜负了其他小伙伴们呢?
收集群里小伙伴建议
看来大家对技术书籍比较在意,感谢“华章图书”赞助了若干技术书籍
部分技术书籍(书籍还在整理,图片有些模糊,请点击原图查看)
不知道各位小伙伴们对大赛奖品还有什么中意的呢?
请在下方直接留言评论,我们将邀请您来到颁奖现场!(颁奖典礼除了已经公布的大奖,只要报名参赛的小伙伴到场均有神秘礼品赠送哦^_^^_^^_^) 收起阅读 »
我为什么给文章付费
图文无关
1.我有一种习惯。
阅读完一篇文章,如果从中得到了某种启发,或是单纯地很喜欢这篇文章,我会为其付费。(很多平台称这为打赏,但我并不喜欢这个透露着狂傲自大名词。任何一种创造都应该值得被尊重。)
讲真,我以为支付宝等在线支付的便捷手段出现,会使为创造付费会成为一种习惯。但是,我错了。
2.这个想法的出现,有两个原因。
一是前两天我读了梁欢的随笔集《我说的不一定对》,提到一个故事。他和的创业团队做了一个游戏,在国外的付费软件下载榜获得不错的成绩,口碑也很好。但是,当这个游戏传到国内的时候,一个网站就传出了它的破解版安装包,造成他们的巨大经济损失无法挽回,更令人惋惜的是使一个创业团队就此解散。
作为一个致力于游戏开发的成长版程序员,这个经历对我的触动非常大。
另一个原因是,前天,我给简书的一篇文章付费后,收到作者的一条短短的简信“太感谢了!!”。我觉得奇怪。难道是付费的人太少了,以至于收到一个读者的阅读费用会如此激动?
当然,亦可能是作者单纯地觉得这是读者对自己的一个鼓励,内心的激动难免,与钱无关。
总之,这使我开始思考一个问题。为什么我们都不习惯为无形的知识和创造付费?
3.举一个例子。
在十几年前,我们想要在家看电影,会先攒着一笔钱咬着牙买一台碟机和各种DVD,对着屏幕心满意足。但是,如今各种视频门户网站的影视众多,人们却开始变得吝啬。
“woc就看这么个破电影还要付费?!”
“看个剧还要充会员,你咋不上天?!”
资源极大的丰富,使人们越来越习惯于双眼一闭、两手一伸地索取,付费像是一种愚蠢的行为——你傻啊,这东西在某某网站可以免费下载,还去花那冤枉钱!
这种现象折射的一种心理便是,无形知识与创造不是一种宝贵的东西。我可以免费获得,为什么还要为此付费?
梁欢在《我说的不一定对》一书中,用他这个创业的经历做了一个有趣的比较。
有一个团队做出了一款付费游戏,但是不就一个网站就将它破解了,免费供人下载,瞬间下载量飙升。团队做出的游戏甚至没有获得开发的费用,解散了。
你会为此而愤怒吗?
先别急着回答。
又有一个水果商店,里面放着许多西瓜。但是某天有人将商店的锁撬开了,一时间人潮汹涌,西瓜就这样被抢光了。水果商店因此破产。
你感到愤怒吗?
如果答案是肯定的,那么不防再想一下。
你对谁而愤怒?撬锁的人,还是抢西瓜的人?
自始至终,人们没有将无形的知识和创造视为一种值得被购买的商品。
4这使我想起了在知乎上挺热门的问题
“设计师觉得最悲哀的事或者最悲哀的时刻是什么?”,热门回答多是某亲戚或某朋友请自己做一个logo或是设计某个东西,拿到成品之后没有支付酬劳或是表露感激,更有甚者觉得“不就是随便画几笔吗居然还要收钱怎么这么矫情”。
事实上,你理所当然索取着的免费产品,是别人花着你无法想象的时间与精力去学习的结果。
这些你都一无所知。又或许你根本不想知道。
因为,这和自己又有什么关系呢?
“没有关系”是一种很可怕的东西。当你拒绝接受对另一个领域的知识时,偏见就会由此产生了。
“你文章写得那么好,帮我写个广告宣传词吧,不用很长的……什么?还要收钱?(不就几个破字值那么多钱!)”
“你是画画的是吧,帮我设计个logo吧……就是画几笔的东西你收什么钱啊真是!又不是外人。(就是外人要收钱才来找你的嘛。)”
呵呵哒。
我会说,要不你自己来试一下?
这时他们又会说:“要是我会就不用找你啦!”
呵呵呵呵哒。
所以亲爱的,有时间的话,不如多去了解下不同领域的知识吧。
另,
看到喜欢的文章就选择为其“付费”吧´_>`
作者:Leoipaang 收起阅读 »
【美团外卖首页效果】三行代码轻松集成
原理介绍:
要想把一个view设计成透明的我们一下子就会想到两种方案,设置view的alpha值为0,或者设置view的backgroundColor为clearColor.但是UINavigationBar是一个比较特殊的视图,它是没有alpha属性的,那我们可以设置opaque(不透明度)为NO,上代码试一试.
//方案一:不透明度为NO结果,然并卵,完全没用。这时候该怎么办呢?这时候我们就得来看看UINavigationBar这个视图的结构了,如下图。
navigationBar.opaque = NO;
//方案二:背景颜色为clearColor
navigationBar.backgroudcolor = [UIColor clearColor];
现在笔者教大家一个小技巧。请看下面代码:
- (void)clearNavBar{这时候再打开项目层次图,你会有惊人的发现
//设置一张空的图片
[self.navigationController.navigationBar setBackgroundImage:[[UIImage alloc]init] forBarMetrics:UIBarMetricsDefault];
//清除边框,设置一张空的图片
[self.navigationController.navigationBar setShadowImage:[[UIImage alloc]init]];
}
对比一下,你会发现只剩两层了。不要问为什么,这都是系统帮你做的。。。当你设置了背景图片的时候,就会出现这样的结果。
知道了上述的原理,这就好办了,现在只要监听,控制器内部的scrollView 的滚动,就可以实现导航条渐渐透明的效果了。
业务逻辑,功能实现其实都不是很难。但是也需要花费一些时间,笔者在这给大家分享一下自己写的一个分类。导入这个分类,你只需要调用两三个接口就可以实现这个功能了。
首先看一下分类提供的接口
分类介绍
我写的这个分类不仅可以在系统的UITableViewController 和UICollectionViewController中使用,(系统的只需调用分类中两个方法即可)。而且当你的UIViewController中有1个或多个可以垂直滚动的scrollView都可以使用。(需要告诉控制器需要监听哪个scrollView的滚动,即设置keyScrollView).
重要的是,这个分类的代码侵入性非常低,使用简单方便。当不需要这些功能的时候,你只需要注释掉两三行代码即可。
下面这个效果图是系统的UITableViewController,以下是效果图和代码
代码:
分类接口
#import <UIKit/UIKit.h>
@interface UIViewController (NavBarHidden)
@property (nonatomic,weak) UIScrollView * keyScrollView;
/** 清除默认导航条的背景设置 */
- (void)clearNavBar;
/** rate将决定颜色变化程度,值越大,颜色变化越明显,rate的取值范围是0.01 - 0.999999 isAlpha 决定导航条上的内容是否需要透明*/
- (void)scrollControlRate:(CGFloat)height colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue isNavBarItemAlpha:(BOOL)isAlpha;
@end
控制器代码
#import "TestViewController.h"
#import "UIViewController+NavBarHidden.h"
@implementation TestViewController
- (void)viewDidLoad{
[super viewDidLoad];
//清除默认导航条的背景颜色
[self clearNavBar];
//设置当有导航栏自动添加64的高度的属性为NO
self.automaticallyAdjustsScrollViewInsets = NO;
//设置tableView的头部视图
UIImageView * imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 0, 250)];
imageView.image = [UIImage imageNamed:@"1.jpg"];
self.tableView.tableHeaderView = imageView;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
//rate将决定颜色变化程度,值越大,颜色变化越明显,rate的取值范围是0.01 - 0.999999
[self scrollControlRate:0.5 colorWithRed:0.0 green:1.0 blue:0.0 isNavBarItemAlpha:YES];
}
控制器代码如下
#import "TestCollectionController.h"使用注意点,一定要在添加好collectionView,再设置keyScrollView,至于为什么,这个就不需要笔者解释了吧
#import "UIViewController+NavBarHidden.h"
@interface TestCollectionController ()<UICollectionViewDataSource,UICollectionViewDelegate>
@property (nonatomic,weak) UICollectionView * collectionView;
@end
@implementation TestCollectionController
-(void)viewDidLoad{
[super viewDidLoad];
//1.清除默认导航条的背景颜色
[self clearNavBar];
//2设置当有导航栏自动添加64的高度的属性为NO
self.automaticallyAdjustsScrollViewInsets = NO;
//3.设置导航条内容
[self setUpNavBar];
//4.创建collectionView,初始化,并添加到self.view上
[self setUpCollectionView];
//5.告诉程序是根据哪个scrollView的滚动来控制状态栏的变化
self.keyScrollView = self.collectionView;
[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
}
滚动监听代码
#warning 监听滚动,调用框架接口项目源码分享,希望大家喜欢,下载的时候顺便star一下,好人多福。https://github.com/newyeliang/HYNavBarHidden.git
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
[self scrollControlRate:0.7 colorWithRed:1.0 green:0.0 blue:0.0 isNavBarItemAlpha:YES];
}
收起阅读 »
贪吃精灵小游戏demo
下了班,闲着没事,写了两个小demo分享给大家练练手.一个通过简单动画完成的,另一个是绘图.你能1个小时写完俩个吗,在不参考源码的情况下,那说明你的动画和绘图掌握的很不错了.要是没能写出来,也不需要气馁,多敲敲你就掌握了.
下面这个是贪吃精灵小游戏demo的效果图,这只是一共才200行代码的一个小demo哦.怎么样,看效果还挺不错吧!
源码链接https://github.com/newyeliang/EatDoudou欢迎star
·核心代码
//判断方向,往不同的方向移动
- (void)moveAnimation{
CGPoint center = self.eat.center;
switch (self.direction) {
case DirectionUp:{
self.eat.image = [UIImage imageNamed:@"3"];
[UIView animateWithDuration:0.05 animations:^{
self.eat.center = CGPointMake(center.x,center.y - self.speed);
}];
[self result];
}
break;
case DirectionLeft:{
self.eat.image = [UIImage imageNamed:@"2"];
[UIView animateWithDuration:0.05 animations:^{
self.eat.center = CGPointMake(center.x - self.speed,center.y );
}];
[self result];
}
break;
case DirectionDown:{
self.eat.image = [UIImage imageNamed:@"4"];
[UIView animateWithDuration:0.05 animations:^{
self.eat.center = CGPointMake(center.x,center.y + self.speed);
}];
[self result];
}
break;
case DirectionRight:{
self.eat.image = [UIImage imageNamed:@"1"];
[UIView animateWithDuration:0.05 animations:^{
self.eat.center = CGPointMake(center.x + self.speed,center.y );
}];
[self result];
}
break;
default:
break;
}
}
游戏结果判断代码
//计算游戏的分数,判断是否超出边界
- (void)result{
//eat 和 doudou相交,分数+100
if (CGRectIntersectsRect(self.eat.frame,self.doudou.frame)) {
//移除原来的豆豆
[self.doudou removeFromSuperview];
self.speed += 1;
self.scoreLabel.text = [NSString stringWithFormat:@"Score: %d",(int)(self.speed - 3) * 100];
//添加新的豆豆
self.doudou;
}
//超出边界,游戏结束
if ( CGRectGetMaxX(self.eat.frame) > self.backgroundView.bounds.size.width ||CGRectGetMaxY(self.eat.frame) > self.backgroundView.bounds.size.height||CGRectGetMinX(self.eat.frame) < 0||CGRectGetMinY(self.eat.frame) < 0) {
[self.timer invalidate];
[self.eat removeFromSuperview];
//game over 提示框
UILabel * deathTip = [[UILabel alloc]init];
deathTip.text = @"Game Over!!!";
deathTip.backgroundColor = [UIColor whiteColor];
[deathTip sizeToFit];
[self.backgroundView addSubview:deathTip];
deathTip.center = self.backgroundView.center;
[UIView animateWithDuration:4.0 animations:^{
deathTip.alpha = 0.0;
} completion:^(BOOL finished) {
[deathTip removeFromSuperview];
}];
}
}
第二个是个太极图,看起来是不是很简单,你能画出来吗?打开Xcode试试吧!!!
没有任何业务逻辑,只需要你认真仔细的绘图,就OK了
·核心代码
源码链接https://github.com/newyeliang/TaiJIAnimation.git
//绘制太极图
- (void)drawImage:(CGSize)size{
float mid = size.width/2;
//1.开启图像上下文
UIGraphicsBeginImageContext(size);
//2.获取上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//3.绘图
//3.1 绘制黑色的半边
CGContextAddArc(ctx, mid, mid, mid, - M_PI_2, M_PI_2, 0);
CGContextAddArc(ctx, mid, mid + 0.5 * mid, mid * 0.5, M_PI_2, -M_PI_2, 1);
CGContextAddArc(ctx, mid, 0.5 * mid, mid * 0.5, M_PI_2, -M_PI_2, 0);
[[UIColor blackColor]set];
CGContextFillPath(ctx);
//3.2绘制白色的半边
CGContextAddArc(ctx, mid, mid, mid, - M_PI_2, M_PI_2, 1);
CGContextAddArc(ctx, mid, mid + 0.5 * mid, mid * 0.5, M_PI_2, -M_PI_2, 1);
CGContextAddArc(ctx, mid, 0.5 * mid, mid * 0.5, M_PI_2, -M_PI_2, 0);
[[UIColor whiteColor]set];
CGContextFillPath(ctx);
//3.3绘制白色的小圆
CGContextAddArc(ctx, mid, 0.5 * mid, 0.2 * mid, M_PI,- M_PI , 1);
CGContextFillPath(ctx);
//3.4绘制黑色的小圆
CGContextAddArc(ctx, mid, 1.5 * mid, 0.2 * mid, M_PI,- M_PI , 1);
[[UIColor blackColor]set];
CGContextFillPath(ctx);
//4.获取生成的图片
UIImage *image=UIGraphicsGetImageFromCurrentImageContext();
//5.显示生成的图片到imageview
self.backgroundColor = [UIColor colorWithPatternImage:image];
UIGraphicsEndImageContext();
}
收起阅读 »
今天妹子直播的视频已上传
观看地址http://community.easemob.com/video/19
把您想听的,想了解的通过下方评论留言告诉我们。对于环信直播有任何意见建议欢迎随时提出。
环信在线直播时间为每周四下午三点。每周四下午三点。每周四下午三点。 收起阅读 »
【高仿微信】基于环信SDK,Github 1,591 Star
Social APP is popular all over the world, such as: Facebook, Line, Whatsapp, Kakao.
You still worry about their own project social module? You also thinking WeChat function is how to achieve? Don't worry, come and look at this! This project is a high copy WeChat, and based on WeChat do to some experience and UI optimization.
您还在为自己的项目社交模块烦恼吗? 您还在琢磨微信的功能是怎么实现的吗? 别愁了,快来这看看吧!
本项目为高仿微信,并在微信基础上对一些体验和UI上做了优化,IM聊天模块基于环信IM SDK,
实现功能有:
好友之间文字聊天,表情,视频通话,语音,语音电话,发送文件等。
群聊,从通讯录添加好友,二维码扫描添加好友,好友之间二维码扫描转账,
微信公众账号消息推送、朋友圈等
GitHub 代码下载,点击这里
APK下载地址,点击这里下载体验
QQ交流群:476988719
收起阅读 »
【转载】组合式测试:移动测试服务的发展趋势
由于国内移动设备和系统版本的碎片化,移动测试对于应用的质量保证变得至关重要,同时也催生了一批提供第三方测试服务的创业公司,BAT也都发布了自己的测试服务。但是,单一的测试服务往往不能完全满足开发者需求,测试服务的提供商也都在探索满足开发者需求的新方式。
自动化测试不能满足开发者需求
因为碎片化原因,开发者不可能手动测试所有的移动设备和系统版本,因此自动化测试对于移动测试来说是必须的。传统的第三方测试服务就是从这一点入手,以庞大 的云端真机测试为卖点,受到了开发者的认可。在社区里,自动化测试也最受关注,自动化测试的框架层出不穷,如何搭建自动化测试系统、编写测试脚本的内容最 受欢迎。一时间,自动化测试有一种彻底取代人工测试的势头。
但是,自动化测试实际上存在着一些问题,导致它并不实用,至少不能完全满足开发者的需求。据顾昕彪介绍,自动化测试的主要问题有:
新的功能很难做自动化测试。自动化测试大多数的作用是回归以前已经稳定下来的功能,对于一个新的功能,开发完以后要编写相应的测试用例,再进行自动化测试,这个时间比人工测试更长,因为人工测试可以直接开始测试,自动化测试有一个编写过程。
自动化测试需要有一些测试用例的积累,在版本大的迭代之后,很多测试用例可能就失效了,需要重新编写。因为移动应用发版很快,测试用例维护成本相对比较高。
自动化测试质量取决于编写测试用例的人的能力。有些时候测试用例能通过,但实际功能并不能用,要避免这点需要有丰富的测试经验和对移动开发的透彻的理解,而这对测试人员的要求太高了。
因此,自动化测试只能帮助开发者解决一部分兼容性问题,通常为了保证质量,开发者仍然需要采取其它测试手段。
施佳樑认为,人工测试之所以没有被市场所重视,是因为第三方人工测试服务的成本太高,如果能把人工测试的成本降下来,那么开发者还是会选择更有效的方式来满足测试需求,众测解决了这个问题。
众测成为测试工程师的业余职业
众包测试是在国外兴起的一种测试模式,通过将测试分配到多人手里,从而解决碎片化问题,并且避免自动化测试的一些弊端。
施佳樑介绍道,他们的众测平台拥有1500万用户,在这些用户中经过培训筛选,筛选出1000多个测试专家。这些测试专家已经能够像专业的测试人员一样,提供标准的测试报告来帮助开发者定位问题。
值得一提的是,这些测试专家里有些本来就是专业的测试人员,比如百度众测里会有百度的测试工程师利用业余时间来帮助别人做测试。事实上测试是一个需要经验和知识积累的职业,一般的众测人员只能模拟普通用户,效率较低,只有专业的测试人员才能高效的找出问题并提出报告。
通过众测这种模式,开发者能够以较低的成本请到多个较专业的测试人员进行测试,而测试工程师也能够在业余时间用职业技能赚些外快,这是一个双赢的事情。笔者认为这很可能成为众测模式的发展方向。
移动应用测试的未来:一体化服务
自动化测试和人工测试结合,能够得到一个较好的测试结果。但是,有一些情况没有包含在其中,比如应用crash,不借助辅助工具,要定位问题仍然比较困难,而crash上报服务正是为解决这个问题而生。
另外,对于应用性能,特别是不同网络条件下的应用表现的监测,使用应用性能管理服务(APM)更加有针对性。
要使用第三方服务来完全测试一个应用里可能出现的问题,开发者需要注册不同的服务,登录不同网站的管理后台来进行,这显然是很不方便的。而提供所有这些服务,同时将它们整合起来,将是移动测试服务未来一段时间的发展方向。
届时,开发者将只需登录一个网站,提交一次应用就可以得到一个多维度的、完整的测试报告,只有发展到这个阶段,移动测试服务才真正满足开发者的需求。
基于全球首创的对象识别技术,TestBird可以为客户提供深入到移动APP&游戏内部所有功能的深度解析能力。通过自助功能测试、远程真机调试、真机兼容性测试、真人体验测试、 真人压力测试和崩溃分析等产品,TestBird建立了云手机、云测试和云分析三大测试平台,为移动应用提供从研发到上线再到运营的一站式质量管理服务,帮助移动应用企业建立完善的质量管理体系和能力,全面提高移动应用的DAU、留存率以及付费情况。 收起阅读 »
环信推出红包功能,打造全民社交新玩法
让所有的App都能有属于自己的红包,国内最大的即时通讯云平台环信正式推出了红包功能,同时环信即时通讯云也是行业首家支持红包功能的产品。接入环信红包功能零费用,全方位适配移动端,仅需一天即可快速集成。将为兴趣社交、婚恋招聘、生活服务、移动电商、教育医疗、游戏等各大行业App量身打造最接地气的场景化社交服务。
环信此次通过红包功能这一全民所追崇的社交交互形式,致力于帮助中小型App解决留存率低、日活低、运营难等问题。在红包主题、节日互动的带动下,增强用户体验,提高用户粘性,将App产品体验发挥到极致。
单身狗追女生无从下手,《撩妹大全》没教你怎么办?求职者想向猎头/企业HR请教问题,如何能成功引起他们注意?同圈层、同爱好兴趣的人们聚到一块儿,怎么促进一下深度交流?网游装备太贵,买了就得吃土,怎么让卖家给我友情价?——发个红包,一切SO EASY!打开社交坚冰,升职加薪走上人生巅峰,都可以从发一个红包开始。
目前,已有十余家App企业内测了环信红包,据某招聘行业龙头App CTO反馈数据显示,在集成了环信红包功能以后,用户粘性和活跃度获得了明显提升,日活数据更是获得了15-20%的提升。据悉,环信红包功能仅仅是其改变社交玩法的第一步,环信即将联合“云账户”上线包括品牌特定主题红包及商家卡券等更多增值服务和新玩法,将为移动互联时代的App社交和变现提供更多的想象空间。
最后,亲们抢完红包请一定大力喊出“谢谢老板”哦!体验环信红包,请猛戳:http://www.easemob.com/downloads 收起阅读 »
感谢热心开发者@北京大鼓书意见反馈--Android语音文字切换输入的优化
在3.0的uidemo
还有一些3.0的ui 聊天小用户体验细节问题
第194行代码,官方demo是toggleFaceImage ,这样点击表情笑脸不会自动切换软件键盘。改成我这样,可以在表情面板和键盘相互切换
还一个是setModeKeyboard方法,官方的这个里面的代码 editText.requestFocus();根本不起作用。
在最后一行改成我这样才可以在 “按住说话” 和 键盘之间切换
各位小伙伴们在集成过程中有任何意见建议欢迎随时提出,我们会及时作出处理,并赠送神秘大奖的哈!
收起阅读 »
环信首席架构师:做业务系统如何成长为架构师?
之前说到在『在行』开了个聊天话题『如何成长为一个合格的架构师』。前段时间有个朋友找到我,问了个非常典型的问题。
图片来源:Live Business Art Board
他说:『我现在在做偏业务开发方向的工作,在平时需要如何积累基础服务和系统架构方面的经验和知识。 』
很显然他意识到了两种系统的区别,而且正在试图转型。然而我知道,他也走进了一个让人难以反驳的认识误区,这就是,因为业务系统技术要求不高,所以开发人员在走向架构师的路上成长缓慢。
业务系统技术要求有多高
如果说从门槛来看,业务逻辑确实是最容易写的代码。产出好量化,功能又好测试。就算真的坏了,系统一般不会因此垮掉。只是,门槛低并不意味着容易做好。
有一种工作是API设计与实现,行话叫『包接口』,也是很多同学刚毕业的第一份工作。这事说起来简单,只要调用方跟被调用方协商一致即可,但是真正做的时候你会发现很多问题。
调用方首当其冲。如果命名混乱,找到想要的接口和参数就会变得很难。而如果你错误码定义得不够清晰,调通一个接口将会变成一个令人崩溃的事情。
被调用方也没有轻松到哪里去。如果没有遵循正交原则,那么你每个接口都可能涉及后端的很多资源调用和库的引用,导致服务不可避免得变大。一个资源的变化,都将有可能会影响到很多接口,这对回归测试和问题排查都将是一个灾难。
如果你在做一个平台,情况会变得更加严重。抽象不足的话,用户的每一个需求都会变成新的接口。而一旦发布出去,你就要保持其兼容性,也就是说,这辈子都是你的接口了。如果开始的时候没考虑到版本,那么恭喜你,从此要转行技术支持了。
这方面微信的开放平台接口,基本算是一个反例。返回数据JSON和XML混排,超出限制后无响应!?可惜的是,由于平台变大,作为调用方的开发者只能被欺(qiang)负(jian)。
现在所有的服务都在云化,其中的基础就是API化,这个事情也变得越来越重要。推荐在做这方面工作的看看 Principles of good RESTful API Design。http://codeplanet.io/principles-good-restful-api-design/
做业务系统会遇到很多这样的工作,做出来简单,但做好却难。是什么让我们却止步于做出来,并因此想做些有挑战的事呢?
图片来源:Surreal & Conceptual Photography by Diggie Vitt
被逼的工作,被逼的学习
因为大多数人都需要工作,很多人在做着自己不那么喜欢的工作。或因为感情,或因为压力,必须做完现在的事情。不喜欢意味着不会朝思暮想,不会为伊消得人憔悴。再好的职业素养,也不会改变做完即可的态度。
如果你是被逼学习型,找一份自己更喜欢的工作,事不宜迟。这里有一点个人的建议是,如果要走技术路线,不要做外包。
我们不排除有些工作因为容易掌握,大多数人都只是做完即可,但更多的情况是,不是工作要求低,而是做的人放低了对自己的要求。就像本文前面的业务系统,虽说离架构设计很远,但是基本功都是一样的。
值得注意的是,在一个分工明确的团队里,并不是所有人要做所有事,但是好的团队里所有人会了解所有事。一个开发者如果不了解上层服务的需求,不了解下层服务的设计,很难做好服务的。
只有对其他组件建立足够的了解,才能设计出一致的服务,减少过度优化和不当依赖。知道什么时候该容忍错误,什么时候该放弃请求,才能在出问题的时候快速定位,才能一起做好服务。
这种了解,就来自于对架构设计的理解。
不要被你的思想局限
如果你喜欢自己现在的事情,那么要恭喜你,你很幸运。而你需要注意的是,不要被自己的思想局限。虽然没人会要求你像卖油翁一样,在能倒油的时候练习从铜钱内穿过,但你至少要知道,还是有很多可以做的。
就拿本文开头的例子,你以为只是设计一个API,但其实API到底层数据到映射和转换,已经涉及了架构设计的基础。你以为只是设计成RESTful,但其实还可以做成自动测试的框架,像Swagger,或者RAML,或者API Blueprint。你以为你只是在包接口,其实是放弃了对自己的要求而已。
人永远不知道自己不知道的东西,这也是我们需要持续学习的原因。
包接口也能变成包老师。
图片来源:苍老师书法
阅读其他文章,请关注知乎专栏『 一乐来了 』
收起阅读 »
关于EaseSDKHelper官方做法,otherConfig参数无法关闭log问题
[[EaseSDKHelper shareHelper] easemobApplication:application
didFinishLaunchingWithOptions:launchOptions
appkey:kEaseMobKey
apnsCertName:nil
otherConfig:@{kSDKConfigEnableConsoleLogger:@NO}];
这段代码是为了注册环信, 其中otherConfig中的kSDKConfigEnableConsoleLogger,可以配置是否打开后台log打印。 但是实际上你传@NO 或者 @YES都是没用的, 原因是这个方法的实现中(CMD+左键),
if ([otherConfig objectForKey:kSDKConfigEnableConsoleLogger]) {
options.enableConsoleLog = YES;
}
是这样判断的, 正确做法是
if ([[otherConfig objectForKey:kSDKConfigEnableConsoleLogger] boolValue]) {
options.enableConsoleLog = YES;
}
需要加一个boolValue转换, 强迫症患者改一下, 就不会再有超多的log打印了~ 收起阅读 »
首届环信编程大赛,让世界感受中国程序员的力量!
一:大赛简介
根据IDC数据显示,中国有近200万开发者,身为一个程序员,我们生活在一个 IT 系统越发复杂且多变化的时代。有时候执行一个简单的开源项目,开发一个基础功能都需要精准定义并耗费大量时间专注任务。随着云计算的兴起,API 和SDK开始作为软件之间重要媒介而作为一种独立应用而存在,“一切皆软件,一切皆API,一切皆SDK”。通过API和SDK可以让开发者摆脱繁重的基础功能底层开发,短时间即可让App拥有各种诸如内置IM、统计等基础功能组件能力。
2014年,以环信为典型的众多云服务商将基于移动互联网的即时通讯能力,如单聊、群聊、发语音、发图片、发位置、实时音频、实时视频等,通过云端开放的Rest API和客户端SDK包的方式提供给开发者和企业。让App内置聊天功能和以前网页中嵌入分享功能一样简单。而开发者就可以集中精力处理自己产品的核心业务开发,不必为基础功能组件耗费自己太多精力,不仅省钱省力,更是加速了APP的上线速度。按照移动互联网时代的速度,往往两三个月就能够决定一款APP的成败。
因此,环信联合国内专业的技术测评平台猿圈共同推出“首届环信编程大赛”,让世界感受中国程序员的力量。本次环信编程大赛由线上初赛、决赛、颁奖典礼三个环节组成。其中初赛环节,通过猿圈网站在线测评平台进行编程挑战。决赛环节基于环信sdk开发一款移动端app,比赛结果将以初赛及决赛的综合评分决定。
二:大赛奖品
1.一等奖8000元,二等奖5000元,三等奖2000元。
2. 决赛前10可获得限量版瑞士军刀背包一个。
3.前五十可获得定制版精美T-shirt或卫衣。
还有更多神秘礼品等着大家,比如文件袋,多功能便携工具卡,环信CEO签名编程书籍等。
三:赛程设置
1.初赛:初赛题目将在国内最专业的技术人才测评平台猿圈上进行在线答题,通过猿圈在线编程评测系统可快速识别一个技术人员的技术水平及素养,在初赛中得分90分及以上的程序员将会获得决赛资格。(小贴士:初赛在线答题可挑战多次,取最好成绩)
2.决赛:基于环信sdk开发一款拥有聊天功能的app,类型自由选择,比如:游戏、工具、社交...决赛将根据APP功能复杂难易程度,项目代码简洁度等标准进行评选。
3,.本次编程大赛最终获奖项目将开源在imgeek社区供大家学习参考。
四:大赛日程安排
报名要求:全国程序员(不限年龄,职业等)
大赛进行时间:3月7日-4月15日
初赛题目:在猿圈平台上进行在线答题(Android/ios)
初赛参赛步骤:
1:在 http://t.cn/RGQ3Kwy 完成报名。
2:报名当日晚9点收到包含初赛链接地址的通知邮件。
3:按照邮件内提示,在线上完成初赛。
4:初赛筛选通过后将于3月21日告之决赛项目提交地址。
决赛题目:基于环信sdk开发一款移动端APP(Android/ios)
决赛参赛步骤:
1:在环信开发者平台注册开发者账号http://www.easemob.com
2:下载资源包,开发至少一款Android或ios 应用http://www.easemob.com/downloads
开发过程中遇到问题可通过以下路径获取技术支持:
1)社区发帖:imgeek社区http://www.imgeek.org
2)联系环信在线技术支持:官网首页最下方http://easemob.com
3)QQ群组讨论:编程大赛讨论群326754315 收起阅读 »
关于3.1集成时的两个错误, 主要是EaseUI。
问题一: 引入UI的童鞋请查看
视频:集成视频http://v.youku.com/v_show/id_XMTQyMDc0NTQwMA==.html?from=y1.7-2
首先解释下为什么视频中同样的步骤集成不报错,视频中的集成是基于2015年10月30日的EaseUI, 最新更新的2016年2月2日的版本中对3.0demo和EaseUI的代码稍作了修改,以解决之前版本中的一些小问题。 但大家也不要着急,只要按视频中集成,再稍作修改即可。先找到EaseUI-Prefix.pch,将其中的 #define NSEaseLocalizedString(key, comment) [[NSBundle bundleWithURL:[[NSBundle mainBundle] URLForResource:@"EaseUIResource" withExtension:@"bundle"]] localizedStringForKey:(key) value:@"" table:nil] 这段代码拷贝到自己的pch文件下即可。 再在自己pch文件中所有代码的首尾加上#ifdef __OBJC__和#endif。 好了,问题就这样解决啦!
问题二:上方回答是03/06之前好用的, 在新版本3.1.0更新以后, 需要额外引入libiconv.tbd框架。
问题三:NSObject+EaseMob类别报错, 找不到头文件#import "EaseMob.h", 大家需要把NSObject+EaseMob类别的h和m文件删除。 因为官方EaseUI的Demo中并没有引入此文件。 推测是这个文件不用了, 但是程序员光删除了索引但是忘记删除到垃圾桶了。 鄙视!!!
收起阅读 »
表情mm|表情云™V1.2版本,整合环信3.0版Demo同步上线!
SDK新版本的功能优化点如下:
1. Android-优化了表情包批量下载(下载表情包更快,更省内存);
2. Android-开放表情商店内标题栏背景颜色和高度设定;
3. iOS-解决了部分gif表情播放有残影的问题;
4. iOS-优化了SDK表情包下载和键盘的性能;
5. iOS-对环信2.0 Demo做了一些性能优化。
开发者们可以直接在表情mm官网下载最新版SDK 体验~
表情mm官网(http://www.biaoqingmm.com/)
同时表情mm整合环信3.0 IM SDK的Demo也发布啦!欢迎下载体验噢~
目前,接入表情mm|表情云™的开发者涵盖兴趣社交、二次元社区、母婴电商、企业OA等多种类型的产品。未来,表情mm|表情云™在不断更新内容的过程中,还会逐步开放更多灵活定制接口,满足更多开发者的不同定制需求,让更多开发者轻松拥有专属自己产品的表情商店。 收起阅读 »
Android开发自定义ImageView控件实现圆角边框等功能
下边边就是我们经常会需要的一个实现了图片的圆角,以及添加边框等功能的自定义控件;文章最后有项目源码地址
这个自定义ImageView控件实现了图片的圆角、圆形、边框等功能,同时具有按下改变颜色的效果,通过属性设置可以自定义按下的颜色,
以及颜色的透明度;还尅定义边框的颜色
Demo截图:
控件属性定义
<?xml version="1.0" encoding="utf-8"?>控件代码的实现
<resources>
<!--自定义MLImageView的属性 加上了自己的前缀,防止和其他自定义控件冲突-->
<declare-styleable name="MLImageView">
<attr name="ml_border_color" format="color" />
<attr name="ml_border_width" format="dimension" />
<attr name="ml_press_alpha" format="integer" />
<attr name="ml_press_color" format="color" />
<attr name="ml_radius" format="dimension" />
<attr name="ml_shape_type" format="enum">
<enum name="none" value="0" />
<enum name="round" value="1" />
<enum name="rectangle" value="2" />
</attr>
</declare-styleable>
</resources>
package net.melove.demo.chat.widget;控件使用方法
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;
import net.melove.demo.chat.R;
/**
* Created by lzan13 on 2015/4/30.
* 自定义 ImageView 控件,实现了圆角和边框,以及按下变色
*/
public class MLImageView extends ImageView {
// 图片按下的画笔
private Paint pressPaint;
// 图片的宽高
private int width;
private int height;
// 定义 Bitmap 的默认配置
private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888;
private static final int COLORDRAWABLE_DIMENSION = 1;
// 边框颜色
private int borderColor;
// 边框宽度
private int borderWidth;
// 按下的透明度
private int pressAlpha;
// 按下的颜色
private int pressColor;
// 圆角半径
private int radius;
// 图片类型(矩形,圆形)
private int shapeType;
public MLImageView(Context context) {
super(context);
init(context, null);
}
public MLImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public MLImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
//初始化默认值
borderWidth = 6;
borderColor = 0xddffffff;
pressAlpha = 0x42;
pressColor = 0x42000000;
radius = 16;
shapeType = 2;
// 获取控件的属性值
if (attrs != null) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MLImageView);
borderColor = array.getColor(R.styleable.MLImageView_ml_border_color, borderColor);
borderWidth = array.getDimensionPixelOffset(R.styleable.MLImageView_ml_border_width, borderWidth);
pressAlpha = array.getInteger(R.styleable.MLImageView_ml_press_alpha, pressAlpha);
pressColor = array.getColor(R.styleable.MLImageView_ml_press_color, pressColor);
radius = array.getDimensionPixelOffset(R.styleable.MLImageView_ml_radius, radius);
shapeType = array.getInteger(R.styleable.MLImageView_ml_shape_type, shapeType);
array.recycle();
}
// 按下的画笔设置
pressPaint = new Paint();
pressPaint.setAntiAlias(true);
pressPaint.setStyle(Paint.Style.FILL);
pressPaint.setColor(pressColor);
pressPaint.setAlpha(0);
pressPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
setClickable(true);
setDrawingCacheEnabled(true);
setWillNotDraw(false);
}
@Override
protected void onDraw(Canvas canvas) {
if (shapeType == 0) {
super.onDraw(canvas);
return;
}
// 获取当前控件的 drawable
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
// 这里 get 回来的宽度和高度是当前控件相对应的宽度和高度(在 xml 设置)
if (getWidth() == 0 || getHeight() == 0) {
return;
}
// 获取 bitmap,即传入 imageview 的 bitmap
// Bitmap bitmap = ((BitmapDrawable) ((SquaringDrawable)
// drawable).getCurrent()).getBitmap();
// 这里参考赵鹏的获取 bitmap 方式,因为上边的获取会导致 Glide 加载的drawable 强转为 BitmapDrawable 出错
Bitmap bitmap = getBitmapFromDrawable(drawable);
drawDrawable(canvas, bitmap);
drawPress(canvas);
drawBorder(canvas);
}
/**
* 实现圆角的绘制
*
* @param canvas
* @param bitmap
*/
private void drawDrawable(Canvas canvas, Bitmap bitmap) {
// 画笔
Paint paint = new Paint();
// 颜色设置
paint.setColor(0xffffffff);
// 抗锯齿
paint.setAntiAlias(true);
//Paint 的 Xfermode,PorterDuff.Mode.SRC_IN 取两层图像的交集部门, 只显示上层图像。
PorterDuffXfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
// 标志
int saveFlags = Canvas.MATRIX_SAVE_FLAG
| Canvas.CLIP_SAVE_FLAG
| Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
| Canvas.FULL_COLOR_LAYER_SAVE_FLAG
| Canvas.CLIP_TO_LAYER_SAVE_FLAG;
canvas.saveLayer(0, 0, width, height, null, saveFlags);
if (shapeType == 1) {
// 画遮罩,画出来就是一个和空间大小相匹配的圆(这里在半径上 -1 是为了不让图片超出边框)
canvas.drawCircle(width / 2, height / 2, width / 2 - 1, paint);
} else if (shapeType == 2) {
// 当ShapeType == 2 时 图片为圆角矩形 (这里在宽高上 -1 是为了不让图片超出边框)
RectF rectf = new RectF(1, 1, getWidth() - 1, getHeight() - 1);
canvas.drawRoundRect(rectf, radius + 1, radius + 1, paint);
}
paint.setXfermode(xfermode);
// 空间的大小 / bitmap 的大小 = bitmap 缩放的倍数
float scaleWidth = ((float) getWidth()) / bitmap.getWidth();
float scaleHeight = ((float) getHeight()) / bitmap.getHeight();
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
//bitmap 缩放
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
//draw 上去
canvas.drawBitmap(bitmap, 0, 0, paint);
canvas.restore();
}
/**
* 绘制控件的按下效果
*
* @param canvas
*/
private void drawPress(Canvas canvas) {
// 这里根据类型判断绘制的效果是圆形还是矩形
if (shapeType == 1) {
// 当ShapeType == 1 时 图片为圆形 (这里在半径上 -1 是为了不让图片超出边框)
canvas.drawCircle(width / 2, height / 2, width / 2 - 1, pressPaint);
} else if (shapeType == 2) {
// 当ShapeType == 2 时 图片为圆角矩形 (这里在宽高上 -1 是为了不让图片超出边框)
RectF rectF = new RectF(1, 1, width - 1, height - 1);
canvas.drawRoundRect(rectF, radius + 1, radius + 1, pressPaint);
}
}
/**
* 绘制自定义控件边框
*
* @param canvas
*/
private void drawBorder(Canvas canvas) {
if (borderWidth > 0) {
Paint paint = new Paint();
paint.setStrokeWidth(borderWidth);
paint.setStyle(Paint.Style.STROKE);
paint.setColor(borderColor);
paint.setAntiAlias(true);
// 根据控件类型的属性去绘制圆形或者矩形
if (shapeType == 1) {
canvas.drawCircle(width / 2, height / 2, (width - borderWidth) / 2, paint);
} else if (shapeType == 2) {
// 当ShapeType = 1 时 图片为圆角矩形
RectF rectf = new RectF(borderWidth / 2, borderWidth / 2, getWidth() - borderWidth / 2,
getHeight() - borderWidth / 2);
canvas.drawRoundRect(rectf, radius, radius, paint);
}
}
}
/**
* 重写父类的 onSizeChanged 方法,检测控件宽高的变化
*
* @param w
* @param h
* @param oldw
* @param oldh
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
width = w;
height = h;
}
/**
* 重写 onTouchEvent 监听方法,用来监听自定义控件是否被触摸
*
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
pressPaint.setAlpha(pressAlpha);
invalidate();
break;
case MotionEvent.ACTION_UP:
pressPaint.setAlpha(0);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
break;
default:
pressPaint.setAlpha(0);
invalidate();
break;
}
return super.onTouchEvent(event);
}
/**
* 这里是参考其他开发者获取Bitmap内容的方法, 之前是因为没有考虑到 Glide 加载的图片
* 导致drawable 类型是属于 SquaringDrawable 类型,导致强转失败
* 这里是通过drawable不同的类型来进行获取Bitmap
*
* @param drawable
* @return
*/
private Bitmap getBitmapFromDrawable(Drawable drawable) {
try {
Bitmap bitmap;
if (drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
} else if (drawable instanceof ColorDrawable) {
bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG);
} else {
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
BITMAP_CONFIG);
}
Canvas canvas = new Canvas(bitmap);
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
drawable.draw(canvas);
return bitmap;
} catch (OutOfMemoryError e) {
e.printStackTrace();
return null;
}
}
/**
* 设置边框颜色
*
* @param borderColor
*/
public void setBorderColor(int borderColor) {
this.borderColor = borderColor;
invalidate();
}
/**
* 设置边框宽度
*
* @param borderWidth
*/
public void setBorderWidth(int borderWidth) {
this.borderWidth = borderWidth;
}
/**
* 设置图片按下颜色透明度
*
* @param pressAlpha
*/
public void setPressAlpha(int pressAlpha) {
this.pressAlpha = pressAlpha;
}
/**
* 设置图片按下的颜色
*
* @param pressColor
*/
public void setPressColor(int pressColor) {
this.pressColor = pressColor;
}
/**
* 设置倒角半径
*
* @param radius
*/
public void setRadius(int radius) {
this.radius = radius;
invalidate();
}
/**
* 设置形状类型
*
* @param shapeType
*/
public void setShapeType(int shapeType) {
this.shapeType = shapeType;
invalidate();
}
}
使用方法很简单,就像在xml布局文件使用其他控件你那样引用就好;如果你不想引用过多的库, 可以直接复制MLImageView类到自己的项目中,
进行修改加工,让控件和自己的项目进行整合
<net.melove.dome.mlimageview.MLImageView注意
android:layout_width="96dp"
android:layout_height="96dp"
android:layout_margin="8dp"
android:src="@mipmap/lz_bp_blue"
melove:border_color="@color/ml_white"
melove:border_width="4dp"
melove:press_alpha="50"
melove:press_color="#00ff00"
melove:radius="8dp"
melove:shape_type="rectangle" />
要记着有一点,在使用自定义控件之前一定要添加自定义命名空间(命名空间的名字可以自己定义)
xmlns:melove="http://schemas.android.com/apk/res-auto"项目源码:自定义ImageView控件 MLImageViewDemo
本文由环信Android工程师lzan13原创,博客地址http://melove.net/ 收起阅读 »
AndroidStudio新建及clone项目关于gradle出现的问题
解决这些问题办法是
打开AndroidStudio项目,找到项目目录gradle\wrapper\gradle-wrapper.properties这个文件内容如下
#Wed Jul 08 23:06:25 CST 2015最重要的就是最下面一句,android studio会联网下载符合当前版本的gradle插件,而这个网址虽然可以访问但速度实在太慢,所以每次下载需要花很长时间或直接超时
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip
解决办法就是自己去手动下载当前项目定义的版本,可以直接复制这个路径去下载,也可以去gradle官网自己选择版本下载
然后把下载下来的压缩包拷贝到C:\Users\lzan13\.gradle\wrapper\dists\gradle-2.5-all\d3xh0kipe7wr2bvnx5sk0hao8目录下后边这个长串的目录不一定相同,以自己的为准
重启AndroidStudio或选择工具栏Tools->Android->Sync Project Gradle Files
等待更新完成,就ok了 收起阅读 »
38节特辑:我们一起追过的“程序媛“女神!
1.世界上第一位程序员,不仅思绪敏捷,聪颖过人,而且还貌美如花。她就是英国著名诗人拜伦的女儿爱达・拉夫拉斯伯爵夫人。
爱达.拉夫拉斯伯爵夫人
2. 美貌与智慧并重的玛丽莎·梅耶尔毫无悬念排名第二,梅耶尔毕业于斯坦福大学,1999年加入谷歌,是谷歌的第一位产品经理和首位女工程师,也是《商业周刊》“创新产业25位领军人物”之一。2012年7月17日,出任雅虎CEO。
3. 相信大家对这个妹子不算陌生,她就是2013年人人网上《这世界唯一的你》的相册女主人公。据了解,这位长相甜美的女孩是人人网的一名前端工程师。男网友看到纷纷表示爱慕,女网友看到纷纷表示“有个会拍照的男友是件多么幸福的事”。
4. 最近,雷军亲自指导小米美女工程师的图片爆红,下图就是“绯闻女主角”。这样一位美美的女子,竟然也是“码农”。
5. 在手机百度4亿用户庆祝会上,一位清纯可人,肤白貌美腿长的妹子惊艳全场,引起一众屌丝宅男们各种争相围观合影。据说,这妹子也是个程序媛,被称为百度“新度娘”。
6. 军中也有漂亮的程序媛妹纸,你没有看错!2000年考入国防科技大学计算机专业的李聪娜,目前在信息化人才缺乏的西北军营,从事网络安全工作。据说这位美女程序媛在90多昼夜编写代码40余万行,让多少男程序猿汗颜!
7. 把目光转向大洋彼岸,介绍下美国云储存公司Box工程部门的美女主管Kimber Lockhart,在加入Box之前,她曾自己创业为一家公司的CEO,后她领导Box公司的工程师团队开发了Box网站大多数的功能。现为旧金山One Medical Group程序部门的Vice President。
8. 目光再回到国内,下边这位被誉为全能程序媛的90妹子,除了业务能力突出以外,还会洗衣服、遛狗铲屎,精通lol,会花会活不粘人!……据悉,她已经被环信公司招至靡下,有图有真相!旁边这位合影的CEO据说除了招募人才能力突出以外,腰椎间盘也突出!
我知道放这张照片我会被打死的......
上面八位有木有你的心动女神?快快分享给你的朋友圈小伙伴们围观吧,据说分享此文的男程序猿2016年都会找到自己中意的妹子哦!
各位程序猿们,欢迎加入环信的大家庭,更多女神等着你:
简历请砸:jobs@easemob.com! 收起阅读 »
环信SDK 3.1.0 发布,全新的通讯协议
Android:
新功能
1. 增加android studio support。
2. 增加x86版本动态库,可以在模拟器上调试。
Bug fix:
1. 修复了扩展字段解析的问题。
2. 修复了用户id中有下划线时,会话中id显示不完整的问题。
3. 修复了某些情况下创建cmd类型消息失败的问题。
iOS:
bug fix:
1. 修复了扩展字段解析的问题
2. 修复了用户id中有下划线时,会话中id显示不完整的问题
点击下载3.1.0SDK http://www.easemob.com/downloads 收起阅读 »
环信编程大赛开始报名了,是GEEK,你就来,等的就是你
了解详情http://www.easemob.com/event/hackathon/
大赛简介
1. 本次编程大赛由线上初赛、决赛、颁奖典礼三个环节组成,其中初赛环节,通过猿圈网站Andriod,iOS在线测评平台进行编程挑战;决赛环节基于环信sdk开发一款移动端app,比赛结果将以初赛及决赛的综合评分决定
2. 初赛通过之后将邮件告知决赛项目提交地址
大赛奖品
1.一等奖8000元,二等奖5000元,三等奖2000元
2. 决赛前10可获得限量版瑞士军刀背包一个
3.前五十可获得定制版精美T-shirt或卫衣
还有更多神秘礼品就不多说拉,比如文件袋,多功能便携工具卡,环信CEO签名的神秘编程书籍
关于比赛题目
1. 初赛:初赛题目将在国内最专业的技术人才测评平台猿圈上进行在线答题,通过猿圈在线编程评测系统可快速识别一个技术人员的技术水平及素养,在初赛中得分90分以上的技术人才将会获得决赛项目的提交地址。最终比赛结果将结合初赛及决赛的综合成绩进行判定。
小贴士:初赛在线答题可挑战多次
2. 决赛:基于环信sdk开发一款拥有聊天功能的app,类型自由选择,比如:医疗,教育,社交...决赛将根据功能复杂难易,项目代码简洁评选
本次编程大赛最终获奖项目将开源在imgeek社区供大家学习参考
收起阅读 »
凌晨两点零八分的环信
靠着环信CTO带着研发团队年复一年日以继夜的奋战 ,只有市场第一的公司程序员才知道凌晨两点钟的北京三环是长什么样子的
好PaaS才产好SaaS:环信已具备差异化竞争优势
中国计算机报专访环信CEO刘俊彦
从PaaS起家:环信即时通讯云优势明显
在PaaS服务类别中,IM云服务是典型的代表。环信长期专注的就是IM云服务,能够为开发者提供基于移动互联网的即时通讯能力。客户选择环信通常是看重了它在IM云服务市场中展现出来的优势。比如,环信可以帮助客户有效地缩短即时通信平台的开发周期,可以帮助客户构建一个可承载上千万用户同时在线的大型IM系统,可以帮助客户节约开发成本和运维成本等。
环信在PaaS市场上获得的成功也帮助它赢得了资本市场的关注,截止目前,环信已获得近2200万美元的融资。
获得上述成绩,环信只用了两年了。在这两年里,环信在技术研发经验和用户数量上都有所积累。更重要的是,在两年的服务过程中,环信发现了一个前景更加广阔的发展方向。
“在未来,客户服务将会覆盖电话、PC、移动终端等多个渠道。又由于越来越多的用户在使用移动终端,移动终端也会成最重要的客户服务渠道。” 环信CEO刘俊彦如是说。
在客户服务形式上,以前用户熟悉的客服方式是邮件、电话、社交媒体(微博客服、微信客服),而现在情况有了变化,现在用户都去手机上了,用户希望能够在手机APP里能够直接联系到企业得到服务。所以,环信希望能从底层的通信服务商(PaaS)再上升一层,拓展为智能客服服务商(SaaS)。另外对于环信来说,这种拓展的商业意义更大,因为通常PaaS服务商与最终用户之间要么隔着服务,要么隔着产品,所以变现的路径稍长,变现的效率也较低。而提供SaaS客服服务后,环信就可以更贴近最终用户,以此缩短变现路径,提升变现效率。
SaaS 模式从去年开始在业内备受追捧,去年环信也趁热打铁推出了SaaS产品,基于在即时通信底层技术与市场运营方面的长期资源积累,环信的SaaS客服产品在智能客服项目的投标过程中仍旧优势明显。
“在App平台开发PaaS领域,IM类PaaS是典型代表,环信在IM类PaaS市场积累了一批用户,当客户采用了环信的PaaS服务后,如果发现这个客户也有客服需求,环信就很容易推动该客户转化成自己的SaaS客服客户。所以,环信SaaS客服客户从推出后也增长的很快。如果客户需要能够支撑几百万甚至几千万用户同时在线的客服系统,环信的胜出机会就很大。因为很多单纯只做SaaS的客服厂商很难具备这个能力,它们还需要获得第三方即时通信底层PaaS平台的支持,因为无法给客户直接提供一站式的服务,这会降低客户的信任度。” 刘俊彦表示。
环信SaaS客服有三门绝技:全媒体接入+智能机器人+商业智能平台
在产品架构上,环信移动客服分成四个部分。第一部分是基于环信PaaS平台构建的全媒体gateway(入口),这部分要对接呼叫中心、App、网页客服端、社交媒体等客服渠道,包含一个服务器集群,优点是能够实现可扩展,比如客户要求能接入推特、Facebook也能实现。第二部分是人工智能机器人,目前环信的机器人产品已能够独立运营,也可以为友商提供机器人客服功能。第三部分是具备数据统计功能的商业智能平台。第四部分是环信的SaaS客服核心业务系统。
从上述架构可以看出,前三部分产品拥有的技术优势造就了环信SaaS客服产品的整体优势。
在人工智能机器人领域,环信认为,人工智能第一个能落地的点就是客服领域。因为现在来看,用人工智能做客服,可以提升客服效率和降低成本,并可以大幅度地帮助客服产品提升沟通体验。其他与客服相关的热门技术,比如语音转换,在客服领域仍不能大规模应用,主要是因为目前语音转换技术仍然在准确率、专业性、体验度上很难满足客户要求,尤其是在各种复杂的生产环境中,基于语音转换的问答系统很难实现良好的客服沟通体验。
“环信把沟通分成两种模式,一种是同步沟通,一种是异步沟通。电话就是典型的同步沟通模式,但缺点是接打电话时客服人员很难再完成其他任务。即时通信客服就是典型的异步沟通模式,无论用户是从微信还是App进入客户渠道,客服人员都可以同步地去完成其他任务,这恰符合移动互联网环境下消费者的碎片化操作习惯,来自人工智能技术的支持让这种优势景上添花。” 刘俊彦介绍说。
为了保障智能机器人技术的“自主可控”,环信坚持自己搭建机器人技术研发团队,虽然这样做成本很高。“很多SaaS客服都是找第三方机器人公司合作的,但我们觉得还是要自己掌握机器人核心技术,积累自己的算法和模型,这样做确实成本很高,因为要请的需要是科学家。”环信CEO刘俊彦说。
另外,商业智能平台(BI)也被环信认为是未来SaaS客服实现差异化的核心点之一,很多传统BI工具能够为企业提供统计报表的能力,但却不能做到有效地挖掘潜在用户。环信提供的BI不但能够统计报表,还能协助客服系统实现对潜在用户的挖掘。比如,环信的BI能做到对“客户情感的量化”。当一位从微信渠道来的客户在情感上表达出不满意了,环信BI中客户情感的指数就会增加,当到达某一个标准时,就会自动报警,这个客户随后就将被申报给客服总监特别处理,这对挖掘潜在客户大有帮助。
环信提供的BI工具也可以帮助客户做反向营销。比如在一个母婴电商App中,客服通过与客户聊天了解情况后为客户打上标签,比如打上了“妈妈”、“想买儿童座椅”等标签,然后再向这些客户以客服的身份推送一条信息,告诉客户有一款儿童座椅正在打折,整个过程都由客服系统执行,给客户一种好友沟通的体验而非广告推送的体验,转化率也就会高很多。
客服会更智能:IOT充满想象空间
刘俊彦认为客服在未来有三个发展趋势。第一是客服请求更多会来自移动设备上。第二是智能机器人未来将承担70%~80%甚至更大比例的客服工作。第三是客服场景将越来越多地基于物联网和大数据技术来构建。
“举个列子,未来冰箱上会设置一个小按钮,当一台冰箱坏了,用户通过小按钮就能与冰箱厂商客服接通视频电话,电话接通的同时冰箱的数据会马上传到厂商,厂商客服就可以马上诊断出是否为缺氟引起的不制冷等故障原因。在这个场景里,实时音视频通话和IM通信功能是通过环信提供的PaaS平台来实现,客服用的工作台也可以由环信提供,故障分析的功能可以由环信的大数据BI来实现。” 刘俊彦说。 收起阅读 »
创业路上遇到的那些坑
你知道如何注册公司吗?
你知道如何控制企业成本吗?
你知道合伙人及团队该如何选择?
你知道市场该如何打开?
创业不容易,教你怎么避开那些坑?
这里没有大佬给你吹牛,只有众多一线实战专家为你解读在创业路上遇到的问题,
让你具备一个CEO的基本素质和能力!
活动时间:2016年3月06日 14:00—17:30
活动规模:100人
活动地址:车库咖啡 海淀区海淀西大街48号鑫鼎宾馆2层
活动流程:
13:30-14:00 签到
14:00-14:45 猿圈CEO 郑萌
14:45-15:30 51社保CEO 余清泉
15:30-16:15 环信技术经理 杜超
16:15-17:00 互动答疑
17:00-17:10 合影留念
演讲嘉宾
猿圈 CEO&创始人 郑萌
分享主题:《初创企业如何打造技术团队》
做为一个资深程序老猿,带了10几年的技术团队,凭借对技术人才和企业的理解,做了一个围绕程序猿招聘的相关项目。在这个巨缺猿类的时代,想让大家辨别真假猿,猿圈就是你的火眼金睛。自主研发Android和iOS云端编译引擎,结合基于大数据的人工智能分析,猿圈是目前是国内唯一一家做程序员代码挑战的平台。
51社保创始人&CEO 余清泉
分享主题:《初创企业的成本优化及风险防范》
国内知名社保专家、劳动用工与成本优化专家。中关村创业大街创业导师、《社保管理师》职业培训首席讲师、《人力资源财税师》能力培训首席讲师、多家机构特聘专家顾问。已出版《社会保险法律政策与工具速查》《社会保险法实战策略》《企业人力资源法规速查大全》《企业人力资源管理师考点地图与真题精解》等专业书籍。《中国企业社保白皮书》系列报告主笔。2015年8月主导发布《中国企业社保白皮书2015》首次明确提出“互联网社保服务模式”。
环信技术经理 杜超
分享主题:《如何让你的APP快速具有即时聊天功能》
负责im即时通讯研发及架构设计工作,imgeek社区创始人,热衷开源精神。对于个人开发者或者中小企业来说,做IM用第三方的是一种趋势,自行研发移动IM,技术门槛高,开发周期长。如何让你的APP快速具有即时聊天功能。
活动报名请点击:我要报名 收起阅读 »
视频数据流
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIButton *button=[UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame=CGRectMake(0, 0, 200, 50);
[button setTitle:@"aa" forState:UIControlStateNormal];
[button addTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
-(void)click:(UIButton *)btn{
UIImagePickerController *imagePicker=[[UIImagePickerController alloc] init];
imagePicker.delegate=self;
// imagePicker.view.frame=s
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){
imagePicker.sourceType=UIImagePickerControllerSourceTypeCamera;
}
// imagePicker.allowsEditing=YES;
// [self.view addSubview:imagePicker.view];
[self presentViewController:imagePicker animated:YES completion:^{
}];
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)image editingInfo:(NSDictionary *)editingInfo {
}
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
[self dismissViewControllerAnimated:YES completion:nil];
NSLog(@"%@",info);
UIImage *image=[info objectForKey:UIImagePickerControllerOriginalImage];
self.image.image=image;
}
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
[self dismissViewControllerAnimated:YES completion:^{
}];
} 收起阅读 »
Android 中bitmap的处理:获取缩略图,点击查看大图
通过路径获取Bitmap的缩略图
public Bitmap getBitmapByWidth(String localImagePath, int width, int addedScaling) {同时,参数里面的路径也可以改为Bitmap,看自己需要吧。
if (TextUtils.isEmpty(localImagePath)) {
return null;
}
Bitmap temBitmap = null;
try {
BitmapFactory.Options outOptions = new BitmapFactory.Options();
// 设置该属性为true,不加载图片到内存,只返回图片的宽高到options中。
outOptions.inJustDecodeBounds = true;
// 加载获取图片的宽高
BitmapFactory.decodeFile(localImagePath, outOptions);
int height = outOptions.outHeight;
if (outOptions.outWidth > width) {
// 根据宽设置缩放比例
outOptions.inSampleSize = outOptions.outWidth / width + 1 + addedScaling;
outOptions.outWidth = width;
// 计算缩放后的高度
height = outOptions.outHeight / outOptions.inSampleSize;
outOptions.outHeight = height;
}
// 重新设置该属性为false,加载图片返回
outOptions.inJustDecodeBounds = false;
temBitmap = BitmapFactory.decodeFile(localImagePath, outOptions);
} catch (Throwable t) {
t.printStackTrace();
}
return temBitmap;
}
点击缩略图显示完整的图片
设置ImageView的点击事件,看具体想怎么处理,如果点击换其他图片,则直接跳转,如果是点击查看详细图片,则弹出PopupWindow,里面放一张ImageView,通过传过去的参数filePath,直接显示原来没压缩的图片即可。这个简单就不贴代码了。
Bitmap的旋转
自己的demo里面,图片长宽不一,缩略图肯定是宽大于长的,而详细信息里面或者手机相册里面的图一般都是长大于宽,所以涉及到图片旋转的问题了。
public Bitmap getRotateBitmap(int type, String bitmapPath) { // type 1
// 竖屏显示图片,2
// 横屏显示图片
Bitmap bitmap = BitmapFactory.decodeFile(bitmapPath);
Bitmap resultBitmap = bitmap;
int height = bitmap.getHeight();
int width = bitmap.getWidth();
System.out.println("获取的bitmap 宽和高:" + width + ":" + height);
switch (type) {
case 1: // 竖屏显示图片,需要偏高
if (height < width) {
// 如果长度小于宽度,则需要选择,否则不需要旋转,只要将option修改即可
Matrix mmMatrix = new Matrix();
mmMatrix.postRotate(90f);
resultBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), mmMatrix, true);
}
break;
case 2: // 横屏显示图片,需要偏长
if (height > width) {
// 如果宽度小于长度
Matrix mmMatrix = new Matrix();
mmMatrix.postRotate(90f);
resultBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), mmMatrix, true);
}
break;
default:
break;
}
return resultBitmap;
}
本篇文章由热心开发者提供,作者主页Mudo_Yan 收起阅读 »
浅谈刷票机
第二届Gopher大会将在京举办,环信小伙伴们等你来!
http://thinkandcode.info/gopherchina2015can-hui-ji-lu/
http://fuxiaohei.me/2015/4/29/gopher-china-2015.html
http://life.leanote.com/post/gopher-china-2015-my-golang-way
说了那么多,回到2016年这一届的大会,因为北京可以说是中国的互联网中心,这里有着大量的Go使用者,而且我去年也答应了很多北京的同学,说明年一定来北京,为了当初的承诺,所以我们来了。北京可以说是一个开大会巨贵的地方,我们年前就一直在寻找会议场所,交通便利又要价格适当,但是北京这样的地方没有,最后我们只能硬着头皮签了一个价格高的不那么离谱的地方,但是必须保证交通便利,吃喝玩乐方便的地方。所以我们选择了亚洲大酒店。目前这个地点我还是比较满意的。
给大家看看我们今年的Logo和给大家准备的T恤
说完这个回到我们最重要的内容安排上,这一次我还是邀请了大量的一线工程师来给大家分享Go的经验,举行的行程大家看下面:
4月16日周六
08:20-8:50 入场报到
08:50-9:00 大会介绍
09:00-09:10 主办方致辞
09:10-10:00 陈辉,蚂蚁金服 Go在数据挖掘的应用
10:05-10:55 刘奇,PingCAP Go在分布式数据库中的应用
11:00-11:50 许式伟,七牛 待定
13:10-14:00 孙宏亮,DaoCloud Go在分布式docker里面的应用
14:05-14:55 Marcel,Google Go如何解决i18n和i13n问题
14:55-15:15 茶歇
15:15-16:05 米嘉,宜信 Go如何构建Web应用
16:10-17:00 邓洪超,CoreOS Go在分布式系统的性能调试和优化
17:05-17:55 沈晟,心动网络 Golang在移动客户端开发中的应用
20:15-22:00 Gopher技术沙龙party, 七牛和DaoCloud联合赞助举办
4月17日周日
09:00-09:50 Dave Cheney How to Write high performance application
09:55-10:45 吴小伟,阿里云 Go在CDN系统的应用
10:50-11:40 陶春华,百度 Go在百度bfe的应用
13:00-13:50 毛剑,哔哩哔哩 Go在数据存储上面的应用
13:55-14:45 高步双,小米 Go在小米网运维平台的应用与实践
14:45-15:05 茶歇
15:05-15:55 孙建良,网易 Go在网易广域网上传加速系统中的应用
15:55-16:45 Paul Dix,influxdb 待定
最后欢迎大家踊跃报名,我们这一次安排了800-1000人的场地,相比于去年规模大了一倍,我一直怀着把这个大会做成一个party的心态,所以我们的每一个细节都是希望给嘉宾、赞助商、参会者带来兴奋点。当然这样的一个大会光靠我一个人肯定是搞不定的,要特别感谢七牛的妹子们给我很大的帮助,感谢合作伙伴环信的大力支持,感谢各位好友的鼎力相助,我坚信今年的大会一定还会做成一个让大家难忘的大会。
合作伙伴
注册参会请点击“阅读原文”
↓↓↓
阅读原文 收起阅读 »
既然一切不能解决问题的客服都是纸老虎,如何才能做好“新时代客服”?
一切都是为了更有效率地沟通,尤其在机器人介入之后,人的工作变得更复杂了。
“普通话请按 1,For English Press 2……”你耐着性子听完一大堆话,等着那句“转人工服务请按 0”,它出现的时候,你毫不犹豫地按了 0。
这样的场景可能每个人都很熟悉,它让人思考消费者寻求客户服务的本质。很多时候,人们并不是想找客服,而是希望解决问题。无论是出于咨询、投诉还是别的需求,和机器纠缠可能效率低下,找人说几句明白话反而来得更方便。但事实上,当一个消费者沉浸在一个互联网产品里(不管是 App 还是网站),Ta 拿起电话沟通的意愿很可能不太高。换句话说,要不是产品里设置的机器人服务无法令人满意,谁都不想去排队听《致爱丽斯》,然后按一个“0”。
2014 年双 11,中国邮政速递物流呼叫中心
随着更多服务的细化(很多需求是被创造出来的,比如追踪快递的进程。你能想象这个服务出现之前,你会主动了解你买的货物到了哪里,以及为什么在某一个地方停留过久吗?),客服这个行当已经不能仅仅用售前、售后之类的名词来区分,准确的说法应该是,如何第一时间满足用户的信息需求,就应该有怎样的客服形式。
我们拿这个问题去问阿里巴巴的客户服务事业部总监汪海,他简略地概括了客服的整个发展过程,可能也是这个行业的发展过程,“我们开通了 PC(客服)系统、帮助中心;再后来,无线时代到了,用户有往无线渠道转移的倾向。只要打开手机淘宝,他就很容易找到客服入口。”“阿里意识到,服务是流量的组成部分,接下来十年,体验是整个电商的重要因素。”
2011 年携程旅游网扩建南通呼叫中心的时候,应该也不会想到客服行业的变化会来得那么快。才四年,8 万平方米 12000 个服务坐席,宏伟壮观的全球最大旅游业服务呼叫中心,到今天,还增加了一个个有“微领队”的微信群。
举个例子,有一批游客购买了去马尔代夫的产品,微领队就发短信给他们让他们加群。在这个群里你就能提问任何信息,既包括携程的产品,也包括目的地玩乐推荐。负责解答问题的微领队、一线员工童琳对《好奇心日报》说,他手里 20 个群左右,旺季(春节)每个群一百多人、平时 30、40 个人。
在携程,这样的微领队的总数不到 100 人。携程旅游事业部 COO 喻晓江表示,电话坐席目前占 7 成,剩下的 2~3 成是其他形式,但现在也慢慢模糊,“(我们正在)试图培养全工种的客服。市场和客服人员也需要教育”。
微领队
客服行业,企业的投入成本和产品形式、与消费者沟通的方式都在发生变化。尽管一切宗旨依然指向效率,但如今的客服牵涉更多的品牌意义——这也是“让机器人客服更像个有血有肉的人”的意义,换句话说,无论使用机器,还是真人,企业都竭力让消费者在解决问题的过程中感受到它们的特点,如果说“细节决定成败”,这可能是最有代表性的一点。
我们分解了一下“新时代客服”的若干特点及其背后的原因。你会看到,以上变革正在越来越快地发生。
大部分情况下,机器人可以解决效率问题
智能机器人客服的存在意义就像语音功能之于电话客服一样。它的面貌通常是一个交互式的帮助中心,以防一些找不到 FAQ 的网友耽误客服人员的时间。拥有开发团队的大公司往往会自主研发智能机器人,淘宝有阿里小蜜、京东则称之为 JIMI 智能服务体系,根据赵鹏亿的说法,这套 JIMI 系统花了京东 3 年时间迭代生成,研发团队有 80 人,而 JIMI 的服务能力在高峰时期等同于京东所有人工客服。
赵鹏亿是 2011 年加入京东的。从一线客服人员做起工作了八年,现在是京东全国客服中心成都分中心的总监。“2010 年我们的电话客服接通率是非常困难的,每个月增加 1 倍的人力,但是用户需求每个月增加 10 倍。”在那个网络客服的蛮荒时代,大公司急需全新的手段改善服务的供需失衡,希望用户能够“生活自理”的客服机器人+帮助中心的组合,就是分流的主要手段之一。
JIMI 客服机器人
以双 11 的极端客服高峰为例,商家自己的客服能力远不足以应付 1 对 30 的顾客,智能机器人的价值在于,只要把店铺的信息填进标准模板,商家就拥有了一个专属的客服机器人。
“机器人”更深的一层含义则和我们熟悉的“互联网+”有关。假设一名乘客用 Uber 叫了辆车,发生了意外情况,取消订单后 APP 仍然给他扣了款。在找不到客服电话的情况下,此时正确的申诉流程是在 APP 的“帮助”里找到“收费有误”并提交,没多久你就能收到退款邮件。Uber 对此的官方解释是:“乘客在 APP 里可以完成大部分申诉、提问的操作,只有最后一步(退款)需要我们的员工来完成。”
公司们把每一种服务场景都细分出来,是对解决问题的进一步模拟。大众点评里,餐馆定位有一个按钮,催单有一个按钮,而很多电商会特别注重优化评价体系,你甚至可以快速找到已经有购买记录的陌生网友提问,而不用重复一遍“加为好友”的过程。
与此同时,人的工作正在变得更复杂
王丽杰在陌陌担任客服主管,她对《好奇心日报》说:“不断学习才能跟得上,请个长假,我根本跟不上一个月两次的版本迭代”。而“微领队”童琳的说法则是,“为游客解答目的地玩乐的难题,价值肯定比一名开发票的在线客服要高一点。”他负责携程的新加坡目的地,那些客人在网上查得到的问题,他都不用解答了,换句话说,他要知道的东西更“偏”,也更多了。
目前中国从事客服的大约有 1000 多万人,社会和企业对这一行的认知在发生变化。“打字速度 60/min 以上”可能只是最基础的要求,京东赵鹏亿说:“客服人员的角色已经从原来的帮你催单、退款、查询延迟原因,逐渐朝服务专家、产品专家去转型。”
当简单的东西年复一年被机器代替,沉淀下来的问题都是更复杂的。“我该穿多大码”、“这个新疆阿克苏苹果真的甜吗”,这些问题现在都抛给了网络客服。这些服务过程也伴随着商机的转化,他们实际上提供的是一种售前导购服务——介绍产品,引导购买,消除网购的不信任感。
苹果店 Genius Bar 的员工,同样会去 Call Center 接一阵子的电话,保证前后台的技术水平同步。之所以人们觉得 AppleCare 的客服体验好,就是因为他们真的很了解产品。基层的客服人员更了解用户需求,迅速接触全端的生产体系,于是当社会招聘无法满足公司人才需求的时候,客服人员就可以为公司输出基层管理人才,比如京东每年招聘几百人的服务之星,就能在一年多后成长为运营体系中的管理层。
除了面对消费者时客服人员开始处理更复杂的问题,因为和产品开发离得更近,客服部门本身也开始发挥作用。在去年 9 月的一次媒体采访中,阿里巴巴首席客户服务官戴珊透露了集团内部 APP 的新功能 “九点电台”——其本质是让庞大的组织机构扁平化——当集团客服发现一个有共性的行为,就可以点一个叫做“拉铃”的按钮,把案例分享到九点电台,这些建议业务部门的同事都能看到,它们如果足够重要,最终可能就会变成一个可优化的点。“我们几千个服务的小二不仅是解决问题,它还能作为内容输送到各个部门去。”汪海说。
阿里集团内部 APP,九点电台的入口
客服社交化,最重要的特点可能是语言
“京东互助体系”是一个典型的社交化案例,它的本质是借助一些用户的力量解决另一些用户的需求。目前这个测试中的产品主要集中在母婴领域。京东会设立公共讨论的话题(比如关于某款奶粉),培养购物达人。根据赵亿鹏透露的数字,电话客服只能一对一,一个在线人员最多同时处理 6-8 个用户,但一个话题可以影响的用户的平均数字在 3000+左右,“里面有活跃发言的,也有沉默浏览的。单从服务的角度看,它是很有效的。”
商品下的购买咨询
而客服使用的语言(很多时候是机器人被设定的语言),最大的目的是拉近与客户的距离。微博名为“周小帅私房菜”的大 V 有一百万粉丝,主打菜品就是小龙虾。他在微博的认证居然是“知名搞笑幽默达人”,而不是“卖小龙虾的”。翻翻他的微博,大部分都是他和顾客的聊天记录,多为搞笑的对话和段子,每次回复都会附上一个“恼火”的表情,这就是他营销自己的方式。
2016 年 1 月底,某卫浴品牌旗舰店因为接待了 438 名留学生提问而火了。一道美国大学生数学建模竞赛关于浴缸放水的题被学生丢给了卫浴客服,越来越多网友来调戏后,店家的自动回复已经变成了“亲,浴缸常用尺寸有 1.5 米到 1.8 米的,厚度是 2 公分,热传导系数根据学生回答是 0.19 左右,一小时温度下降 5 度左右……询问学生太多,所以回复可能会稍微有点慢。”
个性化的客服语言还是主要出现在社交网络上,一旦面对的用户量级增大,公司则倾向于保守应对。至于这些噱头之所以能成为卖点,归根结底,人们固然贪图网购的方便,可也怀念面对面交流的人情味,而人情味,在互联网上永远是稀缺的。
大数据应该是帮助形成解决方案的支持者
如果你打过顺丰快递或者麦当劳的电话,你肯定已经知道了他们会假装了解你。比如记录你的地址、点单偏好之类。
其实大数据的最佳使用方式是用来记录用户复杂行为。比如京东开发的用户画像系统就可以根据用户的操作记录判断优先级——比如说你已经点了催促订单,之后如果系统再接到注册用号码的电话,首先就判断它可能是一个催单的问题,然后看订单时间判断是否延期,如果正常,则交由在线服务机器人或普通客服,如果已经超时,一名擅长处理疑难杂症的资深客服就会准备好接这个电话。
还有就是平台沉淀下来的用户信用记录。在客服层面,交易平台的信用积累能起到减轻网购风险的作用。阿里巴巴客服事业部总监汪海向我们介绍了这个已经进行了近两年的机制:“当你信用等级够高,只要你发起退货,这个钱就马上能到你账上。”在可以应用于极速退款的场景,信用等级有权力简化客服的流程,先赔付、再处理后续。对商家也一样,当信用好的商家遭到恶意投诉,平台就会要求消费者提供更多的证据。
客服不一定总是希望帮你解决问题
我们打算用一个经典的故事来结束本文。
原《纽约时报》记者乔·塞拉诺在 2006 年曾说:“顾客支持服务在电子消费产业中是个弃儿”。事实也是如此,有一度,公司希望你在买完产品之后就不要去打扰他们,所以用相当节省成本的方式解决问题。一个美国消费者听到印度口音的售后服务接线员打招呼说“先生你好”,也没什么好奇怪的。
不过乔·塞拉诺有另一个洞察。
他的音乐播放器 iPod 坏了,而且他打定主意要修一修。
所以他费尽千辛万苦找到了客服电话,然后得到了“再买一台”的真诚建议。他坚持不懈,最后发现可以填一份表格,把机器寄回去修理——苹果公司为此索价 250 美元,外加税收。
换句话说,苹果根本无意维修。乔·塞拉诺引用了投资人安迪·凯斯勒(Andrew Kessler)的话解释了一下,“一个电话每分钟就花去公司 75 美分,一个小时就要花45 美元“,然后他说:“一方面,因为音乐播放器的价格远比电脑的价格来得低,苹果公司有更强烈的动机, 不让人们打电话进来;一台本来有赢利的音乐播放器,因一个长途电话反而变得没有什么利润可言。修理甚至在保修期内的音乐播放器,也没有任何经济意义。苹果公司仅仅只是给您寄来一台新的而已。”
这个故事在一本叫做《绅士与无赖》的书里,探讨的是公司客服成本的秘密。
本文转载自《好奇心日报》,作者:朱凯麟。您可以点击阅读原文跳转。 收起阅读 »
环信直播课堂第一期 知识点干货分享和项目代码
Q:心跳的支持
A:连接成功的回调里面启动心跳
Q:环信发消息是否需要好友关系呢
A:不需要的 ,知道对方id就可以直接聊天
var options = {
//to : to,
to:'msgto',
msg : msg,
type : "chat"
};
Q:输入空消息的判断
A: var sendText = function() {
// if (textSending) {
// return;
//}
Q:自动登陆的 实现
A:$(function()
{
login();
}
)
Q:用户token 的登陆
A://根据用户名密码登录系统
conn.open({
apiUrl : Easemob.im.config.apiURL,
user : user,
// pwd : pass,
accessToken : "YWMtV8DgQt97EeWInF-xEd80TgAAAVRl-FixEr0I5NWLkYFefpM919W5-JU1Uvc",
//连接时提供appkey
appKey : Easemob.im.config.appkey
});
Q:多网页的共存
A:var resource_value = Math.floor(Math.random()*1000);
// var resource_value = "webim";
Q:刷新或者退出网页的时候提示
A: $(function() {
$(window).bind('beforeunload', function() {
if (conn) {
conn.close();
if (navigator.userAgent.indexOf("Firefox") > 0)
return ' ';
else
return '';
}
});
});
Q:低版本ie是否支持
A:支持ie789+,在调试的过程中需要本地配置服务
集成移动客服的时候,IM 服务号是干嘛的呢
A:
1:在客服后台绑定一个关联
指定一个im服务号
2:客户端联系客服的时候,写个按钮“联系客服”
调用了发消息的方法,接收对象 to=关联里面的 im服务号
消息发送过去之后 会到客服后台,根据分配策略分配给对应的客服
Q:网站集成环信移动客服
A:在</body>标签前加入这段代码
<script src='//kefu.easemob.com/webim/easemob.js?tenantId=327&hide=false' async='async'></script>
Q:这个按钮进行自定义
A:首先,将已嵌入网站中的JS插件代码中的hide=false修改为hide=true:(确保tenantId为自己的)
<a href="javascript:;" onclick="easemobIM()" tenantId=0000>自定义按钮</a>
Q:自定义联系客服的界面
A:[url]https://github.com/easemob/kefu-webim[/url]
直播中写的项目代码下载 ↓ ↓ 收起阅读 »
环信:发送头像和昵称(从消息扩展中获取)
注意:以下是在官方Demo3.0的基础上修改的。官方Demo下载地址
环信提供了获取头像和昵称的两种方式:
方法一 从APP服务器获取昵称和头像
昵称和头像的获取:当收到一条消息(群消息)时,得到发送者的用户ID,然后查找手机本地数据库是否有此用户ID的昵称和头像,如没有则调用APP服务器接口通过用户ID查询出昵称和头像,然后保存到本地数据库和缓存,下次此用户发来信息即可直接查询缓存或者本地数据库,不需要再次向APP服务器发起请求
昵称和头像的更新:当点击发送者头像时加载用户详情时从APP服务器查询此用户的具体信息然后更新本地数据库和缓存。当用户自己更新昵称或头像时,也可以发送一条透传消息到其他用户和用户所在的群,来更新该用户的昵称和头像。
方法二 从消息扩展中获取昵称和头像
昵称和头像的获取:把用户基本的昵称和头像的URL放到消息的扩展中,通过消息传递给接收方,当收到一条消息时,则能通过消息的扩展得到发送者的昵称和头像URL,然后保存到本地数据库和缓存。当显示昵称和头像时,请从本地或者缓存中读取,不要直接从消息中把赋值拿给界面(否则当用户昵称改变后,同一个人会显示不同的昵称)。
昵称和头像的更新:当扩展消息中的昵称和头像URI与当前本地数据库和缓存中的相应数据不同的时候,需要把新的昵称保存到本地数据库和缓存,并下载新的头像并保存到本地数据库和缓存。
本文主要介绍第二种方法:给消息添加扩展,用于携带昵称和头像信息。先来看下效果:
效果图
在消息发送时,设置并发送扩展消息
1:因为是在官方Demo里修改的,但对其还不熟悉,咋办呢?
其实,环信是基于XMPP优化而来的,而XMPP消息又是基于XML的。已经知道在XMPP里扩展消息的方式了,这里应该也是类似的。只不过首先要找到发送消息的时机。可是我不知道在哪?这里要善用搜索和断点。下面简要的说下我的思路:在项目里搜索【消息】,找到了EaseChatToolbar.h中的- (void)didSendText:(NSString *)text;方法(别问我为什么是这个方法,不会告诉你我也是查了很久的)。然后在.m中该方法处设置断点,运行程序,输入文字后点击发送按钮。然后看看程序执行的流程是什么。依次向上修改方法,添加头像和昵称信息。如图:
工程截图
2:修改- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
中的调用方法。并设定头像和昵称字典,代码如下:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if ([text isEqualToString:@"\n"]) {
if ([self.delegate respondsToSelector:@selector(didSendText:)]) {
//注释掉的 -- [self.delegate didSendText:textView.text];
//新增头像和昵称扩展
NSDictionary *ext = @{@"accountName":accountName,@"img":@"http://7xo30v.com1.z0.glb.clouddn.com/animal.png"};
[self.delegate didSendText:textView.text withExt:ext];
//结束
self.inputTextView.text = @"";
[self _willShowInputTextViewToHeight:[self _getTextViewContentH:self.inputTextView]];;
}
return NO;
}
return YES;
}
3:从新运行程序,发送消息,查看日志。在<body>元素里包含了额外添加的昵称和头像信息。如下:
ChatDemoJCV1[17136:720f] SEND: <message type="chat" to="easemob-demo#chatdemoui_zlanchun1@easemob.com" id="151a0fcc287">
<body>{"ext":{"img":"http://7xo30v.com1.z0.glb.clouddn.com/animal.png","accountName":"zlanchun"},"to":"zlanchun1","bodies":[{"type":"txt","msg":"You"}],"from":"zlanchun"}</body></message>
4:在聊天框中显示消息里地头像和昵称。因为是测试,所以在ChatViewController.m直接将消息中的昵称和头像赋值给视图(实际应用中不推荐这么做,正如环信方法二缺点所说的,需要自己缓存,从本地提取信息)
- (UITableViewCell *)messageViewController:(UITableView *)tableView cellForMessageModel:(id<IMessageModel>)model最后,这里只是修改了text类型消息的扩展,还有其他几种类型的消息扩展也可以按照这样来处理。
{
if (model.bodyType == eMessageBodyType_Text ) {
NSString *CellIdentifier = [CustomMessageCell cellIdentifierWithModel:model];
//发送cell
CustomMessageCell *sendCell = (CustomMessageCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if (sendCell == nil) {
sendCell = [[CustomMessageCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier model:model];
sendCell.selectionStyle = UITableViewCellSelectionStyleNone;
}
//设定头像和昵称
model.avatarURLPath = model.message.ext[@"img"];
model.nickname = model.message.ext[@"accountName"];
sendCell.model = model;
return sendCell;
}
return nil;
}
本篇集成文章由环信热心开发者提供,作者主页取水 收起阅读 »
用Facebook登录你的APP
第一步
首先你要申请一个Facebook APP ID,至于申请方法不是这里要讨论的重点,先过。这个APP ID要放在AndroidManifast.xml文件里。
<meta-data android:name="com.facebook.sdk.ApplicationId" android:value="@string/application_id" />这样就OK了。
第二步
还是在AndroidManifast.xml里,声明下
Activity。<activity android:name="com.facebook.FacebookActivity" android:exported="true" android:label="@string/app_name" android:theme="@android:style/Theme.Translucent.NoTitleBar" />注意这里有个android:exported="true",不要忘了加,这句的意思是当前Activity是否可以被另一个Application的组件启动:true允许被启动;false不允许被启动。
第三步
写个登录按钮,这地方也有个小小的坑。Facebook有提供一个按钮叫LoginButton的玩意,直接添加到xml文件里即可。下面这段代码就是Facebook提供的。
<com.facebook.login.widget.LoginButton android:id="@+id/login_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="30dp" android:layout_marginBottom="30dp" />但是这个按钮居然没法修改,设置背景文字之类的都不生效,LoginButton类里也没提供相关的按钮属性修改方法。于是乎最后还是放弃使用LoginButton,自己写个吧。
第四步
导入Facebook的jar。用Android studio的话也很简单了。在build.gradle的dependencies里添加:
compile 'com.facebook.android:facebook-android-sdk:4.6.0'
第五步
万事俱备,我们只要写个activity来调用API测试下就好了。
public class FacebookLoginDemo extends Activity implements View.OnClickListener {
private static String TAG = "FacebookLoginDemo";
private Button mFbLoginBtn;
private CallbackManager callbackManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
FacebookSdk.sdkInitialize(getApplicationContext());
callbackManager = CallbackManager.Factory.create();
LoginManager.getInstance().registerCallback(callbackManager, new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult) {
Toast.makeText(FacebookLoginDemo.this, "facebook_account_oauth_Success", Toast.LENGTH_SHORT);
Log.e(TAG, "token: " + loginResult.getAccessToken().getToken());
//TODO:got the token,Notify server,and do something
}
@Override
public void onCancel() {
Toast.makeText(FacebookLoginDemo.this, "facebook_account_oauth_Cancel", Toast.LENGTH_SHORT);
}
@Override
public void onError(FacebookException e) {
Toast.makeText(FacebookLoginDemo.this, "facebook_account_oauth_Error", Toast.LENGTH_SHORT);
Log.e(TAG, "e: " + e);
}
});
}
private void initViews() {
mFbLoginBtn = (Button) findViewById(R.id.fbLoginBtn);
mFbLoginBtn.setOnClickListener(this);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
callbackManager.onActivityResult(requestCode, resultCode, data);
}
@Override
protected void onResume() {
super.onResume();
AppEventsLogger.activateApp(this);
}
@Override
protected void onPause() {
super.onPause();
AppEventsLogger.deactivateApp(this);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.fbLoginBtn) {
AccessToken accessToken = AccessToken.getCurrentAccessToken();
if (accessToken accessToken = AccessToken.getCurrentAccessToken();
if (accessToken == null || accessToken.isExpired()) {
LoginManager.getInstance().logInWithReadPermissions(this, Arrays.asList("public_profile", "user_friends"));
}
}
}
}
简单分析下代码,点击登录的时候会跳转到FacebookActivity,然后做些权限授权之类的操作,成功后页面finish(),回调到onActivityResult里的callbackManager,onSuccess()里会拿到登录授权信息,一般来说拿到token就好了,再拿着token去告诉自己的服务器,授权登录Facebook成功,然后do something,大功告成。
收起阅读 »
环信关于昵称和图片的问题。android
MainActivity.java,代码如下:
package com.easemob.easeuisimpledemo.ui; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import android.R.integer; import android.content.Intent; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.view.View; import android.widget.Button; import android.widget.TextView; import com.easemob.chat.EMConversation; import com.easemob.easeui.EaseConstant; import com.easemob.easeui.controller.EaseUI; import com.easemob.easeui.domain.EaseUser; import com.easemob.easeui.ui.EaseBaseActivity; import com.easemob.easeui.ui.EaseContactListFragment; import com.easemob.easeui.ui.EaseContactListFragment.EaseContactListItemClickListener; import com.easemob.easeui.ui.EaseConversationListFragment; import com.easemob.easeui.ui.EaseConversationListFragment.EaseConversationListItemClickListener; import com.easemob.easeui.utils.EaseCommonUtils; import com.easemob.easeuisimpledemo.R; public class MainActivity extends EaseBaseActivity{ private TextView unreadLabel; private Button[] mTabs; private EaseConversationListFragment conversationListFragment; private EaseContactListFragment contactListFragment; private SettingsFragment settingFragment; private Fragment[] fragments; private int index; private int currentTabIndex; Map<String, EaseUser> contactsMap = new HashMap<String, EaseUser>(); @Override protected void onCreate(Bundle arg0) { super.onCreate(arg0); setContentView(R.layout.activity_main); unreadLabel = (TextView) findViewById(R.id.unread_msg_number); mTabs = new Button[3]; mTabs[0] = (Button) findViewById(R.id.btn_conversation); mTabs[1] = (Button) findViewById(R.id.btn_address_list); mTabs[2] = (Button) findViewById(R.id.btn_setting); // 把第一个tab设为选中状态 mTabs[0].setSelected(true); conversationListFragment = new EaseConversationListFragment(); contactListFragment = new EaseContactListFragment(); settingFragment = new SettingsFragment(); contactListFragment.setContactsMap(getContacts()); contactsMap=getContacts(); conversationListFragment.setConversationListItemClickListener(new EaseConversationListItemClickListener() { @Override public void onListItemClicked(EMConversation conversation) { startActivity(new Intent(MainActivity.this, ChatActivity.class).putExtra(EaseConstant.EXTRA_USER_ID, conversation.getUserName())); } }); contactListFragment.setContactListItemClickListener(new EaseContactListItemClickListener() { @Override public void onListItemClicked(EaseUser user) { startActivity(new Intent(MainActivity.this, ChatActivity.class).putExtra(EaseConstant.EXTRA_USER_ID, user.getUsername())); } }); fragments = new Fragment[] { conversationListFragment, contactListFragment, settingFragment }; // 添加显示第一个fragment getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, conversationListFragment) .add(R.id.fragment_container, contactListFragment).hide(contactListFragment).show(conversationListFragment) .commit(); EaseUI easeUI = EaseUI.getInstance(); //需要easeui库显示用户头像和昵称设置此provider easeUI.setUserProfileProvider(new EaseUI.EaseUserProfileProvider() { @Override public EaseUser getUser(String username) { if (contactsMap == null) { return null; } Iterator<Map.Entry<String, EaseUser>> iterator = contactsMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<String, EaseUser> entry = iterator.next(); //兼容以前的通讯录里的已有的数据显示,加上此判断,如果是新集成的可以去掉此判断 if (!entry.getKey().equals("item_new_friends") && !entry.getKey().equals("item_groups") && !entry.getKey().equals("item_chatroom") && !entry.getKey().equals("item_robots")) { if (entry.getKey().equals(username)) { //不显示黑名单中的用户 return entry.getValue(); } } } return null; } }); } /** * button点击事件 * * @param view */ public void onTabClicked(View view) { switch (view.getId()) { case R.id.btn_conversation: index = 0; break; case R.id.btn_address_list: index = 1; break; case R.id.btn_setting: index = 2; break; } if (currentTabIndex != index) { FragmentTransaction trx = getSupportFragmentManager().beginTransaction(); trx.hide(fragments[currentTabIndex]); if (!fragments[index].isAdded()) { trx.add(R.id.fragment_container, fragments[index]); } trx.show(fragments[index]).commit(); } mTabs[currentTabIndex].setSelected(false); // 把当前tab设为选中状态 mTabs[index].setSelected(true); currentTabIndex = index; } /** * 临时生成的数据,密码皆为123456,可以登录测试接发消息 * @return */ private Map<String, EaseUser> getContacts(){ Map<String, EaseUser> contacts = new HashMap<String, EaseUser>(); for(int i = 1; i <= 10; i++){ EaseUser user = new EaseUser("easeuitest" + i); contacts.put("easeuitest" + i, user); } EaseUser user = new EaseUser("xu"); user.setNick("xujianxiang"); user.setAvatar("http://happysports.jianxingquyundong.com/image/5,112347a89bf2"); contacts.put("xu", user); user = new EaseUser("shen"); user.setNick("shenxiaojuan"); user.setAvatar("http://happysports.jianxingquyundong.com/image/5,112347a89bf2"); contacts.put("shen", user); return contacts; } }
仅献给跟我一样的菜鸟,看了应该会懂, 收起阅读 »
环信自助式社交大数据平台V1.0 上线!--判断APP的核心用户活动状况和用户在APP中的社交稳定性
您好,环信IM大数据平台1.0版本现在已经上线,内容涉及12个指标组共48个指标,希望能在数据展示和分析上,给您的产品带来更大的帮助。
环信IM大数据平台是基于环信IM系统的数据平台。通过分析,整理和挖掘用户之间的IM关系,判断APP的核心用户活动状况和用户在APP中的社交稳定性,产出对客户有价值的参考结果。
———————————————————登 陆————————————————————
◆环信IM用户直接登录
1.官网登录>我的应用>点击“进入我的IM数据平台>>>”
2.直接进入d.easemob.com登陆进入(请使用环信即时通讯云账号登陆哟~)
注:本期仅对日IM消息500+用户开放。
——————————————————进入平台—————————————————————
◆接受用户补充协议,进入IM大数据平台
在应用概况页,可以对指标组进行操作,即删除某个指标组,单击右上角的删除按钮 即可实现。当您浏览指标组卡片时,鼠标hover到指标名称时,会弹出相应的解释气泡,帮助您去理解这个数据的含义。概况页面最多只能显示5个指标组哟~
———————————————————内 容—————————————————————
◆进入“指标组”,定制选择指标组卡片
滑动开关即可添加该指标组至应用概况页面,次日展示计算结果。
IM指标组的作用是通过对用户数据和IM行为分析和挖掘,产生对客户有用的结果。而群组指标组是通过对用户群组数据和行为分析,产生对群组和IM的关系和结果,我们新增了群组的相关数据,希望能帮助您解决各种之前没有预测到的状况。
希望您能在环信IM大数据平台获得直观有效的数据体验,希望我们可以帮助您的APP产品获得更多成功。 收起阅读 »
【已解决】微信和qq中无法使用webim版的环信,在android手机中
经过一晚上对sdk源码的解读和调试解决了问题。
---------------------------------上面都是废话
安卓平台的微信和qq的浏览器不支持wss的websocket,只支持ws的websocket。或者可以用Bosh。
修改easemob.im-1.0.7.js让其不要用wss的方式通讯,或者自己去判断如果是android的qq微信就用Bosh方式。
大概在js文件1170行,我改过了可能行数稍有偏差,如下图所示
如果觉得有用,请赞我,谢谢
收起阅读 »
2016创业公开课第一期:初创企业如何快速成长
你知道如何注册公司吗?
你知道如何控制企业成本吗?
你知道合伙人及团队该如何选择?
你知道市场该如何打开?
创业不容易,教你怎么避开那些坑?
这里没有大佬给你吹牛,只有众多一线实战专家为你解读在创业路上遇到的问题,
让你具备一个CEO的基本素质和能力!
活动时间:2016年2月27日 13:30—17:30
活动规模:50人
活动地址:北京市海淀区海淀西大街36号昊海楼7层,北大创业训练营(地铁10号线苏州街A口出 步行10分钟或地铁4号线中关村站E口 步行10分钟)
演讲嘉宾:
冰狗网CEO 任冠举
分享主题:《初创企业知识产权风险防范》
首席知识产权顾问,培训讲师
南京大学生命科学院毕业,硕士;10年以上知识产权从业经验。
曾供职于国家知识产权局专利局,精通专利审理要求及审理流程;其后成立北京易正达知识产权代理有限公司,2015年出任冰狗网CEO;著有《产业专利分析之经典案例》一书。
51社保 COO 胡万军
分享主题:《初创企业的成本优化及风险防范》
资深企业信息化专家,一直专注于企业运营和流程优化,曾就职于百度和拉手网,担任企业信息化项目负责人,就职于百度公司期间,整体负责百度ERP项目的推进,支持并参与百度财务、人力资源管理、销售、集团预算、财务报表等信息化项目,就职拉手网期间担任公司财务、人力资源管理系统项目经理。
猿圈 CEO&创始人 郑萌
分享主题:《初创企业如何打造团队》
做为一个资深程序老猿,带了10几年的技术团队,凭借对技术人才和企业的理解,做了一个围绕程序猿招聘的相关项目。在这个巨缺猿类的时代,想让大家辨别真假猿,猿圈就是你的火眼金睛。自主研发Android和iOS云端编译引擎,结合基于大数据的人工智能分析,猿圈是目前是国内唯一一家做程序员代码挑战的平台。
百度高级市场主管:贾春雨
分享主题:《初创企业如何做好营销》
2010年加入百度,百度金牌营销讲师。拥有丰富的营销经验及互联网推广技巧。目前专注于百度推广研究及营销效果分析
活动流程:
13:30-14:00 签到
14:00-14:45 《初创企业知识产权风险防范》
14:45-15:30 《初创企业的成本优化及风险防范》
15:30-16:15 《初创企业如何打造团队》
16:15-17:00 《初创企业如何做好营销》
17:00-17:10 抽奖
17:10-17:20 互动答疑
17:20-17:30 合影留念
特别感谢
北大创业训练营对本次活动的大力支持! 收起阅读 »
77.4%份额,环信高居SaaS移动端客服市场第一的背后
报告显示,经过十年发酵的沉淀,SaaS客服市场正从话音呼叫中心、网页端客服向全媒体架构的统一客服平台升级,经过2015年的启动期,2016年SaaS客服行业将进入高速发展期。报告还对当下新兴并逐渐成熟应用的移动端客服市场份额进行了排名,截止到2015年第三季度,环信移动客服在SaaS移动端客服的用户覆盖占比高达77.4%,位居行业第一。
环信占据SaaS移动端客服第一:市场占有率高达77.4%
目前来看,中国SaaS客服市场的成长路径相当清晰。PC时代诞生了最早的传统话音呼叫中心,PC互联网时代诞生了网页在线客服,社交媒体时代诞生了微信、微博等社交媒体客服。进入2015年后,随着移动互联网如电商、O2O生活服务市场的井喷,消费者全面转向移动设备,将移动端客服推到了风口浪尖。这一代客服产品的特点是原生支持移动端APP,并同时支持多种渠道的接入如电话,网页和微信。通过云服务SaaS形式降低用户使用成本,大量运用人工智能技术提高效率。因此,新一代客服正日益成为移动互联网时代的企业的标配。
就此,易观智库出具的SaaS客服报告显示,通过锁定有客服入口的主流APP,统计使用移动端客服功能的APP活跃用户数,以此来计算移动端客服产品的用户覆盖占比。结果显示,截止2015年第三季度,环信移动客服用户覆盖占比达到了77.4%。对于未来SaaS客服的整体表现,易观智库也做了预测,2014年,中国SaaS客服市场规模为380亿元,2015年预计将达到490亿元,年增长率约为22.4%,2017年会增长到680亿元。
SaaS客服主流厂商对比:环信三大优势
目前,市场上盯住SaaS客服蛋糕的主要有三大流派,一是传统话音呼叫中心转型过来的厂商,天润融通是一个代表,经营呼叫中心十余年,依托网络交换机整合不同来源的客服需求,语音客服是其护城河。容联投资的七陌也属此类;二是PC互联网时代兴起的网页端客服,Live800最为典型,但网页端增速明显已经放缓,且有被新兴客服渠道如社交媒体和APP客服分流的态势;三是以环信为代表的移动端云客服。三类厂商偏重不同,但最终都会走向全媒体客服的形态。
环信以移动端客服、全媒体客服、智能机器人客服为核心切入点。
有人奇怪,环信成立移动客服的时间并不是最长的,凭什么能一举拿下移动端客服第一的位置呢?实际上有三点理由支撑。
一是环信起家于环信即时通讯云。环信即时通讯云在PaaS市场的份额很高,服务了一大批的一线互联网公司和头部app。环信延伸出客服产品是其PaaS平台SaaS化扩展的过程,继承了一批优势客户资源,更容易得到市场的认可和信赖。
二是未来全媒体客服市场,智能化是一个趋势,但国内客服厂商中,拥有自主知识产权的人工智能、机器问答,语义分析技术实力的并不多,大多数都采取了集成第三方技术的方式。相比,环信一开始就深耕智能问答客服机器人的核心技术,建立核心算法创建应答模型,在实际问答中不断修正、训练和学习,能帮助消费者解答60%-80%的常见问题,提升服务满意度,并减少人工投入。长期看,智能问答机器人是客服产品的标配和核心竞争力,因此环信并没采取集成第三方机器人技术的方式。
三是全媒体客服的四个主要客服渠道,即语音呼叫中心,微信、网页端,移动端APP中的前三个渠道的技术门槛并不高。比如语音呼叫中心技术已经非常成熟了,微信客服只是集成微信提供的接口,而网页端客服基于轮询技术,没有什么技术含量,这也是国内一下子冒出一大批SaaS客服的原因。但随着移动互联网的深入发展,消费者全面转向移动端,移动端APP客服这个接入渠道将成为整个全媒体客服的最至关重要的一环。而IM长连接技术是移动端APP客服的基石,IM长连接技术的实力强弱,能否做到弱网环境下消息必达,能否支持千万级用户同时在线,这些都是企业选购移动端客服产品的重要考量目标。而这些也正是环信等即时通讯云平台起家的厂家的“后院”。这一点在竞争后期会表现出来。
未来SaaS客服的三大趋势:全媒体+移动化+智能化
未来,SaaS客服会呈现三个明显的趋势。首先是客服中心将全面转型为全媒体客服,即呼叫中心+网页在线客服+社交媒体客服+移动端客服的形态,传统呼叫中心将从饱和期进入衰退期,并被移动客服逐步蚕食。同时,智能化的应用广度和深度将加强,竞争壁垒会走高。当然,全媒体会是百舸争流的竞争局面,短兵相接的现象暂时未上演。
其次是移动端客服将扮演越来越重要的角色。消费者全面转向移动终端的大趋势已经毋庸置疑,移动端客服产品的实力,将成为客服软件厂商的竞争焦点。
最后则是客服中心角色的转变,由成本中心向盈利中心升级,开始承担更多的营销、销售的职责。过去是以客服工单为主,沟通关系被动,职能隔离且偏售后,与销售、营销部门无协同关系。但未来客服的业务链条将“并联”营销、销售和售后环节,是互联网时代企业与用户的“第一连接点”,承担客户关系维护、二次销售、营销等职能,成为盈利中心。
虽然环信在移动端客服市场占竞争优势,但着眼未来全媒体、多形态融合的SaaS客服,平台化会催生更丰富的生态,特别是营销、销售等新角色的增强,让客服与前端的营销、CRM系统,以及企业内部的协同办公等模块,产生更多的交叉和整合地带。所以总体看,SaaS客服市场还处于一个初级阶段,企业仅仅是试水期,场景化有待挖掘,平台化还未开始,未来还存在诸多的变数。 收起阅读 »
一乐:当你手抖删了线上数据库..
一乐,aka 梁宇鹏
现任环信首席架构师兼IM技术总监,负责即时通讯云平台的整体研发和管理。曾任新浪微博通讯技术专家,负责微博通讯系统的设计与研发。
2016年1月18日,新年刚过,距离噩梦的圣诞节已经过去三周。已经好多天没有线上报警,群里一片安静,大家都在享受这份宁静与安逸。唯一不一样的是,有集群的迁移工作要做,相关人员干劲十足,已经连续三天通宵。按照惯例,为了保险起见,线上操作都在夜里进行。
如果说这几天最怀念的时光,也许就是这一天了,因为在第二天,我们的一个线上数据库出了问题。
19日上午10点,陆续有用户抱怨,一个接口的数据丢失,而之前删除的数据又出现了。这时候我们的运维同事贴出一个截图,发现有一个数据同步的进程,从凌晨五点开始运行,把线上数据库覆盖,数据一夜回到了解放前!
好在运气好,在这个覆盖发生之前,有一个备份。
修复工作马上展开,先把主从切断,主库利用备份数据重启,从库用来进行比对,恢复增量数据……(部分内容由于当地政策,未予显示)
然而事情并没有结束。这时候内部出现了一个声音高喊,我们一定要惩罚!惩罚这个人,让他知道服务稳定性的重要!
有没有觉得似曾相识?类似的情况其实经常发生。而很多事情就是这样,好像是日常中的一个插曲,却对团队和公司的发展产生着微妙又长远的影响。
是的,我说的是惩罚。
让我们看看惩罚是做什么的
以儆效尤?如果当事人玩忽职守,故意破坏,也许有一些作用。我这里用了也许,因为真出现这种情况的话,可能不是惩罚就够了的。但如果价值观没有问题,这点却未必有效。因为事故已经可以对当事人造成足够压力,增加罚款并没有什么必要。
解气么?公司变大必然出现分工,而各个团队之间的沟通也会变弱。每出现一个问题,其实都是整个公司的问题,用户需要安抚,市场需要维护。这时候就很容易发出一种声音,你看你总给我们添麻烦。这种指责和随后的处罚除了让发声的人心里痛快,该做的事情并没有减少。
它们并没有创造什么价值,却带来了很多你不想要的东西。
更差的工作表现。因为惩罚带来的畏首畏尾,以及随之而来的挫败感,都会让一个人的工作效率大打折扣。
错误的工作态度。谁都知道疲劳作战效率不高容易出错,既然多做多错,少做少错,为什么要去加班加点赶什么进度呢?多一事肯定不如少一事。
隔阂的团队。出了问题就开始指责,那出问题之前的加班加点为了谁呢?一个彼此间互相信任的团队与一个互相防备的团队,差距也是显而易见。
最重要的是,它让技术团队偏离了对技术的追求,而把目光收回到内部关系上,这自然会放慢前进的步伐,这对创业公司将是致命的。
速度是小公司取胜竞争对手直至打败大公司的关键。
不要惩罚不意味着拒绝进步
我们这么做,是因为我们也相信,促使个人和团队成长的,应该是团队的荣誉感和为之努力的心,而不是对惩罚的恐惧。
但我们也不能停在这个地方。如果连自己的教训都无法总结并长成经验,也注定是悲剧的。所以还是回归本初,看看真正想要的是什么。
我们想要的,不过是避免类似事情的发生。
先看一则旧闻。
2015年10月20日,德意志银行外汇部门的一名初级交易员将一订单中的「净值」错误处理为「总额」,令德意志银行向一家美国的对冲基金客户白白送出了60亿美元。 http://wallstreetcn.com/node/224923
这种输入上的低级错误,金融业里叫胖手指,而避免的最重要的方法就是两人法则,我也更喜欢它第二个名字,四眼原则(four eyes principle)。
https://en.wikipedia.org/wiki/Fat-finger_error
它提醒了我们,在关键业务上需要有人结对。鉴于现在工作的远程状态,我们使用了Tmux的会话共享模式,两个人可以通过相同的会话来共享控制台以及键盘输入。
技术可以做到更多
四眼原则用来做紧急措施是可以的,但毕竟有交互成本。而人在精确性上天生不如机器,因此要确保问题不再发生,还要用一些技术手段才行。
由于命令执行的是一个历史命令,而出错的运维人员进入了一个前人遗留的Tmux会话,或者是按了向上或者是进入时的回车直接执行了CTRL-R留下的命令。于是我们
修改了数据恢复的命令,强制进行二次确认;
对危险命令进行了别名处理;
禁止了Tmux的默认session,使用Tmux的人员强制使用别名。
所以你看,人的问题也可以用技术手段来解决。
技术驱动和技术导向
互联网发展仍是日新月异,挑战无处不在。要想变挑战为机遇,只有创新和技术才有可能。只有重视技术的公司,才能充分发挥技术人员的能动性,也将更容易在技术的竞争中胜出。
我们经常开玩笑,很多公司,做不到技术驱动,因为他的每一步都是领导提出领导拍板,它只能叫领导驱动。而如果一个公司在遇到事情之后就总是想到惩罚,不注意保护和发挥技术人员的能动性,技术导向也只能是一个口号。
说到底不过一句话。一个团队或公司,要变成什么样子,跟她迈出的每一步都有关系。
毕竟罗马不是一天建成的。
收起阅读 »
环信IM 3.0 Lite发布
长假归来,未做好的仍继续!本次IM 3.0 Lite为各位大大们带来了全新的通信协议、全新的SDK
SDK 更新日志
1、全新的通信协议:全新的基于消息同步的私有协议,在不稳定网络环境下更稳定更省流量,确保消息投递的可靠、顺序以及实时性,并具有更高的安全性。同时提供了更好的扩展性,将支持更多的对接和设备同步场景。
2、全新的SDK:全面重构,将核心通信模块做了更好的封装;简化了接口,结构更清晰,集成更容易;提升了登录速度和弱网络环境下的可靠性编辑
有没有很期待呢,看着就想立马体验下!在这里要提醒各位大大们,Lite不包含实时音视频,如需使用实时音视频请下载Full版本
SDK 2.x至3.0升级指南
Android点击了解Android升级指南
IOS点击了解IOS升级指南
文章的最后附上IM 3.0 Lite下载地址,欢迎各位大大们升级体验,在使用过程中有任何优化建议、寻找帮助都可以直接下方评论,我们会及时处理您的每一条留言!
IM 3.0 Lite下载地址
IM3.0点击下载
收起阅读 »
Android EaseUI 关于设置昵称、头像
在调用EaseUI.getInstance().init初始化之后去设置用户信息提供者
//get easeui instance
EaseUI easeUI = EaseUI.getInstance();
//需要easeui库显示用户头像和昵称设置此provider
easeUI.setUserProfileProvider(new EaseUserProfileProvider() {
@Override
public EaseUser getUser(String username) {
return getUserInfo(username);
}
});
getUserInfo是自己实现的一个方法,在这个方法里去根据传入的username获取本地保存的对应的昵称、头像,设置给EaseUser的对象,并返回。
easeui里显示昵称、头像的时候会去调用EaseUserProfileProvider这个接口去获取EaseUser对象,会去执行在初始化之后设置的getUserInfo方法,如果没有显示昵称、头像,你就要去看getUserInfo里是否拿到昵称、头像设置给EaseUser对象了。
获取昵称、头像显示,我这里给大家两种方案,昵称、头像都保存在自己的服务器。
第一种
可以在登录之后去服务器获取所有好友的昵称、头像,包括自己的,保存在本地,getUserInfo方法里就去根据传入的username去本地获取,设置给EaseUser对象返回。
第二种
可以在getUserInfo方法里去判断本地是否有保存对应的昵称和头像,没有就发送网络请求去服务器获取对应的昵称头像保存到本地,设置给EaseUser对象返回 ,然后发送广播到聊天界面去提示刷新,刷新之后就会执行getUserInfo方法拿到本地的昵称、头像。
头像、昵称更新
用户请求你的服务器修改了昵称、头像,你的服务器去调用rest给这个用户的所有好友,发条透传消息,提示去更新本地保存的昵称、头像
收起阅读 »
关于Android在添加好友时邀请收不到的问题
1. 首先我们要看看好友监听是否在application或MainActivity中注册,要保证在接收邀请时,监听处于监听状态,也就是没有被消毁和取消注册。
2. 检查监听注册是否正确,在监听的下方是否加了:EMChat.getInstance().setAppInited();
3. 打个断点看看,这个好友邀请的监听onContactInvited(String username,String reason)是否在执行(见Demo中DemoHelper),具体代码如下:
public void onContactInvited(String username, String reason) {
// 接到邀请的消息,如果不处理(同意或拒绝),掉线后,服务器会自动再发过来,所以客户端不需要重复提醒
List<InviteMessage> msgs = inviteMessgeDao.getMessagesList();
for (InviteMessage inviteMessage : msgs) {
if (inviteMessage.getGroupId() == null && inviteMessage.getFrom().equals(username)) {
inviteMessgeDao.deleteMessage(username);
}
}
// 自己封装的javabean
InviteMessage msg = new InviteMessage();
msg.setFrom(username);
msg.setTime(System.currentTimeMillis());
msg.setReason(reason);
Log.d(TAG, username + "请求加你为好友,reason: " + reason);
// 设置相应status
msg.setStatus(InviteMesageStatus.BEINVITEED);
notifyNewIviteMessage(msg);
broadcastManager.sendBroadcast(new Intent(Constant.ACTION_CONTACT_CHANAGED));
}
当然,类似的群组邀请收不到的问题也是类似的,具体排查思路和上面雷同,邀请监听的代码如下:
/**
* 群组变动监听
*/
class MyGroupChangeListener implements EMGroupChangeListener {
@Override
public void onInvitationReceived(String groupId, String groupName, String inviter, String reason) {
boolean hasGroup = false;
for (EMGroup group : EMGroupManager.getInstance().getAllGroups()) {
if (group.getGroupId().equals(groupId)) {
hasGroup = true;
break;
}
}
if (!hasGroup)
return;
// 被邀请
String st3 = appContext.getString(R.string.Invite_you_to_join_a_group_chat);
EMMessage msg = EMMessage.createReceiveMessage(Type.TXT);
msg.setChatType(ChatType.GroupChat);
msg.setFrom(inviter);
msg.setTo(groupId);
msg.setMsgId(UUID.randomUUID().toString());
msg.addBody(new TextMessageBody(inviter + " " +st3));
// 保存邀请消息
EMChatManager.getInstance().saveMessage(msg);
// 提醒新消息
getNotifier().viberateAndPlayTone(msg);
//发送local广播
broadcastManager.sendBroadcast(new Intent(Constant.ACTION_GROUP_CHANAGED));
}
@Override
public void onInvitationAccpted(String groupId, String inviter, String reason) {
}
@Override
public void onInvitationDeclined(String groupId, String invitee, String reason) {
}
@Override
public void onUserRemoved(String groupId, String groupName) {
//TODO 提示用户被T了,demo省略此步骤
broadcastManager.sendBroadcast(new Intent(Constant.ACTION_GROUP_CHANAGED));
}
@Override
public void onGroupDestroy(String groupId, String groupName) {
// 群被解散
//TODO 提示用户群被解散,demo省略
broadcastManager.sendBroadcast(new Intent(Constant.ACTION_GROUP_CHANAGED));
}
@Override
public void onApplicationReceived(String groupId, String groupName, String applyer, String reason) {
// 用户申请加入群聊
InviteMessage msg = new InviteMessage();
msg.setFrom(applyer);
msg.setTime(System.currentTimeMillis());
msg.setGroupId(groupId);
msg.setGroupName(groupName);
msg.setReason(reason);
Log.d(TAG, applyer + " 申请加入群聊:" + groupName);
msg.setStatus(InviteMesageStatus.BEAPPLYED);
notifyNewIviteMessage(msg);
broadcastManager.sendBroadcast(new Intent(Constant.ACTION_GROUP_CHANAGED));
}
@Override
public void onApplicationAccept(String groupId, String groupName, String accepter) {
String st4 = appContext.getString(R.string.Agreed_to_your_group_chat_application);
// 加群申请被同意
EMMessage msg = EMMessage.createReceiveMessage(Type.TXT);
msg.setChatType(ChatType.GroupChat);
msg.setFrom(accepter);
msg.setTo(groupId);
msg.setMsgId(UUID.randomUUID().toString());
msg.addBody(new TextMessageBody(accepter + " " +st4));
// 保存同意消息
EMChatManager.getInstance().saveMessage(msg);
// 提醒新消息
getNotifier().viberateAndPlayTone(msg);
broadcastManager.sendBroadcast(new Intent(Constant.ACTION_GROUP_CHANAGED));
}
@Override
public void onApplicationDeclined(String groupId, String groupName, String decliner, String reason) {
// 加群申请被拒绝,demo未实现
}
}
收起阅读 »
环信给大家拜年咯!祝大家新春快乐,猴年大吉!
环信祝大家猴年大吉
辞旧迎新,2015年已经随着新年的钟声渐渐远去,但是给中国企业级服务市场所带来的深远影响才刚刚开始。随着中国人口红利的消退、经济走弱带来的各行业毛利下滑以及移动互联网红利的凸显,通过Saas提高企业运营效率,节省成本,成为企业服务加速爆发的核心驱动力,SaaS领域将会迎来一个爆发式增长的黄金时期。
2015年是中国企业级服务元年,也是中国SaaS元年。企业服务市场因此成为资本追逐的热点,而其中环信更是明星中的明星公司,一年时间实现四轮融资。环信从连接“人与人”为愿景的即时通讯云产品出发,进而在PaaS平台上生长出了连接“人与商业”的SaaS产品环信移动客服。同时还逐步上线了环信大数据产品、环信反垃圾产品,打造了一个IM蓝图的全产业链布局。环信推动了整个即时通讯云行业从PaaS服务向SaaS服务延展的风潮,引领了整个行业的发展趋势。
因为有你,环信连接人与人才有价值。
因为有你,环信连接人与商业才有基础。
感谢有你,环信飞速发展,一年四轮融资。
见证有你,环信即时通讯云领军行业,覆盖TOP20领域TOP10客户。
见证有你,环信移动客服占据SaaS移动端客服市场77.4%份额居行业第一。
感谢有你,环信大数据产品,反垃圾服务等如雨后春笋茁壮成长。
感谢有你,感恩有你,感激有你,2016“环信”有“你”更精彩!
环信祝福小伙伴们,新春快乐,猴年大吉!
融资情况环信一年时间内完成了4轮融资。天使轮为经纬中国500万人民币、A轮为SIG 500万美元、A+轮为红杉资本300万美元,B轮融资1250万美元,由红杉资本领投,经纬中国和SIG跟投。是即时通讯云和SaaS客服领域融资最快、资金最充裕的平台。业绩规模环信是国内起步最早、规模最大的即时通讯云平台和全媒体智能云客服平台。现已覆盖包括电商、O2O、互联网金融、在线教育、在线旅游、移动医疗、智能硬件、游戏等20大领域的Top10客户,典型用户包括国美在线、58到家、快牙、随手记、猎聘、海尔等。截至2015年底,环信共服务了50833家 App 客户,SDK覆盖手机终端3.19亿,平台日均发送消息2.1亿条。
收起阅读 »
iOS开发小记:关于环信Demo3.0的使用总结以及昵称和头像问题的研究与解决
最近公司在开发一款创业项目,可以说是以即时通讯功能为主的,所以用到了第三方的即时通讯SDK----环信。相比于国内的几家即时通讯云服务商,像网易云信、融云什么的,环信应该算比较早的了吧,可以说IM云服务的老大。
我们要做的项目类似于微信,有联系人页面、聊天列表与聊天页面、设置页面,刚刚好包括了环信Demo3.0的全部内容,所以理论上应该把Demo直接嵌入工程。由于这个Demo是实现了一些IM的基本UI,但是因为环信的官方文档和视频比较欠缺,维护起来相当麻烦,所以在开发的过程中有好多次决定弃用这个Demo,自己构建UI。但是又考虑到,Demo的代码可以说相当健壮,各种机制都集成的非常好(比如好友申请和删除的回调处理),最终决定还是硬着头皮上,改Demo的UI部分以供自己使用。
环信的官方文档虽然比较欠缺,但是代码的注释和命名还是很好的,基本上可以一目了然每个变量、每个函数在做什么事情。笔者遇到的最大的问题就是好友头像和用户的显示问题,因为环信的服务器是不存储除了用户名和密码以外的其他任何数据的。解决这个问题的办法,就是将你要保存的其他用户信息保存在应用程序自己的服务器上。先来看一张官方图:
如图所示,你需要构建自己的应用服务器。环信的建议是,包括好友体系都不要用环信来维护,最好是由你APP自己的服务器来维护。但是笔者为了简化开发,并没有这样做,而是使用环信维护的好友体系,把昵称和头像存在自己的服务器上,每次从环信上获得当前用户的好友列表,再根据每个好友的用户名到自己的服务器上去获取。
需要显示昵称和头像的地方有以下几处:联系人列表、聊天页表、聊天页面、联系人和群的详情页面。环信Demo3.0中有一个叫做ContactListViewController的类正是联系人列表页面,笔者决定从这个类入手。这个类是一个常见的带Tableview的Controller,找到它的下拉刷新和tableview的几个代理方法进行尝试,发现无论如何也不能完美的实现想要的效果。于是开始研究Demo是怎样显示昵称和头像的,经研究发现,环信是使用国外的App数据储存商Parse来实现储存,于是找到Demo中存取Parse部分的代码:
在ViewDidLoad中,笔者找到了一个叫做UserProfileManager的类(绿色部分),看了看这个类的h和m文件,发现这个类就是管理存取Parse上数据的类,而且全局是一个单例。笔者认真分析了一下这个类的作用,根据它提供给外部使用的方法的名称,发现他的作用主要有以下三个,且是按照以下顺序的:
1----获取当前用户在Parse服务器上的好友数据(头像、昵称),储存到内存中或者本地沙盒中:loadUserProfileInBackgroundWithBuddy:self.contactsSource saveToLoacal:YES completion:NULL
2----根据好友的用户名(环信储存的用户名),返回内存或本地沙盒中保存的昵称: - (NSString*)getNickNameWithUsername:(NSString*)username;
3---根据好友的用户名(环信储存的用户名),返回内存或本地沙盒中保存的头像Url:- (UserProfileEntity*)getUserProfileByUsername:(NSString*)username;
其中2和3其实可以合成一个,因为头像的url一般都是用一个用户的唯一标识(数据库表中的主键)来命名,而这个唯一标识刚好可以是环信服务器上所储存的用户名字段
举个例子,在ViewDidLoad方法中,先调用方法1,获取到昵称和头像,然后在tableview的cellForRowAtIndexPath,也就是给每个cell赋值的那个方法中,先调用方法2和3,再给cell赋值。
如图所示,(绿色部分),根据model.buddy.username属性,获取到环信服务器所保存的用户名,再调用23方法得到昵称和头像url的拼接。
于是根据这个类,笔者仿照它也写了一个单例,给单例加了一个保存所有好友昵称的NSDictionary属性,这个单例对象在APP全局是唯一的,所以该属性在内存中也是唯一的,每次调用获取它的方法,不用担心是空或者重新生成新对象的问题发生。而且最好将属性设置成nonatomic的,这样可以防止在一次网络请求构建改属性的过程中被访问,导致数据错误。但是笔者还是加上了判断。笔者的这个类叫做NickNameAndHeadImage,也就是上面两幅截图中绿色注释部分紧跟的代码。并且还加入了一些判断,比如,如果昵称为空,则显示环信服务器上保存的用户名。当然,如果你想让更新即时的话,你可以在这个类中实现一些发送和接受透传消息的方法,笔者暂时没有写。
大家可以全局搜索UserProfileManager的使用地方(比如按昵称搜索,首字母排序,详情等),发现基本上就是用到了笔者所提到那三种操作,所以,可以用自己仿制的这个单例类完美的代替UserProfileManager的功能,这样就可以在不修改环信Demo逻辑的前提下,接入自己的APP服务器,这样便保留了环信Demo的所有优良特性。
下面将NickName类的代码列出,供大家参考:
#import <Foundation/Foundation.h>附上截图
@interface NickNameAndHeadImage : NSObject
+(instancetype) shareInstance;
- (void)loadUserProfileInBackgroundWithBuddy:(NSArray*)buddyList;
- (NSString*)getNicknameByUserName:(NSString*)username;
#import "NickNameAndHeadImage.h"
@interface NickNameAndHeadImage()
@property (strong, nonatomic) NSMutableArray *UserNames;
@property (strong, nonatomic) NSMutableDictionary *NickNames;
@property (nonatomic) BOOL DownloadHasDone;
@property (nonatomic) BOOL LoadFromLocalDickDone;
@end
@implementation NickNameAndHeadImage
{
}
static NickNameAndHeadImage* _instance = nil;
+(instancetype) shareInstance
{
static dispatch_once_t onceToken ;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init] ;
}) ;
return _instance ;
}
- (instancetype)init
{
self = [super init];
if (self) {
_DownloadHasDone = NO;
_LoadFromLocalDickDone = NO;
_UserNames = [NSMutableArray array];
NSMutableDictionary *dic = [[NSUserDefaults standardUserDefaults] objectForKey:dUserDefaults_Dic_NickName];
if (dic == nil || [dic count] == 0) {
_NickNames = [NSMutableDictionary dictionary];
_LoadFromLocalDickDone = YES;
}
else
{
_LoadFromLocalDickDone = YES;
_NickNames = [NSMutableDictionary dictionaryWithDictionary:dic];
}
}
return self;
}
- (void)loadUserProfileInBackgroundWithBuddy:(NSArray*)buddyList
{
_DownloadHasDone = NO;
[_UserNames removeAllObjects];
[_NickNames removeAllObjects];
if (buddyList == nil || [buddyList count] == 0)
{
return;
}
else
{
for (EMBuddy *buddy in buddyList)
{
[_UserNames addObject:buddy.username];
}
}
[self loadUserProfileInBackgroundWithUsernames];
}
- (void)loadUserProfileInBackgroundWithUsernames
{
_DownloadHasDone = NO;
//首先构造Json数组
//1.头
NSMutableString *jsonString = [[NSMutableString alloc] initWithString:@"{\"mobilelist\":["];
for(NSString *mobile in _UserNames){
//2. 遍历数组,取出键值对并按json格式存放
NSString *string;
string = [NSString stringWithFormat:
@"{\"mobile\":\"%@\"},",mobile];
[jsonString appendString:string];
}
// 3. 获取末尾逗号所在位置
NSUInteger location = [jsonString length]-1;
NSRange range = NSMakeRange(location, 1);
// 4. 将末尾逗号换成结束的]}
[jsonString replaceCharactersInRange:range withString:@"]}"];
NSLog(@"请求昵称时要发送的jsonString = %@",jsonString);
NSString *token = [[NSUserDefaults standardUserDefaults] objectForKey:dUserDefaults_String_LoginToken];
NSString *url = [NSString stringWithFormat:@"customer/contract?token=%@",token];
NSDictionary *postdic = [NSDictionary dictionaryWithObjectsAndKeys:jsonString,@"mobilelist",nil];
[HttpUtil POST_Path:url params:postdic completed:^(id JSON,NSString *str)
{
_LoadFromLocalDickDone = NO;
NSLog(@"打印JSON数据:%@",str);//打印Json数据
NSString *state = [[JSON objectForKey:@"json"] objectForKey:@"state"];
if ([state isEqualToString:@"1"]) {//获得昵称成功
//打印信息
NSString *msg = [[JSON objectForKey:@"json"] objectForKey:@"msg"];
NSLog(@"获得昵称成功:msg:%@",msg);
NSArray *array = [[[JSON objectForKey:@"json"] objectForKey:@"data"] objectForKey:@"list"];
for (NSDictionary *dic in array) {
[_NickNames setObject: [dic objectForKey:@"name"] forKey: [dic objectForKey:@"mobile"]];
}
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
[ud setObject:_NickNames forKey:dUserDefaults_Dic_NickName];
[ud synchronize];
_LoadFromLocalDickDone = YES;
_DownloadHasDone = YES;
}
else//获得昵称失败
{
_DownloadHasDone = NO;
//打印信息
NSString *msg = [[JSON objectForKey:@"json"] objectForKey:@"msg"];
NSLog(@"获得昵称失败:msg:%@",msg);
}
}
failed:^(NSError *err){
_DownloadHasDone = NO;
[SVProgressHUD showSuccessWithStatus:@"登录失败"];
NSLog(@"获得昵称失败:%@",err);
}];
}
- (NSString*)getNicknameByUserName:(NSString*)username
{
if(_DownloadHasDone == YES)
{
NSString *string = [_NickNames objectForKey:username];
if (string == nil || [string length] == 0) {
return username;
}
return string;
}
else if(_LoadFromLocalDickDone == YES)
{
NSMutableDictionary *dic = [[NSUserDefaults standardUserDefaults] objectForKey:dUserDefaults_Dic_NickName];
NSString *string = [dic objectForKey:username];
if (string == nil || [string length] == 0) {
return username;
}
return string;
}
return username;
}
其中,第一行为没有上传头像而有昵称,第二行为有头像有昵称,第三行为有头像无昵称,则显示用户名。
希望可以和大家多交流,做出更完美的App。 收起阅读 »
IOS V2.2.2 2016-02-02版本更新
流浪的脚步在外闯荡,家是永远的方向。不管你是已经到家,还是在回家的路上或还坚守在公司,环信送上最真挚的祝福,道一声朋友,祝你一路顺风,新春快乐。
环信与你同在,在距离春节最后一周,我们期待已久的ios新版本sdk发布了,这里让我们向还奋斗在一线的工程师们致敬。
以下是此次新版本介绍,文章结尾附下载链接
新功能:
实时通话新增弱网监测、暂停或打开音频视频流等API(相应增加的方法可查看文档)。
实时视频新增录制功能(相应增加的方法可查看文档)。
bug fix:
SDK bug: iphone 6s 实时视频挂断crash。
SDK bug: 优化iphone 6s 实时语音外放噪音。
SDK bug: 使用sdk发送高分辨率图片crush bug。
SDK bug: 附件下载失败,附件下载状态为成功的bug。
SDK细节调整:
提升实时语音音质
点击下载体验http://www.easemob.com/downloads 收起阅读 »
支付宝为什么拼了命做社交
支付宝真的打算做社交了吗?
福卡的玩法将进一步推动用户在支付宝上沉淀自己的关系链。以红包为支点,让用户逐步习惯在支付宝内与好友互动。
我们都知道,支付宝重点在于商业,支付只是手段而已,但本身关系链不强大,只有通过各种商业环境来布局自身的触角,通俗点讲,就是在需要使用支付业务时打开支付宝,付款完成,然后就等着被打入手机后台吧~
说到这里,我们就不得不谈下支付宝的对头”微信“了,虽然微信本身是社交,支付只是衍生,但我更愿意把他们看成竞争对手。由于微信社交平台的粘性,我们看到微信从社交化到各个领域的渗透,比如”微信红包“,”网上购物“,“生活缴费”等各种层出不穷的服务(有了用户关系链的场景真的不一样)
那支付宝这次到底是图啥呢?
支付宝其实是在构建金融场景,寻找社交和支付的结合点,借助社交的关系链给支付宝提供服务场景!
我们可以来看下未来的愿景,举个例子,你给家里的父母转每个月的孝敬费,一转过去了可以问下“妈,钱收到了吗,哦,收到了是吧,好的,最近天冷 多保重身体呀” 父母就很开心了,不仅钱收到了,还收到了子女的问候,甚至可以在手机另一边唠叨两句“哎,闺女,过年什么时候回家呀,今年男朋友带回来吗”
为什么很多公司做社交产品没有成功?
场景有了,可是用户间的沟通缺少核心技术。
用户已经有非常多的沟通渠道,比如:短信、微信甚至陌陌,经常看到在一些新上架APP里用户的沟通还停留在“请加 我微信***详聊”甚至没有通讯功能,在这个即时通讯连接人与商业的时代,拥有像QQ微信这样的收发文字、图片、语音、实时音视频这样的功能真的很重要。
我们实现即时通讯难吗?
自行研发移动IM,技术门槛高,开发周期长。
主要的技术难点包括:
1:协议和IM服务器的选择:
当前常用作IM的协议包括XMPP和MQTT,也有用SIP的,还有自行开发的私有协议。可以使用的开源的IM服务器包括OpenFire, Tigase, Prosody, Mosquitto, ejabberd等。你知道它们各自的优缺点吗,你知道哪个协议,那个IM服务器实现最适合你的需求吗,你知道你一旦选定了一个方案,你分别需要对协议和IM服务器做哪些改动和改进吗?
2:不稳定网络环境下(3G,2G,Wifi,无网络,及各种网络环境下的切换)
移动终端即时通讯长连接可靠性的维护
移动终端耗电量优化
移动终端流量优化
发送各类富媒体消息的特定处理,如语音文件格式选择,语音压缩算法,语音降噪算法,图片压缩处理,地理位置,名片,文档等
消息回执处理(ack),防止消息丢失。
离线消息处理。离线时的实时消息通知(比如通过第三方推送平台) 实时状态同步
支持千万级同时在线用户的高可靠,高并发的服务器集群架构的搭建和运维
安全
3:移动IM是一个需要长期跟进和维护的技术,并不是产品上线后研发团队就可以解散了。
作为运营者,你做好长期的技术投入的思想准备了吗?比如新的IM功能层出不穷,如匿名社交,阅后即焚,你的产品要不要与时俱进?移动IM相关的各种安全隐患和漏洞,你要不要及时修复?所以你需要问自己一个问题,移动IM技术是你的核心竞争力吗,还是只是支撑你的业务实现的一个工具?
实现即时通讯功能那么难,有没有简单的办法轻松拥有?
这里给各位推荐一家即时通讯云服务厂商--环信
环信提供基于移动互联网的即时通讯能力,如单聊、群聊、发语音、发图片、发位置、实时音频、实时视频等,让开发者摆脱繁重的移动IM通讯底层开发,24小时即可让App拥有内置IM能力。
公司介绍
环信成立于2013年4月,是一家全通讯能力云服务提供商。产品包括全球最大的即时通讯云PaaS平台——环信即时通讯云,以及全球首创的全媒体智能云客服平台——环信移动客服。截至2015年底,环信共服务了50833家 App 客户,SDK覆盖手机终端3.19亿,平台日均发送消息2.1亿条。
融资情况:
环信一年时间内完成了4轮融资。天使轮为经纬中国500万人民币、A轮为SIG 500万美元、A+轮为红杉资本300万美元,B轮融资1250万美元,由红杉资本领投,经纬中国和SIG跟投。是即时通讯云和SaaS客服领域融资最快、资金最充裕的平台。
业绩规模:
环信是国内起步最早、规模最大的即时通讯云平台和全媒体智能云客服平台。现已覆盖包括电商、O2O、互联网金融、在线教育、在线旅游、移动医疗、智能硬件、游戏等20大领域的Top10客户,典型用户包括国美在线、58到家、快牙、随手记、猎聘、海尔等。截至2015年底,环信共服务了50833家 App 客户,SDK覆盖手机终端3.19亿,平台日均发送消息2.1亿条。收起阅读 »
来自环信的新年问候
辞旧迎新,2015年已经随着新年的钟声渐渐远去,但是给中国企业级服务市场所带来的深远影响才刚刚开始。随着中国人口红利的消退、经济走弱带来的各行业毛利下滑以及移动互联网红利的凸显,通过Saas提高企业运营效率,节省成本,成为企业服务加速爆发的核心驱动力,SaaS领域将会迎来一个爆发式增长的黄金时期。
2015年是中国企业级服务元年,也是中国SaaS元年。企业服务市场因此成为资本追逐的热点,而其中环信更是明星中的明星公司,一年时间实现四轮融资。环信从连接“人与人”为愿景的即时通讯云产品出发,进而在PaaS平台上生长出了连接“人与商业”的SaaS产品环信移动客服。同时还逐步上线了环信大数据产品、环信反垃圾产品,打造了一个IM蓝图的全产业链布局。环信推动了整个即时通讯云行业从PaaS服务向SaaS服务延展的风潮,引领了整个行业的发展趋势。
因为有你,环信连接人与人才有价值。
因为有你,环信连接人与商业才有基础。
感谢有你,环信飞速发展,一年四轮融资。
见证有你,环信即时通讯云领军行业,覆盖TOP20领域TOP10客户。
见证有你,环信移动客服占据SaaS移动端客服市场77.4%份额居行业第一。
感谢有你,环信大数据产品,反垃圾服务等如雨后春笋茁壮成长。
感谢有你,感恩有你,感激有你,2016“环信”有“你”更精彩!
环信祝福小伙伴们,新春快乐,猴年吉祥!
融资情况:
环信一年时间内完成了4轮融资。天使轮为经纬中国500万人民币、A轮为SIG 500万美元、A+轮为红杉资本300万美元,B轮融资1250万美元,由红杉资本领投,经纬中国和SIG跟投。是即时通讯云和SaaS客服领域融资最快、资金最充裕的平台。
业绩规模:
环信是国内起步最早、规模最大的即时通讯云平台和全媒体智能云客服平台。现已覆盖包括电商、O2O、互联网金融、在线教育、在线旅游、移动医疗、智能硬件、游戏等20大领域的Top10客户,典型用户包括国美在线、58到家、快牙、随手记、猎聘、海尔等。截至2015年底,环信共服务了50833家 App 客户,SDK覆盖手机终端3.19亿,平台日均发送消息2.1亿条。
收起阅读 »
凡信2.0beta发布-超仿微信的开源项目 (更新了朋友圈和钱包)
关于此次更新的朋友圈版块,有些地方的处理的我觉得非常有技术分享的价值,项目为了极速开发,整个项目写得有点凌乱粗糙,但是部分功能单独拎出来讨论。会以博客的形式的解析一些功能。
可关注http://www.imgeek.org/people/huangfangyi
作者QQ : 84543217
技术讨论群:437758366(已有900名小伙伴等着你)
APP运行效果图展示
APK扫码下载体验
二维码下载不了的,直接用链接
http://120.24.211.126/fanxin/download/Fanxin.apk
github源码下载 https://github.com/huangfangyi/FanXin2.0_IM
凡信2.0beta的代码更新说明:
一、朋友圈相关
1.发布动态--文字 图片 位置
2.朋友动态列表
3.点赞
4.评论
5.识别网址
6.好友的所有动态查看
7.我的相册
8.部分功能待完善
二、钱包相关
1.零钱 -虚拟账户
2.充值 选择卡-充值-每张卡初始额度200元
3.提现 提现到卡-需要手动处理才能完成,我就不手动去弄 了,因此提现后无法到你的卡(注:此卡指的是凡信中的虚拟卡)
4.交易记录---转账、充值、提现三类
5.银行卡 后台虚拟了一些卡账号,每张卡有200的额度。添加后可充值。
6.给好友转账--后面会添加提现和在聊天页显示。
7.支付宝集成(app中常用的功能)-----集成了支付宝的SDK,由于密钥等参数都是比较重要的,已在工程中去掉了。体验这个带参数的功能,可以下载这个包-http://120.24.211.126/fanxin/download/Fanxin.apk,做了一个打赏的功能。
三、 逻辑变化:
好友关系独立化,弃用了环信的好友关系表,在后端自己管理好友关系,这样做是跟朋友圈的业务相关,因此请务必注册新的账号的测试,
前情回顾:
本项目的IM通信部分是基于第三方通信云——环信的SDK开发的。对于个人开发者或者小企业来说,做IM用第三方的也是一种趋势吧,毕竟自己整一套可供运营使用的IM系统几乎是不切实际的(技术门槛和维护成本)。之前用环信做了几个外包项目,其中有些设计和安排我觉得很赞,所以总结了以前的经验和收获,做了这套全仿微信的APP。总的来说,这里面大的架构还是沿用了环信官方提供的UIdemo,但是里面的很多的细节和大部分页面都是我精心按照微信的逻辑和UI设计进行编写的。功能上目前解决了好友体系、用户资料、单聊、群聊等社交功能,后续还会继续更新类似于更换聊天背景、搜索本地用户、朋友圈、更多聊天表情等功能。。。希望有兴趣的小伙伴能一起更新这个开源项目。 整套代码编写的时间仓促,加上作者水平有限,望理解!
第一版功能说明:
1.注册登录部分:
1.1重写了EditText的默认的蓝色底线,变成微信的绿色
1.2 登录和注册按钮对输入框进行监听,并变色
1.3 密码明文和隐藏
2.主页
2.1全仿微信底部导航
2.2 右上角加号按钮可进入 “发起群聊”和“添加朋友“
2.3 显示未读消息数和未读通知数
3.聊天列表页:
3.1 群聊头像是群成员头像的组合,有1.2.3.4.5种类型的头像
3.2 置顶功能。置顶后该会话item置于列表顶端,并像微信一样变底色
3.3 删除列表功能,删除该条会话记录
4.通讯录页
4.1 显示好友列表
4.2 进入还有申请通知
4.3 进入群聊列表
5.发现页(正在开发朋友圈功能.....)
6.用户详情页
6.1 资料设置(目前可更改的资料是:头像、昵称、性别)
6.2 微信号只能设置一次。
6.3 设置页(通知、声音、震动、退出登录)
7.用户申请通知
7.1按时间由近及远排序
7.2 显示申请理由
7.3 处理状态(已添加、同意)
8.查找添加用户
8.1 按用户的手机号查找用户
8.2 搜索的用户的存在显示用户资料
8.3 若该用户已经是好友,显示”发送消息“按钮
8.4 若该用户不是好友,显示添加好友,并要求输入申请理由
9.发起群聊
9.1可以在输入框内按用户昵称搜索好友
9.2 添加群聊的用户的头像可以动态显示在顶部
10.聊天页面
可以发送语音文字图片和视频(后续更新更多表情和设置聊天背景)
11聊天设置
11.1单聊:置顶聊天、免打扰、和清除聊天记录
11.2 群聊:显示群成员列表、增加群成员、删除群成员(群主可操作)、
修改群名称、置顶聊天、屏蔽清除群消息 收起阅读 »
致美洽,造谣抹黑和博同情不能赢得市场,好产品不需要说谎!
环信呼吁公开、公平、公正测评,规范中国SaaS客服市场
中国SaaS客服软件市场将是一个千亿级市场,但目前市场份额的很大部分还是被传统安装型软件和传统的单一语音呼叫中心所占领。中国新一代的SaaS客服厂商的共同战场是SaaS VS 传统安装软件,是移动互联网时代应运而生的创新技术对诞生在PC互联网时代的上一代客服技术的革新,提高整个客服行业的用户体验和工作效率。环信衷心希望可以团结中国新一代的SaaS客服厂商,教育市场,培育市场,一起把中国的SaaS客服市场做大做强。
环信一直秉承着用数据和事实说话,环信郑重承诺,环信公开发布的所有数据包括融资金额、产品数据和客户量等信息均真实可靠,环信愿意为此承担一切法律责任和道德风险。
环信提倡在一个公开、公平、公正的环境下用第三方的评测标准和透明的用户数据来规范中国SaaS客服市场,大家带上自己的TOP 用户一起来比一比,美洽,敢约么?
环信用数据说话,不服来战,美洽敢约么?
环信在即时通讯云领域耕耘数年,积累了大量的用户和良好的口碑,成就了环信“连接人与人”的愿景。环信移动客服是在环信即时通讯云PaaS平台上生长出来的SaaS产品,环信移动客服SDK与环信即时通讯云SDK共享核心代码,历经5万余家APP实践验证,2年半迭代开发,承担着环信“连接人与商业”的愿景。环信携其优势移动端技术和客户资源,在SaaS客服的移动端客服领域后发先至,高歌猛进也是理所当然。
企业级服务市场从来都是靠产品技术和市场销售实力取胜,而不是靠造谣、抹黑和博同情,针对美洽质疑报告数据,环信提议美洽带上自己的TOP用户一起来比一比,敢约么?
具体提议如下:(环信已将评测方案开源在github上,其余友商有兴趣参加,环信同样欢迎。)
1,用户:提交各自TOP50移动端app用户名单,需要有明确客服入口,需要检测明确使用了自己的SDK。(针对美洽质疑TOP5/TOP10用户不代表整个厂商市场覆盖,那我们直接加码到TOP50客户,如果对方不足50家客户的可以酌情减少到40家)
2,机构:主持评测机构:第三方公证处。数据来源机构:各大应用商店,App annie、易观千帆、QuestMobile等。
3,评测方法:1、各自Top50 App用户的总累计市场下载量。2、、各自Top50 App用户的总累计日活量。为保证日活数据的透明公正,可采用至少2家研究机构的日活监控数据,如app annie、易观千帆、QuestMobile等。
4,如果你敢接受环信的挑战,请在2月19日前提交申请。SaaS移动端客服市场占有率公开评测方案GitHub开源地址:https://github.com/haozki/servicecloudmarket
市场份额不是大锅饭:主流SaaS客服厂商均认可,为啥单美洽质疑?
易观《2015中国SaaS客服市场专题研究报告》发布后获得了广泛传播。其中部分领先厂商比如逸创云、智齿、爱客服等均第一时间解读了,并在各自微信和优势媒体传播了报告里的趋势,引用了报告里的核心市场数据。
逸创云客服微信描述易观智库为国内知名数据机构,智齿客服微信描述易观智库为权威的第三方机构,这是为什么呢?
为啥美洽你口中的“大佬”《2015中国SaaS客服市场专题研究报告》代表厂商天润融通和Live800不质疑,这么多比你优秀的厂商不质疑,为什么只有你质疑?在移动端美洽1.7%的真实市场占有率影响到你投资人信心了是么?市场不是大锅饭,靠的是实力。
美洽:恶意中伤,黑稿路人群全覆盖,误导不明真相群众,红包发到手抽筋。
以上为部分大群截图,绑架友商恶意中伤环信,妄图鹤蚌相争渔翁得利,可惜友商都有职业操守。请问程总您是如何得知逸创、Udesk、环信三家的核心市场数据的?还得出结论环信排第四,靠冥想么?
组团将黑稿发到行业群里供大家讨论本也无可非议,刷爆上百个微信群也没什么,砸红包诱发转发都能理解,美洽COO程总将黑稿发到众多不明真相的普通路人群,比如“北京程氏宗亲群”是单纯为了冲阅读数?还是里面有一股来自东方的神秘力量?
产品和市场落后可以追,最可怕的是固步自封、观念落后
根据官网显示美洽成立于2013年,而环信移动客服2014年12月开始内测,于2015年4月正式上线,环信移动客服是晚于美洽进入市场,但现在市场占有率环信远超美洽,美洽有反思过为什么吗?
2015年某国内最大O2O平台的App内置客服选型,其中某友商爆出两年完全免费的价格,但最后仍旧付费采购了环信移动客服。某友商是否在失败后在产品和技术层面进行了反思:
1,你的移动端客服是否基于IM长连接技术?只有基于IM长连接技术的移动端客服才能保证消息必达、24小时在线,这已经是常识。
2,SaaS云客服要支持互联网上的海量用户,你的移动端客服是否有经过验证的支持千万级用户同时在线咨询的能力?
企业级服务产品的核心竞争点是产品和技术实力,是靠高质量的研发团队的长期和巨量的投入,不是靠价格,更不是靠打嘴仗,发黑稿博取同情,绑架用户。
易观报告客户服务领域关于移动端和全媒体的趋势已经不需累述,如果SaaS客服“移动端”指标还算是程总口中所谓意淫的“中国特色”指标,那么很遗憾您的观念起码已经落后整个SaaS客服行业了。如果行业厂商一直固步自封,停留在原来的产品和市场圈子自沾自喜,将会被新一轮先进的生产力无情的淘汰,这也是他们为什么市场占有率低的主要原因。当然如果程总能和谈笑风生的 Nielsen 或者其他机构一起在以下美洽提议的三个方面: “付费用户数占比”、“付费金额占市场总额比”和“注册用户占比”做一个中立报告,环信将积极参与并提供数据。
环信新媒体小编努力工作效率高也有错?行业调研机构发布报告以后,第一时间完成解读借势传播难道不是每个厂商市场部的最起码职责么?由此可以看出美洽的全方面落后,不单只在市场部。
俗话说“离开剂量谈毒性”都是耍流氓,抛开数据谈第一是不是更耍流氓?美洽COO程总说:“反正美洽比环信领先的多了。”亲,原因呢?数据呢?哼,讨厌、恶心、呸,就是比你领先的多…
不堪入目的骂街都来了
造谣和吹牛逼三神兽:“我同学、我朋友、我亲戚”。本来想深度扒扒易观智库的,后来想想还是省省力气吧…其实大家真的很想听。下面这幅图还给您,不谢。
Udesk:你没看清楚数据,我不怪你
求Udesk小编手下留情,马上大过年的,就不要打打杀杀啦。重要的事情说三遍:“移动端、移动端、移动端。”这个图里说明的是环信占中国SaaS移动端客服市场比例,而不是整个市场。也许媒体自发转载传播的标题有歧义,你没看清楚数据我不怪你。
写在最后,2015年是中国SaaS元年,行业需要自律,同时也需要新标准。环信衷心希望可以团结中国新一代的SaaS客服厂商,教育市场,培育市场,一起把中国的SaaS客服市场做大做强,市场足够大,大家都可以活下来。 收起阅读 »
【有奖调查】关于表情的使用需求
萌岛是一个专注于互联网卡通形象的服务平台,汇聚国内专业卡通形象设计师,大家熟悉的各路表情包设计大神,都在萌岛。萌岛已为国内多个互联网产品提供卡通形象和表情设计服务。
1、你是否想要类似天猫和京东狗这样的卡通形象?
2、你是否想要企业专属定制的卡通形象表情包?
3、单个表情制作费用多少钱能够接受?500以内 / 500-1000 / 1000-2500 / 其它价格(可以具体说明)
4、关于表情有任何想法请告诉我们。
如果对卡通形象表情感兴趣,还可以关注萌岛的微信服务号了解哦。
收起阅读 »