环信客户互动云v5.31已上线,新增随机质检功能,使质检结果更加公平、公正
本次更新的主要内容为:优化智能机器人功能,支持为机器人知识规则设置应答策略,使机器人能够根据不同的渠道关联、时间计划发送不同的答案。新增随机质检功能,采取系统对质检样本随机抽样的方法管理质检流程,避免质检作弊,使质检结果更加公平、公正。环信客户互动云v5.31_产品更新说明
发布日期:2017-12-25
客服模式
客服变更在线状态需要审批
新增“客服变更在线状态需要审批”功能。当管理员打开“客服变更状态需要审批”开关时,普通客服将在线状态从“空闲”切换为忙碌、离开、隐身状态需要管理员审批;当管理员关闭此开关时,普通客服可以随意切换在线状态。
管理员切换在线状态不受此开关影响。
客服变更在线状态:
开关打开时,客服将在线状态从“空闲”切换为忙碌、离开、隐身状态时,将收到弹窗提醒,需填写状态变更理由,并提交至管理员审批。
管理员审批状态变更:
管理员收到客服的状态变更请求后,将在消息中心收到系统消息提醒。可以进入“管理员模式 > 审批管理”页面,审批该请求。
审批通过后,系统自动完成客服的状态切换。同时,系统发送系统消息提醒客服,可在消息中心页面查看。
“客服状态变更需要审批”开关:
需要对客服的在线状态变更进行审批时,管理员可以进入“管理员模式 > 设置 > 系统开关”页面,打开“客服状态变更需要审批”开关。
待接入会话列表显示坐席名
待接入页面的会话列表增加一列:坐席名,用于显示会话指定的客服名称。
注:若会话未指定客服,则只显示技能组名称,不显示客服名称。
管理员模式
机器人知识规则
机器人知识规则新增分类管理、日志管理、和应答策略。日志管理支持管理员查看知识规则相关的日志。分类管理支持将知识规则添加至不同的分类,方便查询和管理知识规则。应答策略为知识规则中的答案的发送策略,支持设置根据不同的渠道关联、时间计划发送不同的答案。
分类管理
在机器人的知识规则页面,可以添加、编辑分类,并修改知识规则所在的分类。
查看分类:
在分类列表中选择任意分类,查看该分类中的知识规则。
管理分类:
在分类列表下方,点击“管理分类”按钮,添加、编辑分类。
修改分类:
选中一条或多条知识规则,在弹出窗口中点击“修改分类”按钮,修改选中的知识规则所属的分类。
日志管理
日志管理支持管理员查看知识规则相关的日志,可以按照时间范围查询,以及导出。
在知识规则页面,点击“添加规则”右侧的下拉按钮,点击“日志管理”按钮,查看日志。
应答策略
支持为知识规则中的答案单独设置发送策略,在添加、编辑知识规则时,均可以设置发送策略。策略包含策略名称、条件(渠道关联和时间计划)、执行(知识规则的答案),当满足策略中的条件时,发送对应的答案给客户。
当知识规则中有多个答案时,如果不设置发送策略,则默认随机发送其中一个答案。
编辑知识规则:
在知识规则页面,点击知识规则右侧的“编辑”按钮,可以编辑知识规则。包括添加/编辑问题、添加/编辑答案。编辑完成后,点击“确认”。
添加发送策略:
在添加、编辑知识规则页面,点击“添加策略”按钮。
填写策略名称,选择一个渠道关联(不选择时,策略不生效),选择一个时间计划(不选择时,默认为全部时间),选择知识规则的一条答案,并保存。
设置好发送策略后,当客户的消息匹配知识规则的问题,并满足渠道关联和时间计划这两个条件时,发送策略中设置的答案给客户。
随机质检
新增随机质检功能。采取系统对质检样本随机抽样的方法管理质检流程,避免质检作弊,使质检结果更加公平、公正。
随机质检功能为标准版/旗舰版增值服务,如需开通,请提供租户ID并联系环信商务经理。
查看质检任务
质检任务由管理员/质检员创建,质检任务包含系统基于筛选条件随机抽取的客户会话。
在随机质检页面,管理员可以查看所有质检任务;质检员可以查看所有/自己创建的质检任务。
设置质检权限
进入“管理员模式 > 设置 > 权限管理”页面,设置质检员查看质检任务的数据权限。
- 租户:支持查看系统内全部质检任务
- 客服:只能查看自己创建的质检任务
创建质检任务管理员/质检员每次可以为自己创建一条质检任务。质检任务分为质检中、已完成两个状态。当有质检中的任务时,需要先完成该质检任务,才可以创建新的质检任务。在随机质检页面,点击右上角“创建质检任务”按钮,设置相关质检条件,再次点击“创建质检任务”按钮。系统根据质检条件随机抽取对应数量的会话,并创建质检任务。
- 任务名称:质检任务的名称。
- 时间范围:必须为一个月内,如11月1日至11月30日。
- 会话抽样范围:包含会话来源渠道、技能组、关联、会话标签、参与客服。
- 会话质检条件:包含首次响应时长、会话时长、平均/单次响应时长、访客/坐席消息数、满意度评价。
- 抽样数量:必须为1至300之间的数字。
完成质检任务管理员/质检员可以随时对质检中的任务里的会话进行质检评分,完成所有会话的质检评分后,即可完成该质检任务。在随机质检页面,点击自己创建的质检任务,可以查看任务详情以及会话列表。点击任意会话,可查看会话详情,并对会话进行质检评分。
“24小时排队趋势”显示排队的会话详情在“统计查询 > 排队统计”页面,点击“24小时排队趋势”中的柱状图,可以查看对应的排队的会话详情。注:从该版本开始,“排队统计”仅支持筛选最近3个月及当月的统计数据。例如,本月为12月,可筛选9月至12月的数据。Android SDK访客端当前版本:V1.1.3新功能/优化:
- 支持消息预知功能(增值服务)
- 支持FCM推送
环信客户互动云更新日志http://docs.easemob.com/cs/releasenote/5.31
环信客户互动云登陆地址http://kefu.easemob.com/ 收起阅读 »
一款基于环信开发的APP-超级家委会
“超级家委会”是一款基于环信开发的集活动、聊天、项目管理为一体的APP。
如需项目合作,请联系:石锋 18616870207(微信同号)
【功能介绍】
消息
享畅聊,与微信一样好用的通讯功能,免费即时沟通,但在这里只聊工作,去除娱乐化,支持单聊、普通群聊、活动群聊、部门群聊、团队群聊。
【单聊】和好友实时沟通
【群聊】邀请特定的人组建群聊
【活动群聊】对活动感兴趣的人员可以一起畅所欲言,也可和主办方沟通疑问,活动群聊 页面可一键直达活动
【部门/团队群聊】提供团队内部聊天功能,随时与同伴和团队沟通和讨论工作,让沟通更顺畅
【系统消息】实时接收重要信息的通知,如审核申请,报名信息,关注,评论等,并及时做出反馈;
实现功能
- 好友/群内的文字、表情、图片、位置、收藏、名片发送和接收
- 查看群信息
- 快速查找
- 新建群
- 系统消息推送
- 删除会话
- 获取未读消息
- @功能正在实现中...
项目
提供了包括项目管理、行政办公、教育培训、营销工具等基本应用和丰富的插件功能,通过精心设计打造出体验出色的应用,且每个项目可直达相应群聊,让你和团队成员随时随地参与协作。
【快速立项】明确工作目标并创建项目 ,邀请团队成员加入项目一起来开展工作;
【任务管理】新建任务,指派执行者和添加参与者,添加并更新相关任务信息;
【工作安排】创建「日程」来安排会议、 记录外出和预约重点活动等等工作,也随时了解其他项目成员的工作安排;
【进展同步】通过任务列表随时关注项目进展的更新,进入项目查看具体的进展信息;
【插件丰富】丰富的移动办公应用接入,任务、签到、审批、笔记、文件、费用、班级、学生老师、课程、消课等,应有尽有。
活动
您可以参加活动聚会,学习一项新技能,带上孩子发现未知…更特别的是,您还可以自己组织发起活动,呼朋唤友一起玩耍。
【主办方】提供从发布活动、活动推广、报名管理到财务管理等全流程完整解决方案
【参与者】找到感兴趣的活动,志同道合的朋友,长假远行,家长课堂,周边游,培训课 程,聚会沙龙,冬夏令营,手工课程,多种活动,丰富娱乐生活
【报名信息 随时查收】支持自定义设置报名表单,报名信息详情可查,支持导出
【精彩活动 乐享群聊】一起进入活动群聊,可以和其他参与者一起互动
联系人
- 搜索好友/群
- 添加好友/群
- 发送/接受好友申请
【技术实现】
本项目是基于官方最新SDK Hyphenate 进行开发 页面效果基于EasyUI调整 和微信页面效果看齐。
主要实现功能
1、注册 登录 自动登录 重连 退出登录
EMError *error = [[EMClient sharedClient] registerWithUsername:@"8001" password:@"111111"];
if (error==nil) {
NSLog(@"注册成功");
}
EMError *error = [[EMClient sharedClient] loginWithUsername:@"8001" password:@"111111"];
if (!error) {
NSLog(@"登录成功");
}
自动登录:即首次登录成功后,不需要再次调用登录方法,在下次 APP 启动时,SDK 会自动为您登录。并且如果您自动登录失败,也可以读取到之前的会话信息。
SDK 中自动登录属性默认是关闭的,需要您在登录成功后设置,以便您在下次 APP 启动时不需要再次调用环信登录,并且能在没有网的情况下得到会话列表。
EMError *error = [[EMClient sharedClient] loginWithUsername:@"8001" password:@"111111"];
if (!error)
{
[[EMClient sharedClient].options setIsAutoLogin:YES];
}
2. 消息
IM 交互实体,在 SDK 中对应的类型是 EMMessage。EMMessage 由 EMMessageBody 组成。
构造文字消息 构造图片消息 构造图片消息 构造位置消息 构造语音消息 构造视频消息 构造扩展消息(系统消息)
构造文字消息
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要发送的消息"];
NSString *from = [[EMClient sharedClient] currentUsername];
//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息
构造图片消息
EMImageMessageBody *body = [[EMImageMessageBody alloc] initWithData:data displayName:@"image.png"];
// body.compressionRatio = 1.0f; 1.0表示发送原图不压缩。默认值是0.6,压缩的倍数是0.6倍
NSString *from = [[EMClient sharedClient] currentUsername];
//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息
构造扩展消息
// 以单聊消息举例
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要发送的消息"];
NSString *from = [[EMClient sharedClient] currentUsername];
//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息
//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息
//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息
message.ext = @{@"key":@"value"}; // 扩展消息部分
扩展消息主要用要系统消息里
3. 会话
操作聊天消息 EMMessage 的容器,在 SDK 中对应的类型是 EMConversation。
新建 、 获取一个会话 (根据 conversationId 创建一个 conversation)
[[EMClient sharedClient].chatManager getConversation:@"8001" type:EMConversationTypeChat createIfNotExist:YES];getConversation:创建与8001的会话
//EMConversationTypeChat 单聊会话
//EMConversationTypeGroupChat 群聊会话
//EMConversationTypeChatRoom 聊天室会话
type:会话类型
createIfNotExist:不存在是否创建
4. 删除会话
删除单个会话
[[EMClient sharedClient].chatManager deleteConversation:@"8001" isDeleteMessages:YES completion:^(NSString *aConversationId, EMError *aError){deleteConversation: 删除与8001的会话
//code
}];
deleteMessages: 删除会话中的消息
5. 获取会话列表
获取所有会话 (内存中有则从内存中取,否则从db中取)
NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations];
6. 获取会话未读消息
[EMConversation unreadMessagesCount]; 显示红点
7. 聊天 (发送消息 接收消息 解析普通消息 解析扩展消息)
登录成功之后才能进行聊天操作。发消息时,单聊和群聊调用的是统一接口,区别只是要设置下 message.chatType。
/*!
@property
@brief 发送消息
@discussion
异步方法
*/
- (void)sendMessage:(EMMessage *)aMessage
progress:(void (^)(int progress))aProgressBlock
completion:(void (^)(EMMessage *message, EMError *error))aCompletionBlock;
//调用:[[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *aError) {}];
//消息回调:EMChatManagerDelegate
//移除消息回调
[[EMClient sharedClient].chatManager removeDelegate:self];
//注册消息回调
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];
/*!
@method
@brief 接收到一条及以上非cmd消息
*/
- (void)messagesDidReceive:(NSArray *)aMessages;
解析普通消息
// 收到消息的回调,带有附件类型的消息可以用 SDK 提供的下载附件方法下载(后面会讲到)
- (void)messagesDidReceive:(NSArray *)aMessages {
for (EMMessage *message in aMessages) {
EMMessageBody *msgBody = message.body;
switch (msgBody.type) {
case EMMessageBodyTypeText:
{
// 收到的文字消息
EMTextMessageBody *textBody = (EMTextMessageBody *)msgBody;
NSString *txt = textBody.text;
NSLog(@"收到的文字是 txt -- %@",txt);
}
break;
case EMMessageBodyTypeImage:
解析扩展消息
- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages {
for (EMMessage *message in aCmdMessages) {
// cmd消息中的扩展属性
NSDictionary *ext = message.ext;
NSLog(@"cmd消息中的扩展属性是 -- %@",ext)
}
}
// 收到消息回调
- (void)messagesDidReceive:(NSArray *)aMessages {
for (EMMessage *message in aMessages) {
// 消息中的扩展属性
NSDictionary *ext = message.ext;
NSLog(@"消息中的扩展属性是 -- %@",ext);
}
}
8. 好友管理 (本项目的好友管理是自己服务器上管理的)
9. 好友申请
发送好友申请
EMError *error = [[EMClient sharedClient].contactManager addContact:@"6001" message:@"我想加您为好友"];
if (!error) {
NSLog(@"添加成功");
}
监听加好友请求 (项目里面 发送系统消息)
/*!
* 用户A发送加用户B为好友的申请,用户B会收到这个回调
*
* @param aUsername 用户名
* @param aMessage 附属信息
*/
- (void)friendRequestDidReceiveFromUser:(NSString *)aUsername
message:(NSString *)aMessage;
同意加好友申请
EMError *error = [[EMClient sharedClient].contactManager acceptInvitationForUsername:@"8001"];
if (!error) {
NSLog(@"发送同意成功");
}
10 群组管理
创建群 后台创建的
加入群组 添人进群 退出群组 解散群组 修改群描述 获取群组成员列表
11 群组管理
1.后台配置推送证书
2.代码配置 APNs 使用的推送证书。
3.代码注册离线推送
【联系我们】
如需项目合作,请联系
石锋 18616870207 (微信同号) 收起阅读 »
【有奖互动】如果把各编程语言比作各国语言,哪种语言对应中文?
如果把编程语言比作各国语言,会分别对应什么?
目前点赞最高的回复如下:
Python 是英语,迅速成为许多人说的全球“默认”语言。多数情况下,相对容易学习,表达,语法简洁。
C 是中文,非常紧凑和快速,但很难学习和写作,容易“倒”在起点。
Lisp 是世界语(Esperanto)。只有一小群忠实的人说,并且一直告诉别人这有多棒。
Ruby 会是法语。这是一种可爱的语言,充满了例外和怪癖。一度受到精英的喜爱。现在虽然快要过时了,但仍然性感。
Ruby 会是法语,这是一种可爱的语言,充满了例外和怪癖。一度受到精英的喜爱。现在虽然快要过时了,但仍然性感。
Assembly 是拉丁语。现在几乎没什么人说了,尽管它是大多数现代语言的基础。
对此,中国小伙伴发表了他们的看法:
@网友:PHP是中文,想白话文就白话文,想文言文就文言文。
@网友:Java 是日语,入门很容易,精通很痛苦
对此问题,你怎么看?欢迎评论参与探讨。评论前5名同学送出环信定制指尖陀螺一个。
收起阅读 »
2017环信八大开源项目源码放出:两个已获融资,单个20W+关注
“这是一家极具极客范的公司”,来过环信公司的每一位客户都这么评价到。有着“连接人与人,连接人与商业”愿景的环信正在一步一步慢慢用技术和场景改变每个人的生活和工作。生有涯而知无涯,业有涯而心无涯,路漫漫其修远,“开源”当上下而求索!
环信成立于2013年,公司数位联合创始人都是技术大牛出身,在Symbian,Nokia,Red Hat等知名IT公司都是开源项目的重度参与者,环信的基因便因此打上了“开源”的烙印,在2014年即创办了国内首个即时通讯云开源社区“IMGeek社区”,经过了3年多的深耕,2017年度在环信IMGeek社区涌现了数十个优质开源项目,其中两个开源项目目前已经拿到融资,更有一个项目获得了超过20W+的关注度,环信正通过即时通讯云PaaS平台和客服PaaS平台一步步完善自己的商业梦想,也在一步步的通过开源回馈自己的开发者和产业链上下游的小伙伴。
环信公司前台一角
2017年是企业服务丰收的一年,感谢伙伴们对环信一直以来的支持。18年伊始之际,我们总结了17年间基于环信开发者的八大开源项目,希望能对大家有所帮助。
小马直播间-开源直播APP
推荐理由:基于环信开发的开源直播应用,IMGeek收藏数量3W8,对于有直播需求的小伙伴们值得参考,教你从头开始开发一个移动端直播APP。
互联网直播平台催生了一批批网红大咖,作为程序猿,我们绝不甘于委身幕后做搬砖工,我们一定要闪亮登场!!!做一个属于我们程序猿的IOS版直播平台~~
应用截图
实现功能:
- 创建推流和拉流加速
- 集成环信IM的聊天室功能
- 集成UCloud的ULive直播云SDK
- 在聊天室里集成推流(录制)和拉流(播放)功能
相关链接:http://www.imgeek.org/article/825308805 凡信-百尺竿头更进一步,2017凡信携直播、红包而来 推荐理由:自凡信开源以来,更新了3个大版本,从基本聊天功能,到越来越多的开发者创建分支,累计收到了10W+的收藏,帮助了很多开发者进行开发即时通讯应用。 已完成功能:
Dolores海报
- 单聊
- 群聊
- 朋友圈
- 钱包
- 直播
- 红包
相关链接:http://www.imgeek.org/article/825307930 Slack聊天机器人-环信客服版 推荐理由:17年作为人工智能元年,聊天机器人(Chatbot)在各大行业的应用方兴未艾,国外包括Facebook Messenger、Slack等均引入了聊天机器人,所以毋庸置疑,聊天机器人将成为我们未来生活中不可或缺的一部分,IMGEEK开源社区热心开发者&朝阳区群众“晨星桑”一言不合他就花2小时写了一个Slack的聊天机器人,您可以通过这个项目在Slack上对接客户服务,并且通过一些定制开发能够看见Slack用户的基本信息(比如:昵称、电话、团队名称等),并且可以二维码支付。相关功能:
项目运行效果图
- 事件订阅初始化
- 处理消息的事件
- 把消息发送到移动客服
- 处理OAuth回调
- 把收到的消息发给Slack 用户
实现功能:
项目运行效果图
- 环信SDK的集成与使用
- MVP模式的运用
- ORM数据库的集成与使用
- 模块化思想的运用
实现功能:
项目运行效果图
- 加入Tinker 热修复
- 加入部分注释
- 增加长按删除功能
- 优化Rxbus订阅加载数据
- 外国友人优化的一些细节
- 增加了评论功能
- 优化了相册加载
- 把登陆注册事件换了个Zip操作符更符合流的思想
实现功能:
项目运行效果图
- 好友/群内的文字、表情、图片、文件 在线/离线消息发送和接收。
- 查看群员列表。
- 面板内快速查找。
- 面板右键自定义事件
- 修改签名
- 自定义上传背景皮肤
- 搜索好友/群
- 添加好友/群
- 新建群
- 消息盒子展示
实现功能
项目运行效果图
- 项目首次启动自动注册登录
- 拨号盘实现
- 历史通话记录 TODO
- 视频通话功能(因为电视不需要语音通话以及最小化)
- 视频通话的录制
- 通话截图
相关链接:http://www.imgeek.org/article/825308732
end.
生有涯而知无涯,业有涯而心无涯,路漫漫其修远,当上下而求索。未来,我们还将开源更多。
环信IMGeek社区开源项目地址http://www.imgeek.org/code/
收起阅读 »
环信客户互动云v5.30已上线,支持客服主动发起视频邀请
本次更新的主要内容为:支持客服将个人常用语提交至公共常用语,方便整个客服团队共同维护公共常用语,提升常用语维护相关的工作效率。优化实时视频功能,支持客服在会话过程中主动发起视频邀请。客服模式
支持客服提交公共常用语
支持客服将个人常用语提交至公共常用语,方便整个客服团队共同维护公共常用语,提升常用语维护相关的工作效率。
提交个人常用语至公共常用语:
- 进入常用语页面,将鼠标放在个人常用语上,点击提交按钮 [提交] 。
- 选择公共常用语分类,确认常用语的内容(可修改),填写提交理由,并点击“提交”按钮。
客服将个人常用语提交至公共常用语后,需要管理员在“管理员模式 > 审批管理”页面,对客服的常用语申请进行审批,审批通过后,该常用语展示在公共常用语中。
支持客服主动发起视频邀请
与app、网页端客户聊天过程中,客服可以主动发起视频邀请,待客户接受视频邀请后,即可开始视频聊天。
客服发起视频聊天:
- 在会话页面,选择客户的会话,点击输入框上方的视频按钮 [发起视频邀请] 。
- 等待客户接受视频邀请。
在视频通话过程中,客服还可以邀请一名客服同事加入视频,或者与客户共享桌面。
注:“实时视频”功能为增值服务,如需开通,请提供租户ID并联系环信商务经理。
管理员模式
新增审批管理功能
新增审批管理功能。支持客服提交申请,由管理员统一进行审批,增强管理员对客服团队的管理能力,加强团队协作。
目前,支持客服提交个人常用语至公共常用语,由管理员进行审批。审批通过后,自动将该常用语添加至公共常用语,供所有客服使用。后续会增加更多审批功能,敬请期待。
审批管理页面分类显示所有待审批、已通过、已拒绝的审批申请,点击任意待审批的申请,可查看申请详情,并对其进行审批(通过或拒绝)。
客服提交申请后,管理员会在消息中心收到提醒;管理员完成审批后,客服可在消息中心查看审批结果。
新增调度规则设置
会话调度指会话路由至技能组后,系统将会话分配给技能组内客服的过程。调度规则包含技能组优先级属性等,由管理员设置,用于控制会话调度时分配会话的先后顺序。
新增调度规则设置,支持管理员设置5个技能组的优先级顺序,对优先级高的技能组的会话进行优先调度。并且,在调度规则中设置了优先级的技能组比剩余的其他技能组优先级高。例如:客服A同时属于技能组B和技能组C,技能组B的优先级高,则优先将技能组B的会话分配给客服A。
设置并启用调度规则:
- 进入“管理员模式 > 设置 > 会话分配规则 > 调度规则”页签。
- 在“客服接待能力分配”栏目下,点击“设置技能组优先级”按钮。
- 添加优先等级,并设置技能组对应的优先顺序。
- 打开“客服接待能力分配”开关。
注:“调度规则”功能为标准版/旗舰版增值服务,如需开通,请提供租户ID并联系环信商务经理。
支持根据客户信息路由会话
路由规则新增“客户信息指定”,目前支持按照客户标签将客户会话分配至不同的客服、技能组或机器人。该路由规则可用于优先接待VIP客户,为不同类别的客户提供有区别的客户服务等。
设置客户信息指定规则:
- 进入“管理员模式 > 设置 > 会话分配规则 > 路由规则”页签。
- 在“客户信息指定”栏目下,点击“添加客户信息设置”按钮。
- 填写规则名称,启用规则,添加客户标签,选择规则指定的机器人、技能组、客服,并保存。
- 重复步骤2、步骤3,创建多条客户信息指定规则。
- 点击客户信息指定规则右侧的排序按钮,调整规则之间的优先级顺序。
注:暂时不支持在客户信息指定规则中,将客户会话指定给未分组的客服。
设置完客户信息指定规则后,可在路由规则页签上下拖动各路由规则,调整各路由规则之间的优先级顺序。排在上方的路由规则的优先级高。
支持筛选所有会话标签的叶节点
会话标签包含根节点、枝节点、叶节点三种类型。在“统计查询 > 工作量”页面选择根节点或枝节点时,会话数分布(按会话标签维度)显示该节点下所有叶节点标签的会话的总数。
新增“全选叶标签”按钮 [全选叶节点] ,支持一键选择所有会话标签的叶节点;以及“取消全选叶标签”按钮 [取消全选叶节点] ,支持一键取消选择所有会话标签的叶节点。方便企业查询叶节点标签对应的会话数分布情况。
在工作量页面,选择“筛选排序 > 指定标签”,点击“全选叶标签”按钮,选择所有会话的叶节点,并确认。会话数分布(按会话标签维度)将显示各个叶节点标签的会话数;导出报表中也包含各个叶节点标签的会话数。
优化首次响应时长的计算方式
优化系统的首次响应时长的计算方式,更改为客服首条消息时间减去第一位客服的接起时间,不再包含机器人接待的会话时长。
Android客服工作台
当前版本:V3.6
新功能/优化:
- 新增告警记录功能
- 支持显示表单消息
iOS客服工作台
当前版本:V3.0.1
新功能/优化:
- 支持显示表单消息
iOS SDK访客端
当前版本:V1.1.6
新功能/优化:
- 支持显示客服输入状态(增值服务)
Web插件访客端
当前版本:V47.21.1
新功能/优化:
- 支持三方视频通话(增值服务)
- 支持自定义满意度评价提示语
环信移动客服更新日志http://docs.easemob.com/cs/releasenote/5.30
环信移动客服登陆地址http://kefu.easemob.com/ 收起阅读 »
基于layim+环信webim的网页即时聊天 LITE-IM
LITE-IM是一款基于 环信webim3.X 和 layim 开发而成的WEB即时通讯,并且完全的免费和开源 。LITE-IM使用 拥有高并发,长连接永不掉线的即时通讯的行业领头羊环信作为通信介质,再搭配上拥有丰富前端交互的layim,让你能够快速的搭建一个现代化的、高度稳定的web即时通讯。
LITE-IM不仅能够担当客户服务来使用,还可以用作你网站粘连客户、活跃社区的媒介,提升用户的使用率。当然LITE-IM还有许多有待完善之处。
目前已完成的功能有:
- 好友/群内的文字、表情、图片、文件 在线/离线消息发送和接收。
- 查看群员列表。
- 面板内快速查找。
- 面板右键自定义事件
- 修改签名
- 自定义上传背景皮肤
- 搜索好友/群
- 添加好友/群
- 新建群
- 消息盒子展示
- 查看/修改个人信息
- 实时获取好友在线状态
- 挤下线提醒
- 增删改 好友/好友分组
- 群管理(增删管理员/修改群名片/单个群员禁言解除禁言/踢人)
部分截图如下
好友聊天界面
自定义上传皮肤
群组
自定义右键
消息盒子
好友
LITE-IM在线体验地址:test.guoshanchina.com
体验帐号:
用户名:911088 密码:123456
用户名:1570855 密码:123456
用户名:1570845 密码:123456
用户名:911058 密码:123456
用户名:910992 密码:123456
用户名:911067 密码:123456
用户名:911100 密码:123456
用户名:911085 密码:123456
github源码:https://github.com/shmilylbelva/webim 收起阅读 »
环信CEO刘俊彦直播回放:环信如何重新定义客服软件?-环信公开课第18期
不能当网红的CEO做不好产品现场
刘俊彦讲到在直播公开课中讲到:“随着全媒体客服的完善以及AI的逐渐成熟, 环信预测“云通讯+服务云+智能营销”将构成从用户服务到用户营销的完整闭环。因此,2017年 ,环信整合旗下即时通信云、移动客服、智能客服机器人和主动营销产品线,推出环信CEC (Customer Engagement Cloud),向企业提供从客户互动渠道,到客户服务,到精准客户营销 的客户互动全流程解决方案。”同时,刘俊彦认为:“全媒体客服已经从传统客户服务形态的终点转化成了SaaS客户互动形态的起点,随着2017年环信CEC(客户互动云)的发布,人工智能驱动的互动中心(AI-driven Engagement Center)即将来临,整个SaaS客服行业将被重构和赋能。”
环信客户互动云:从用户互动渠道到客户服务再到用户营销的完整闭环
环信CEC(客户互动云)矩阵:
- 全渠道客户互动:全面支持网页、微信、微博、APP/IM、工单和呼叫中心等主流客户互动渠道。其中,环信业界领先的IM长连接技术支持千万级并发,保证消息必达,助力企业打造极致的移动端客户服务体验。所有渠道支持双向互动,如主动回呼,多渠道统一推送,基于用户行为的自动营销等,真正将服务通道与营销通道融合,实现客户中心从成本中心向利润中心的升级。
- 视频客服:实时双向视频客服,支持Android、iOS、Pad及主流PC和手机浏览器等多平台接入,低延迟,1080P高清,支持客户端和服务器端录制,可控灵活。
- 全渠道客服:环信移动客服作为业内广泛使用的客户中心系统,囊括多项行业主流大奖,拥有多项国际PCT专利和国内专利,深受客户好评。环信移动客服产品成熟可靠,功能完善,全面覆盖了全渠道接入管理,客户服务与客户互动管理,运营与运维管理,工单系统,现场管理,智能报表,质检等客户中心功能。
- 客户声音:环信客户声音是基于人工智能和大数据挖掘的客户体验透析产品。对来自多个渠道的非结构化客服会话数据进行自然语言解析,主题聚类和情感度建模,挖掘和分析热点话题,发现服务运营问题,寻找畅销或问题产品,洞察销售机会。客户声音系统可以帮助企业识别和改善客户旅程的各个阶段。
- 智能客服机器人:环信智能客服机器人不仅在常见的单轮对话能力上表现优异,预装多种行业知识库,还可以快速开发多轮对话,支持人机协作以便在复杂场景下对人工客服提供全面AI辅助支持。同时,环信智能客服机器人的自动学习能力极大的降低了机器人知识库的维护成本。
- 精准营销及自动化营销:大数据和AI驱动的营销功能,如自动化消息模板和自动化规则管理及A/B测试,营销计划管理,基于用户行为轨迹、用户画像和用户会话内容的自动化消息和访客CTA(Call To Action)等。
环信公开课第18期视频回放地址:https://v.qq.com/x/page/a05077ko5ly.html
环信客户互动云产品试用,公开课合作请添加公开课小助手
收起阅读 »
虾米音乐代码注释“穷逼VIP”,程序员出面致歉“今后我老老实实写代码,正正经经写注释”
虾米音乐程序员在代码注释中赫然将虾米音乐搞活动赠送给用户的VIP称之为“穷逼VIP”。
为与同类型的应用(QQ音乐与网易云音乐等)竞争,虾米音乐经常会推出各种领取VIP的优惠活动,用户领取后享受到的VIP内容和包月付费VIP用户没什么不同,但有时间上的限制。
但无论是领取了还是没领取,感谢或者觉得无所谓的虾米音乐用户们不会想到,虾米音乐程序员会简单粗暴地将这类VIP称之为“穷逼VIP”,英文名是Beggar vip(乞丐VIP)。
11月19日晚间,媒体报道虾米音乐第一时间做了复盘,替换了有问题的应用包,彻底去除了不当用语,同时修复文件混淆失效的BUG。
11月20日,虾米音乐前程序员“八座”在知乎回应致歉,并指出注释代码是自己个人行为,本意并没有任何歧视意思,只是想吐槽一些活动规则的复杂,但在吐槽中,丧失了对客户的敬畏。
对于这次虾米音乐程序员的做法,心大的网友调侃表示,幸好没有使用虾米音乐,躲过了“穷逼VIP”。一些网友试图从程序员的角度出发,认为这只是程序员沉闷工作下的一种寻找乐趣的手段。愤怒的网友则指责,虾米以及背后的阿里巴巴优越感很强嘛,有种就别搞任何营销活动。 收起阅读 »
基于环信webIM提供的Demo改造
1.实现自动登录,到聊天窗口
解决办法:是在页面自己写参数调用 Demo.conn.open(options) 方法
2.实现最近联系人列表渲染(因为我们没有好友概念,只要跟谁最近聊天了,就算是好友了)
解决办法:在页面通过ajax调用后台restFul地址获取联系人,然后循环调用 Demo.conn.onTextMessage(msg)方法,将消息内容为空,在msg里面设置标识为初始化加载,这样就会出现在列表里面
3.实现联系人:头像、昵称 渲染
解决办法:很简单就是在刚才上面的方法体里面调用完之后,你的列表就会出现好友列表,这时候你只需要根据环信用户id,直接基于jq替换即可
4.实现点击联系人 渲染历史聊天记录(在发送消息的时候将聊天记录保存在我们自己的数据库)
解决办法:在你获取最近联系人这个方法时已经返回了聊天记录列表,你需要在(Demo.chatRecord.环信用户id.messages)这个数组里面把你的消息放在这个数据里面去,然后当用户点击联系人列表时你jq写一个(webim-contact-item)这个样式的click触发方法,在这个方法中你需要写把聊天记录从(Demo.chatRecord.环信用户id.messages) 循环取出来,包装成HTML然后在 $("#wrapper"+Demo.selected).append() 这些HTML即可
5.实现保存聊天
解决办法:就是在 sendTxt里面调用我们的ajax方法保存
大致就这么多,个人不建议基于官方的webIM的Demo 去修改,这次踩过这个坑了
欢迎各位 集成的朋友来访,目前我这个算是解决,等过段时间我还是自己写一个吧,不打算基于他们的Demo去改造
在此欢迎去我的博客: www.kaven.cn 收起阅读 »
【环信开发者福利】江西省科技馆面向环信开发者公开采购智能硬件!
随着国家中国智造2025战略实施,智能产品、智能制造与互联网的深度融合、跨业创新,成为家电消费电子行业发展趋势。日前,环信与江西省科技馆达成合作协议,环信作为国内领先的企业级服务商,江西省科技馆将从环信20万+开发者中采购一批代表科技先进力的智能硬件,入驻江西省科技馆展览,一经录取,将按照市价采购!市场上科技馆现状:
现状一:常设展览和展品缺乏创新,简单模仿、相互雷同的现象普遍,展览主题和设计理念不 明确, 展品更新速度慢,大多数科技馆未能达到《标准》中“年更新率不低于5%”的要求。
现状二:短期专题展览(临时展览)开发力度弱,即使偶尔举办专题展览,也主要靠从外单位引进,缺乏自主创新
现状三:重展示、轻教育,重形式,轻体验。
科技馆分类:
江西 南北京
关于江西省科技馆:
江西省科学技术馆(简称江西省科技馆)坐落于赣江之滨,毗邻江南文化名楼滕王阁,是中共江西省委、江西省人民政府决策投资兴建的重点建设工程。全馆占地面积4.6万平方米,建筑面积1.6万平方米。场馆建筑突出“超弦生万物,对撞生新态”的设计理念,主体建筑组合在螺旋运动的轨道上,造型新颖、独特、动势飘逸,“游于无穷,寓于无境”。场馆由主展厅、儿童科学乐园、宇宙剧场、国际会议厅、青云厅及世纪广场等组成,是以展览教育为中心,融科技培训、科学报告、科学实验和科技影视为一体的大型科普教育基地,也是展示我省科技、文化、经济、社会发展的和重要窗口。
采购要求:
- 基于环信平台开发,具有先进科技代表性。
- 智能手机
- 智能家居
- 可穿戴设备
- 智能交通
- 智能医疗
- 智能玩具
- 智能机器人
欢迎环信用户踊跃参加,请将产品介绍发送至邮箱mkt@easemob.com,一经录取,将按照市价采购!
标题《江西省科技馆智能硬件采购-XX》
邮件内容:产品分类+产品/公司介绍,使用环信开发功能
附件:产品PPT/照片
环信优秀智能硬件案例
小墨机器人
收起阅读 »
环信即时通讯云 V3.3.6已发布,新增多人实时音视频功能
经过了两个月的内测,环信多人实时音频功能发布,是基于国内领先的环信云通讯技术平台搭建,致力于为用户提供高品质、稳定可靠、随时随地高效沟通的多人视频通讯解决方案。环信多人实时音视频可满足各种日常沟通的应用场景,针对不同场景,只需下载更新到V3.3.6版本SDK即刻拥有,赶紧下载体验吧!
Android SDK 版本 V3.3.6 2017-11-03
新功能:
- 新增API请查看3.3.6 API变化
- 使用外接音频输入源进行音视频通话时,设置音频源
- 提供是否自己处理附件的上传和下载设置项
- 提供是否自动下载附件类消息附件设置项(缩略图,语音文件)
- 多人音视频会议功能,详细参考集成文档 多人音视频会议
- 更改 easeui 中 EaseChatRow 实现方式,保证发送消息的回调顺利执行
- 修复使用华为推送时注册华为推送 token 空指针问题
- 修复更新聊天室公告时,其他聊天室成员收到回调崩溃问题
- 修复保存和插入消息时间戳和本地已存在消息的时间戳不同时,导致内存出现重复消息的问题
- 多人音视频功能
- 增加“是否自己实现消息附件上传下载”设置项 [EMOptions isAutoTransferMessageAttachments]
- 增加“是否自动下载图片和视频缩略图及语音消息”设置项 [EMOptions isAutoDownloadThumbnail]
- 1v1实时音视频,接通后,一方静音后,另一方再触发静音操作不起作用;
- 使用SDK下载接口,如果本地已经有同名文件,新的文件名会在原有文件名后边追加数字;
- 断网情况下,自动登录无法获取会话
- 使用SDK上传接口,进度回调第一次会返回100%
版本历史:Android SDK更新日志 ios SDK更新日志
下载地址:SDK下载 收起阅读 »
【开源项目】Kitura-HuanxinSDK:Swift+Kitura集成环信的开源解决方案
- Swift是Apple为iOS和Mac OS X开发的编程语言,但不止于此。随着Swift的开源,它开始被Apple官方支持在Ubuntu等GNU/Linux平台上运行,并且理论上可以移植到其他任何操作系统上(只要有人为它开发合适的工具链)。进一步的,它不再限制于用来开发本地/移动App,有人为它开发了Web框架和Web服务器。
- Kitura是上述Web框架和Web服务器之一。它是由IBM公司开发的,使用Swift语言。不过IBM只是基于Swift.org提供的编译工具链和Swift Package Manager(SPM)开发了一个第三方库,并没有单独开发一个完整的IDE,因此在Linux平台上的开发过程会略显不便。
- 环信是一个即时通信(IM)服务提供商。如果你的App需要好友私聊、群聊、客服等功能,你就需要一个IM服务。环信已经提供了iOS、Android等平台的SDK,用于客户端直接与环信服务器的交互。除此之外,注册、注销用户等高权限操作不适合从客户端直接发起请求,而应该让客户端先和[你的服务器]交互,再由[你的服务器]去和[环信服务器]交互。由此,服务器端集成是需要开发者自己去完成的。
- Kitura-HuanxinSDK是用于Swift+Kitura+环信解决方案的服务器端集成。它是对环信服务器端API的简单封装。开发者可以专注于App功能的开发,不用再去逐个研究环信服务器API的细节。
使用方法
1.Swift Package Manager
import PackageDescription2.环信账户信息
let package = Package(
name: "YourProjectName",
dependencies: [
.Package(url: "https://github.com/andy1247008998/Kitura-HuanxinSDK.git", majorVersion: 0)
]
)
import KituraHuanxinSDK3.获取一个Huanxin实例
//拼接环信URL基址
let huanxinDomain = "https://a1.easemob.com"
let huanxinOrgName = "1111222233334444"
let huanxinAppName = "yourappname"
let huanxinBaseURL = "\(huanxinDomain)/\(huanxinOrgName)/\(huanxinAppName)"
//准备好ID和Secret
let huanxinClientID = "AAAABBBBCCCCDDDDEEEEFFFF"
let huanxinClientSecret = "AAAABBBBCCCCDDDDEEEEFFFFGGGG"
let huanxin = Huanxin(domain:huanxinDomain, orgName:huanxinOrgName, appName:huanxinAppName, client_id:huanxinClientID, client_secret:huanxinClientSecret)4.注册用户
huanxin.registerUser(username:username, password:password, nickname:nickname, withToken:true){ registerUserResponse, error in
print("registerUserResponse is \(registerUserResponse)")
}
项目github源码地址:https://github.com/andy1247008998/Kitura-HuanxinSDK 收起阅读 »
集成环信之后集成动态库上传AppStore怎么破?
环信即时通讯云V3.3.5 SDK已发布,安全传输升级,支持FCM推送
10月23日,环信即时通讯云发布了新版本SDK,此次更新的V3.3.5版本增加了传输安全性,AndroidSDK支持FCM推送,FCM是谷歌推出的最新的Android系统级别的消息推送服务(用来替换GCM)。
iOS SDK 更新日志
版本 V3.3.5 2017-10-23
新功能:
- 增加了传输安全性
- 增加广告插件,可以收集用户信息
- 私有部署设置dns的接口
- 优化私有部署重连逻辑
- 限制用户名长度为255
- 需要服务器开通的功能接口返回SERVICE_NOT_ENABLED(505)
- 添加i386库解决模拟器profile时的编译问题
- 修复4G与wifi切换时偶然出现发送消息失败的bug
- 增加了传输安全性;
- 支持FCM推送;
- 私有部署设置dns的接口;
- 优化私有部署重连逻辑;
- 限制用户名长度为255;
- 需要服务器开通的功能接口返回SERVICE_NOT_ENABLED(505);
- 修复4G与wifi切换时偶然出现发送消息失败的bug;
- 修复VIVO手机JobService crash问题;
版本历史:Android SDK更新日志 ios SDK更新日志
下载地址:SDK下载 收起阅读 »
武汉开发者小伙伴看过来,环信讲师线下分享APP如何与AI共舞
你是否有开发时间短却任务重的窘境?
开发过程中需要做的功能点复杂却又很难下手?
如今人工智能行业备受关注 你了解多少?
作为一名技术人员
如何将自己的工作技能与其相结合并不断学习
本次活动我们的演讲嘉宾将对此类问题
为大家答疑解惑 传授经验
"超速玩转"安卓开发
本次活动邀请到
名人朋友圈的安卓负责人霍启圣
环信讲师AIhub人工智能CEO章国良
现场为各位开发者
分享干货
答疑解惑
只要你来就没有遗憾
活动概况
2017年10月21日(周六) 14:00-17:00
活动流程
嘉宾&讲题介绍
活动福利
前20名签到的猿猿
可获得“安卓巴士6周年”徽章
现场还有一二三等抽奖环节
和贴心的伴手礼SendCloud环保手袋一个
不容错过哦
活动须知
请认真填写报名资料用于审核使用
为保证当天活动质量拒绝空降
两点活动准时开始请提前签到
现场签到凭报名成功二维码
路线指南
别愣着 快扫码报名啊
收起阅读 »
Vue-cli整合环信WebIM
[b]非常抱歉以前写的文章给各位带来了麻烦,今天突然看到imgeek推送的邮件才记起这个[/b]其实很简单的,以前是我弄复杂了
1. 在index.html页面引入js文件
<script type='text/javascript' src='static/webim/webim.config.js'></script>
<script type='text/javascript' src='static/webim/strophe-1.2.8.js'></script>
2. 在main.js 赋值 , 如下图
代码如下
let WebIM = require('easemob-websdk')
Vue.prototype.$webim = WebIM
WebIM.config = {
xmppURL: 'im-api.easemob.com',
apiURL: (location.protocol === 'https:' ? 'https:' : 'http:') + '//a1.easemob.com',
appkey: '你的环信appkey',
https: false,
isMultiLoginSessions: true,
isAutoLogin: true,
isWindowSDK: false,
isSandBox: false,
isDebug: false,
autoReconnectNumMax: 2,
autoReconnectInterval: 2,
isWebRTC: (/Firefox/.test(navigator.userAgent) || /WebKit/.test(navigator.userAgent)) && /^https\:$/.test(window.location.protocol),
heartBeatWait: 4500,
isHttpDNS: false,
msgStatus: true,
delivery: true,
read: true,
saveLocal: false,
encrypt: {
type: 'none'
}
}
// 创建连接
const conn = new WebIM.connection({
isMultiLoginSessions: WebIM.config.isMultiLoginSessions,
https: typeof WebIM.config.https === 'boolean' ? WebIM.config.https : location.protocol === 'https:',
url: WebIM.config.xmppURL,
heartBeatWait: WebIM.config.heartBeatWait,
autoReconnectNumMax: WebIM.config.autoReconnectNumMax,
autoReconnectInterval: WebIM.config.autoReconnectInterval,
apiUrl: WebIM.config.apiURL,
isAutoLogin: true
})
// 添加成功的回调
conn.listen({
onOpened: function (message) {
console.log('连接打开=>', message)
},
onClosed: function (message) {
console.log('连接关闭=>', message)
},
onTextMessage: function (message) {
console.log('收到文本信息message=>', message)
}
})
const options = {
apiUrl: WebIM.config.apiURL,
user: null,
pwd: null,
appKey: WebIM.config.appkey
}
Vue.prototype.$imconn = conn
Vue.prototype.$imoption = options
3. 在页面调用全局的赋值即可
this.$imconn.open(this.$imoption)
收起阅读 »
环信公开课17期回放:环信视频客服的六大应用场景和十大黑科技
公开课17期视频回放
环信音视频老司机符宁
关于环信视频客服:
作为客户服务领域的领军企业,环信以Web和APP为载体发布了视频客服产品。基于业界领先的实时音视频通讯技术,为访客及企业客服人员提供双向的实时视频交互能力,支持视频画面展示与回放,语音及文字同步在线畅通交流,画质清晰,低延迟。目前已经大量应用于保险定损、在线教育、商品导购、医疗问诊、远程业务办理、VIP服务等六大场景,消费者可以足不出户便可享受真人面对面VIP服务,帮助企业在提高客户体验的同时极大降低成本和提升客服效率。
参加环信公开课还有礼品相送:
恭喜 赵X银,houge,王珏 三位同学同学成为本期公开课幸运观众,获得环信定制版T恤。
环信视频客服产品试用请点击http://a.eqxiu.com/s/ob8agMUU 收起阅读 »
环信WebIM2.0版本发布,专为移动端H5打造的通讯SDK
十年磨一剑 砺得梅花香
-献给在一线开发程序员们
经过了长达三个月的封闭开发,环信WebIM2.0版本在9月22号发布,此次更新的WebIM2.0也被称为“H5版本”,一套Demo同时支持PC和H5,自适应微信/QQ和各种手机浏览器。
WebIM 2.0 (webim-h5) 在1.x的基础上, 主要做了以下更新:
- 响应式布局, 一套Demo同时支持PC和H5,自适应不同终端屏幕尺寸
- 完全基于Reac + Redux的单向数据流
- 引入ant-design组件库,方便开发者后续开发
- 适配微信/QQ和各种手机浏览器
webim-h5在线体验地址:https://webim-h5.easemob.com
安装
1.初始化安装执行npm start时如果出现
在/demo下执行 npm i
2.如果需要同时编辑sdk cd sdk && npm link && cd .. && npm link easemob-websdk
3.如果需要同时编辑webrtc cd webrtc && npm link && cd .. && npm link easemob-webrtc
4.运行demo
cd demo && npm start (requires node@>=6)
http://localhost:3001
cd demo && HTTPS=true npm start (webrtc supports HTTPS only)
https://localhost:3001
5.发布demo cd demo && npm run build /demo/build 目录下的就是可以运行和部署的版本
```FIX: 没有执行 npm link easemob-websdk
./src/config/WebIM.js
Module not found: Can't resolve 'easemob-websdk/dist/strophe-1.2.8-g.js' in '<YourRootDir>/demo/src/config'
```
3. 执行npm start时如果出现
> node scripts/start.jsFIX: 请检查node版本是否是v6.0+
/Users/wenke/www/web-im/demo/scripts/start.js:23
const {
^
SyntaxError: Unexpected token {
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:373:25)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Function.Module.runMain (module.js:441:10)
at startup (node.js:139:18)
at node.js:974:3
4. Redux State 的数据结构如下:
{收起阅读 »
// ---------------------------------
// 响应式断点
// ---------------------------------
//xs: "480px"
//sm: "768px"
//md: "992px"
//lg: "1200px"
//xl: "1600px"
breakpoint: {
xs: false,
sm: false,
md: false,
lg: false,
xl: false
},
// ---------------------------------
// UI相关
// ---------------------------------
common: {
fetching: false,
isGetGroupAlready: true,
isGetChatRoomAlready: false,
showGroupRequestModal: false //群主管理加入群消息
},
// ---------------------------------
// 用户登录信息
// ---------------------------------
login: {
username: 'sunylt',
password: null,
token: "YWMtZ0m-opwTEeeS-e0Ko59rsU1-S6DcShHjkNXh_7qs2vV",
fetching: false,
error: false
isLogin: true,
},
// ---------------------------------
// 多语言
// ---------------------------------
i18n: {
// 已配置语言
translations: {
cn: {},
us: {},
},
// 当前语言
locale: "cn"
},
// 注册信息,没进行注册操作为{}
register: {
username: "123abcdbb",
password: "123",
fetching: false,
registerError: null
},
// 预留 暂无用
contacts: {}
// 预留 暂无用
im: {}
// ---------------------------------
// 数据实体
// ---------------------------------
entities: {
// 好友
roster: {
byName: {
name: { subscription,jid, ask, name, groups }
...
},
names: ['lwz2' ...],
// 好友列表在此,因为好友列表来源于roster,息息相关
friends: ,
},
// 群组
group: {
loadingFailed: <Boolean>,
isLoading: <Booleadn>,
rightSiderOffset: <Number>, //控制右侧群组管理面板
byId: {
groupId: {groupid, groupname},
....
},
names: [groupName_#-#_groupId, ....]
},
// 聊天室
chatroom: {
byId: {
chatId: {chatId, name, owner, affiliations_count}
...
},
names: [chatName_#-#_chatId, ....]
},
// 陌生人
stranger: {
},
// 群组成员信息
groupMember: {
groupId: {
muted: {byName: {}},//群主可见,禁言列表
byName: {
name: {name: <String: name>, affiliation: 'member'}
},
names: ,
admins: , //群管理员可见
},
...
}
// 订阅通知
subscribe: {
byFrom: {}
},
// 黑名单列表
blacklist: {
byName: {}
name:
},
// 消息
message: {
// 所有消息
byId: {
mid: {"type":"chat|groupchat|chatroom|stranger|error", "chatId": <String: chatId>},
...
}
// 单聊消息列表
chat: {
chatId: [
{message},
...
]
},
// 群组消息列表
groupChat: {
chatId: [
{message},
...
]
},
// 聊天室消息列表
chatroom: {
chatId: [
{message},
...
]
},
// 陌生人消息列表
stranger: {
chatId: [
{message},
...
]
},
// 预留 暂无用
extra: {}
// 未读消息记录
unread: {
// 好友
chat: {
chatId: <Number: unreadNum>,
...
},
// 群组
groupchat: {
chatId: <Number: unreadNum>,
...
},
// 聊天室
chatroom: {
chatId: <Number: unreadNum>,
...
},
// 陌生人
stranger: {
chatId: <Number: unreadNum>,
...
}
}
// 自己发的消息mid跟本地id对照
byMid: {
messageId: {id: <String: localId>},
...
},
},
// 加入群申请
groupRequest: {
byGid: {}
}
}
}
环信助力九个秘书打造全国中小企业人才共享管家
九个秘书-中小企业人才共享管家
遇到的挑战:
九个秘书APP技术总监卢志涛表示:“九个秘书调研期间技术团队对于聊天功能评估了很久,当时考虑是自己编写还是使用第三方的sdk。对于初创公司来讲,IM这一块由自己来开发不仅时间不允许,技术沉淀也不够,即便开发出来稳定性也很难保证。所以当时在相对于比较成熟的几款IM服务中,通过服务质量,稳定性,开发团队以及和业务需求进行匹配,技术部门进行了评断,在第三方sdk中精心筛选出了环信。”
环信解决方案:
九个秘书作为环信早期的用户,从15年就开始接入环信聊天功能,环信聊天能实现消息及时到达以及可扩展性良好,在接入时也遇到些问题,环信成立单独的项目技术支持的QQ群,来帮助九个秘书解决集成中遇到的问题,环信在帮助用户集成sdk时真的很尽心尽力,大大缩短了项目开发周期,为能用上这样贴心的服务点赞!”
价值体现:
九个秘书使用环信IM实现客户之间的相互聊天功能,以及群功能,同时为了丰富聊天的互动性,以及环信的可扩展性,在聊天中实现了收发红包,以及打赏用户的功能。”
关于九个秘书:
公司积极响应国家主席习近平提出的“推动互联网和实体经济深度融合”网络强国战略,立足全球共享经济大风口,探索城乡人才结构失衡、资源配置不均的互联网解决方案,成功研发人才共享企业级SAAS服务平台——九个秘书,让海量专业人才汇聚平台,通过远程协同智能办公作业模式,实现人才与企业按需雇佣,主要将一二线城市高端人才共享给四五线城市中小企业,解决一二线城市人才集中、四五线城市人才匮乏的差异化需求。
公司旗下拥有“九个秘书、九秘微城、九秘商城”三大产品线,将围绕“人才共享、本地生活、特产直营”三大核心业务,为生产、地产、酒店、餐饮、健康、旅游、休闲、娱乐、教育等行业,提供“品牌策划、商务直播、产品分销、品牌推广、品牌投资”一站式项目众包解决方案,深度解决企业“产品销售难、品牌推广难、渠道建设难、人才招聘难、成本降低难”五大难题,为企业的日常经营和可持续发展打通上下游云服务生态链,全方位推动中国实体经济互联网+转型! 收起阅读 »
环信客户互动云荣获2017年度全媒体智能客服最佳解决方案奖
2017年9月10日下午14时,由中国电子商会呼叫中心与客户关系管理专业委员会主办、北京易训天下咨询服务有限公司承办、贵阳市服务外包及呼叫中心产业发展办公室联合承办的“2017年度(第十三届)中国最佳呼叫中心颁奖暨行业大会”表彰活动之“2017年度中国呼叫中心产业交流峰会”在人民大会堂成功举办。本次峰会有来自电信、银行、保险、证券、汽车、旅游、电子商务、服务外包等不同行业的近400位中高层领导参会。本次大会重点表彰了国内呼叫中心产业优秀单位及个人,树立卓越行业形象,深度激活呼叫中心产业内上下游优秀企业与品牌,促使产业内部积极跨界融合及健康持续发展。
峰会期间,北京易掌云峰科技有限公司(环信)CEO刘俊彦先生以一家软件供应商的视角,将看到的行业最新趋势、最新变革与在座嘉宾共享,并提出三个趋势:从语音和电话座席向全媒体座席的升级趋势、服务座席向我们的营销座席升级的趋势、人工座席向人工智能座席的趋势。演讲围绕以上三个趋势提出问题、解答问题,引发现场在座嘉宾阵阵掌声。
环信荣获2017年度全媒体智能客服最佳解决方案奖
环信客户互动云(Customer Engagement Cloud)支持全媒体接入,包括网页在线客服、社交媒体客服(微博、微信)、APP内置客服和呼叫中心等多种渠道均可一键接入。基于环信业界领先的IM长连接技术保证消息必达,并通过智能客服机器人技术降低人工客服工作量。同时,基于人工智能和大数据挖掘的客户旅程透析产品"环信客户声音"能够帮助企业优化运营,提高跨渠道客服体验。环信CEC为企业提供了从客户互动渠道、到客户服务、再到精准营销的一体化全流程客户互动解决方案。 收起阅读 »
【环信征文】祭天时不同程序员的不同杀法
在此我想帮我的校友洗一次地,你们注意这个更新文案中只说“还杀了一个程序员祭天”没说是怎么杀的,为啥你们就脑补出砍头、活埋、六马分尸(女程序员可能是五马分尸)这些血腥的杀法了呢?为啥不觉得是老板奖励了程序员一辈子无福消受的酒肉烟钱把程序员的造化瞬间耗尽了呢?
喝酒醉死
诗云:李白当年水底眠,惟留诗篇万口传。码农入坑捞大饼,只给别人做笑谈。
程序员健康的第一大杀手是酒。
杭州有位程序员,虽然技术牛B,酒瘾也大。他荣升CTO之际恰逢母校80周年校庆,在收到了“欢迎杰出校友出席庆典”的邀请函后,坐上了开往合肥的动车,不料当动车开到当涂的时候,肝癌、酒精肝、胃穿孔同时发病,程序员被酒杀死了。
程序员死后,开启了上帝视角。他看到了祖师爷李白——我且问你,诗人怎么成了程序员的祖师爷?原来李白在醉酒之后,于采石矶低头看见水中月亮的倒影,便纵身一跃,跳进了一万里扬子大江捞月亮,从此李白变成了当涂县太白镇的衣冠冢,虽然尸骨无存,万幸香火不断。然后程序员又看见了建国后,上海美术电影制片厂拍了一个一群Monkey跳进小河里捞月亮的动画片。最后程序员看见了当代,老板在臭水坑里画了一个大饼,在项目上线后,用酒把一群Code Monkey灌醉,然后让Code Monkey争先恐后入坑捞大饼的故事。李白就这样成了Code Monkey的祖师爷。
有诗为证:天上月亮只一个,举杯对影便成三。醉生梦死伤身体,诗人一醉变诗仙。
程序员明白了喝酒有害健康的道理之后就复活了,从此粉碎了老板想让他喝酒醉死祭天的阴谋。
吃肉撑死
诗云:反式脂肪胆固醇,催肥激素更无伦。工作午餐多吃素,青山怕葬黑发人。
程序员健康的第二大杀手是肉。
北京有位程序员,虽然技术牛B,烟瘾也大。他荣升CTO之际恰逢母校80周年校庆,在收到了“欢迎杰出校友出席庆典”的邀请函后,坐上了开往合肥的动车,不料当动车开到淮南的时候,高血压、脂肪肝、直肠癌同时发病,程序员被肉杀死了。
程序员死后,开启了上帝视角。他看到赵王中了秦国的反间计,逼走了廉颇,因此长平之战赵国惨败。于是“赵王思复得廉颇,廉颇亦思复用于赵”,赵王派使者来到魏国问廉颇“尚能饭否?”廉颇非常高兴,一顿饭吃了十斤肉,披甲上马,不料因为肉吃得太多坏了肚子,和使者谈话的时候连上三次厕所。于是赵王没有重新重用廉颇,廉颇又从魏国流亡到了楚国,最终在八公山逝世,赵国不久也就成了《阿房宫赋》里轻描淡写的一句“燕赵之收藏,……,输来其间”。
有诗为证:廉颇在魏思邯郸,星落淮南八公山。吃肉太多伤身体,收藏不该来其间。
程序员明白了吃肉有害健康的道理之后就复活了,从此粉碎了老板想让他吃肉撑死祭天的阴谋。
抽烟呛死
诗云:八旗守城似金汤,为何英军入镇江。皆因大烟未烧尽,留下祸根毒四方。
程序员健康的第三大杀手是烟。
厦门有位程序员,虽然技术牛B,烟瘾也大。他荣升CTO之际恰逢母校80周年校庆,在收到了“欢迎杰出校友出席庆典”的邀请函后,坐上了开往合肥的动车,不料当动车开到镇江的时候,肺癌、肺气肿、口腔癌同时发病,程序员被烟杀死了。
程序员死后,开启了上帝视角。他看到古代镇江是长江门户,自古便是兵家必争之地。民族英雄郑成功三次从厦门誓师北伐,每一次都势如破竹,但无一例外在镇江败北。镇江之所以易守难攻,不完全依赖长江天险,更靠八旗子弟骁勇善战。不料后来在鸦片战争中镇江被英军轻而易举攻破,原来两广总督林则徐虎门销烟的时候有一箱子烟忘了销毁,流传到了镇江,八旗子弟吸烟之后“头痛头晕加恶心,眼花耳响不认人。脸色苍白出虚汗,浑身乱颤腿抽筋”,导致镇江“几无可以御敌之兵”。
有诗为证:编程早知世事艰,码农为何气如山。吞云吐雾伤身体,总督岂能不销烟。
程序员明白了吸烟有害健康的道理之后就复活了,从此粉碎了老板想让他抽烟呛死祭天的阴谋。
拿钱砸死
诗云:劝君莫要聚宝盆,富可敌国害死人。若是贪财能保命,周庄沈厅可不焚。
程序员健康的第四大杀手是钱。
上海有位程序员,虽然技术牛B,钱瘾也大。他荣升CTO之际恰逢母校80周年校庆,在收到了“欢迎杰出校友出席庆典”的邀请函后,坐上了开往合肥的动车,不料当动车开到苏州的时候,失眠、抑郁症、谋财害命同时发病,程序员被钱杀死了。
程序员死后,开启了上帝视角。他看到古代周庄有个大财主沈万三,家里有个聚宝盆,全国的金银财宝都会流到他的手里,导致了朱元璋的嫉恨。朱元璋没收了沈万三的粮食,烧毁了沈万三的房子,给他一个金碗,还给他盖了一座金屋子。让他白天拿着金碗讨饭,夜里睡在金屋子里。因为没人设施捧金碗的乞丐,黄金的导热能力强比热容又小,沈万三死于饥寒交迫。
有诗为证:但愿有头生白发,何忧无地觅青蚨。贪财无厌伤身体,拿命卖钱太糊涂。
程序员明白了贪财有害健康的道理之后就复活了,从此粉碎了老板想让他拿钱砸死祭天的阴谋。 收起阅读 »
【环信征文】集成环信,并实现消息免打扰
先解释一下,本人项目中对消息免打扰功能的定义:正常情况下,我们收到的每一条聊天消息都会收到小红点、声音、震动的提示。如果对某个好友设置消息免打扰功能,则只提示小红点,声音和震动则不再提示。
下面简述结合环信SDK时,此功能的实现方法。
环信将即时聊天的所有功能分为四大模块进行管理:
//聊天模块:消息免打扰的功能借助聊天模块[EMClient sharedClient].chatManager的API就能实现。
[EMClient sharedClient].chatManager
//好友模块 :
[EMClient sharedClient].contactManager
//群组模块 :
[EMClient sharedClient].groupManager
//聊天室模块:
[EMClient sharedClient].roomManager
一般来说,在app内不管当前在哪个界面,只要收到消息都需要被判断是否需要免打扰,因此可以在appdelegate里写如下代码,app通常都有tabBarController,那么也可以让tabBarController来实现如下代码。
首先让控制器tabBarController遵守代理EMChatManagerDelegate
然后成为代理
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];
EMChatManagerDelegate中有一个代理方法
- (void)didReceiveMessages:(NSArray *)aMessages;实现此代理方法
- (void)didReceiveMessages:(NSArray *)aMessages{方法中有一个aMessages参数。这个参数是一个消息组,每一个元素都是EMMessage类型的实例。
[self setupUnreadMessageCount];
EMMessage *message = aMessages[0];
NSString *sendPerson = message.from;
BHNavigatiomController *imNaviCV = self.viewControllers[1];
BHConversationListController *converCV = imNaviCV.viewControllers[0];
[converCV refreshDataSource];//只要收到消息就从服务器拿
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
for (NSString *hx_name in AppEngine.IMDataCent.data_ExcuseFriendsData) {
if ([hx_name isEqualToString:sendPerson]) {
return;
}
}
switch (state) {
case UIApplicationStateActive:
[self playSoundAndVibration];
break;
case UIApplicationStateInactive:
[self playSoundAndVibration];
break;
case UIApplicationStateBackground:
[self showNotificationWithMessage:message];
break;
default:
break;
}
}
因为通常都只有一条信息。因此只需要取出EMMessage *message = aMessages[0];
EMMessage类中有许多属性,因此根据一条信息基本可以获取想知道的所有信息。这里我们只需要知道此消息的发送方即可,也就是发送方的环信idNSString *sendPerson = message.from;下面代码中有一AppEngine.IMDataCent.data_ExcuseFriendsData,这个数组里面装的都是已经被设置消息免打扰的好友的环信id,是请求自己服务器获得的,获取的代码最好在一打开app时,就及时获取到。然后根据对好友免打扰设置的操作,访问后台接口进行增删,并刷新数组与后端保持一致即可。
通过[hx_name isEqualToString:sendPerson],遍历免打扰数组与当前消息的发送方环信id,就可以知道是否需要免打扰了。
下面附上完整代码
//
// BHTabBarController.m
// ShangHeYiYang
//
// Created by LiBohan on 2017/8/24.
// Copyright © 2017年 xxxxx. All rights reserved.
//
//两次提示的默认间隔
static const CGFloat kDefaultPlaySoundInterval = 3.0;
static NSString *kMessageType = @"MessageType";
static NSString *kConversationChatter = @"ConversationChatter";
static NSString *kGroupName = @"GroupName";
#import "BHTabBarController.h"
#import <UserNotifications/UserNotifications.h>
#import "BHConversationListController.h"
@interface BHTabBarController ()<EMChatManagerDelegate,EMContactManagerDelegate>
@property (strong, nonatomic) NSDate *lastPlaySoundDate;
@end
@implementation BHTabBarController
- (void)viewDidLoad {
[super viewDidLoad];
[DemoCallManager sharedManager].mainController = self;
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];
[[EMClient sharedClient].contactManager addDelegate:self delegateQueue:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setupUnreadMessageCount) name:@"setupUnreadMessageCount" object:nil];
}
-(void)friendshipDidRemoveByUser:(NSString *)aUsername{
// __weak __typeof(&*self)weakSelf = self;
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0/*延迟执行时间*/ * NSEC_PER_SEC));
dispatch_after(delay, dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:contactReloadData object:nil];
});
// if ([AppEngine.mainDataCent.data_UserData.data_HxID isEqualToString:aUsername]) {
//删除好友成功后,再删除聊天会话
[[EMClient sharedClient].chatManager deleteConversation:aUsername isDeleteMessages:YES completion:^(NSString *aConversationId, EMError *aError) {
if (!aError) {
//删除聊天会话,成功后,刷新聊天会话列表
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0/*延迟执行时间*/ * NSEC_PER_SEC));
dispatch_after(delay, dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:talkBtnClickThenUpdateConversionlist object:nil];
});
}
}];
}
// 统计未读消息数
-(void)setupUnreadMessageCount
{
NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations];
NSInteger unreadCount = 0;
for (EMConversation *conversation in conversations) {
unreadCount += conversation.unreadMessagesCount;
}
NSArray *tabBarItems = self.tabBar.items;
UITabBarItem *conlistTabBarItem = [tabBarItems objectAtIndex:1];
if (unreadCount > 0) {
conlistTabBarItem.badgeValue = [NSString stringWithFormat:@"%i",(int)unreadCount];
}else{
conlistTabBarItem.badgeValue = nil;
}
// UIApplication *application = [UIApplication sharedApplication];
// [application setApplicationIconBadgeNumber:unreadCount];
}
- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages {
for (EMMessage *message in aCmdMessages) {
EMCmdMessageBody *body = (EMCmdMessageBody *)message.body;
NSLog(@"收到的action是 -- %@",body.action);
if (body.action == nil) {
return;
}
NSData *jsonData = [body.action dataUsingEncoding:NSUTF8StringEncoding];
NSError *err;
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];
if(err) {
NSLog(@"json解析失败:%@",err);
return;
}
NSNumber *num = dic[@"count"];
NSString *str = [num stringValue];
[AppEngine.IMDataCent requestUpdateUnreadNumberWithUnreadNumber:str];
}
}
- (void)didReceiveMessages:(NSArray *)aMessages{
// [self refresh];
[self setupUnreadMessageCount];
EMMessage *message = aMessages[0];
NSString *sendPerson = message.from;
BHNavigatiomController *imNaviCV = self.viewControllers[1];
BHConversationListController *converCV = imNaviCV.viewControllers[0];
// [converCV refresh];
[converCV refreshDataSource];//只要收到消息就从服务器拿
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
for (NSString *hx_name in AppEngine.IMDataCent.data_ExcuseFriendsData) {
if ([hx_name isEqualToString:sendPerson]) {
return;
}
}
switch (state) {
case UIApplicationStateActive:
[self playSoundAndVibration];
break;
case UIApplicationStateInactive:
[self playSoundAndVibration];
break;
case UIApplicationStateBackground:
[self showNotificationWithMessage:message];
break;
default:
break;
}
}
- (void)playSoundAndVibration{
NSTimeInterval timeInterval = [[NSDate date]
timeIntervalSinceDate:self.lastPlaySoundDate];
if (timeInterval < kDefaultPlaySoundInterval) {
//如果距离上次响铃和震动时间太短, 则跳过响铃
NSLog(@"skip ringing & vibration %@, %@", [NSDate date], self.lastPlaySoundDate);
return;
}
//保存最后一次响铃时间
self.lastPlaySoundDate = [NSDate date];
// 收到消息时,播放音频
[[EMCDDeviceManager sharedInstance] playNewMessageSound];
// 收到消息时,震动
[[EMCDDeviceManager sharedInstance] playVibration];
}
- (void)showNotificationWithMessage:(EMMessage *)message
{
EMPushOptions *options = [[EMClient sharedClient] pushOptions];
NSString *alertBody = nil;
if (options.displayStyle == EMPushDisplayStyleMessageSummary) {
EMMessageBody *messageBody = message.body;
NSString *messageStr = nil;
switch (messageBody.type) {
case EMMessageBodyTypeText:
{
messageStr = ((EMTextMessageBody *)messageBody).text;
}
break;
case EMMessageBodyTypeImage:
{
messageStr = NSLocalizedString(@"message.image", @"Image");
}
break;
case EMMessageBodyTypeLocation:
{
messageStr = NSLocalizedString(@"message.location", @"Location");
}
break;
case EMMessageBodyTypeVoice:
{
messageStr = NSLocalizedString(@"message.voice", @"Voice");
}
break;
case EMMessageBodyTypeVideo:{
messageStr = NSLocalizedString(@"message.video", @"Video");
}
break;
default:
break;
}
do {
// NSString *title = [[UserProfileManager sharedInstance] getNickNameWithUsername:message.from];
NSString *title = @"大佬";
if (message.chatType == EMChatTypeGroupChat) {
NSDictionary *ext = message.ext;
if (ext && ext[kGroupMessageAtList]) {
id target = ext[kGroupMessageAtList];
if ([target isKindOfClass:[NSString class]]) {
if ([kGroupMessageAtAll compare:target options:NSCaseInsensitiveSearch] == NSOrderedSame) {
alertBody = [NSString stringWithFormat:@"%@%@", title, NSLocalizedString(@"group.atPushTitle", @" @ me in the group")];
break;
}
}
else if ([target isKindOfClass:[NSArray class]]) {
NSArray *atTargets = (NSArray*)target;
if ([atTargets containsObject:[EMClient sharedClient].currentUsername]) {
alertBody = [NSString stringWithFormat:@"%@%@", title, NSLocalizedString(@"group.atPushTitle", @" @ me in the group")];
break;
}
}
}
NSArray *groupArray = [[EMClient sharedClient].groupManager getJoinedGroups];
for (EMGroup *group in groupArray) {
if ([group.groupId isEqualToString:message.conversationId]) {
title = [NSString stringWithFormat:@"%@(%@)", message.from, group.subject];
break;
}
}
}
else if (message.chatType == EMChatTypeChatRoom)
{
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
NSString *key = [NSString stringWithFormat:@"OnceJoinedChatrooms_%@", [[EMClient sharedClient] currentUsername]];
NSMutableDictionary *chatrooms = [NSMutableDictionary dictionaryWithDictionary:[ud objectForKey:key]];
NSString *chatroomName = [chatrooms objectForKey:message.conversationId];
if (chatroomName)
{
title = [NSString stringWithFormat:@"%@(%@)", message.from, chatroomName];
}
}
alertBody = [NSString stringWithFormat:@"%@:%@", title, messageStr];
} while (0);
}
else{
// alertBody = NSLocalizedString(@"receiveMessage", @"you have a new message");
alertBody = @"您有一条消息";
}
NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceDate:self.lastPlaySoundDate];
BOOL playSound = NO;
if (!self.lastPlaySoundDate || timeInterval >= kDefaultPlaySoundInterval) {
self.lastPlaySoundDate = [NSDate date];
playSound = YES;
}
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[userInfo setObject:[NSNumber numberWithInt:message.chatType] forKey:kMessageType];
[userInfo setObject:message.conversationId forKey:kConversationChatter];
//发送本地推送
if (NSClassFromString(@"UNUserNotificationCenter")) {
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0.01 repeats:NO];
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
if (playSound) {
content.sound = [UNNotificationSound defaultSound];
}
content.body =alertBody;
content.userInfo = userInfo;
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:message.messageId content:content trigger:trigger];
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:nil];
}
else {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = [NSDate date]; //触发通知的时间
notification.alertBody = alertBody;
notification.alertAction = NSLocalizedString(@"open", @"Open");
notification.timeZone = [NSTimeZone defaultTimeZone];
if (playSound) {
notification.soundName = UILocalNotificationDefaultSoundName;
}
notification.userInfo = userInfo;
//发送通知
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
}
- (void)messagesDidDeliver:(NSArray *)aMessages{
NSLog(@"sf");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
本人github:https://github.com/BHAreslee
本人简书:http://www.jianshu.com/u/bb53043aaa00
以上就是集成环信时暂时发现的问题,欢迎大家分享你们遇到的问题,也欢迎加入QQ群:372251359,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂
收起阅读 »
【环信招聘】Android、ios、H5前端、后台工程师快到碗里来!
这里的每一项技术都会直接帮助平台上的App开发者,并在真正的应用里得到实践检验。
我们不仅是技术的研发者,也是技术的输出方。
这里的每一项技术都在改变世界!
欢迎加入!我们支持开源运动!
来环信,和我们一起用技术改变世界!
以下职位工作地点是在河南郑州开发,小伙伴们简历赶紧砸过来吧!内推邮箱地址duc@easemob.com
iOS工程师
岗位职责:
1. 负责IM SDK开发与相关应用的开发;
2. 对客户提供解决方案和必要的技术支持;
任职资格:
1. 熟悉iOS开发环境、iOS App开发规范和App开发流程;
2. 熟练使用iOS开发核心库,有一定的文档编写能力;
3. 熟悉iOS SDK中布局、网络、数据库、HTTP协议、XML/JSON解析等;
4. 掌握iOS平台的模块化设计架构,能够设计出恰当的应用方案;
5. 熟悉iOS平台的内存管理机制,懂得内存优化技术;
6. 能够与产品经理、设计师、用户进行深入的沟通和交流;
7. 有即时通讯平台开发经验者优先考虑;
8. 两年以上开发经验,其中一年以上iOS应用开发经验;
9. Github 使用者、熟悉c/c++开发,有开源项目贡献者优先考虑。
安卓工程师
岗位职责:
1. 负责IM SDK开发与相关应用的开发;
2. 对客户提供解决方案和必要的技术支持;
任职资格:
1. 熟悉android开发环境、android应用开发规范和开发流程;
2. 熟练使用android SDK,熟悉JNI开发,有一定的文档编写能力;
3. 熟悉android SDK中布局、网络、数据库、HTTP协议、XML/JSON解析等;
4. 掌握Android 平台的模块化设计架构,能够设计出恰当的应用方案;
5. 熟悉 Android 平台的内存管理机制,懂得内存优化技术;
6. 能够与产品经理、设计师、用户进行深入的沟通和交流;
7. 有即时通讯平台开发经验者优先考虑;
8. 两年以上开发经验,其中一年以上android应用开发经验;
9. Github 使用者、熟悉c/c++开发,有开源项目贡献者优先考虑。
H5前端工程师
工作职责
1.环信Web、IM、SDK等的开发设计
2.环信业务后台管理系统的开发设计
任职资格
1.有web前端经验,熟悉流行的前端技术, 包括但不限于bootstrap、html5、css3、saas、less、jQuery、bower、grunt、webpack、reactJs
2.有H5移动端开发经验
3.熟悉Ajax, Rest等原理和使用方式
4.熟悉Http, WebSocket, Spdy等协议
5.深刻理解Web标准, 对可用性、可访问性等相关知识有实际的了解和实践经验
6.有一定的设计美感
7.简历请同时提供以往项目地址,以及github地址或技术博客地址
加分项:
1.熟悉ruby、python、bash、nodejs等脚本语言优先考虑
2.有开源社区经验者优先考虑
后台工程师
工作职责
1.负责持续改进后端服务,打造业界领先的即时通讯云服务;
2.或负责持续优化服务性能,提高后端服务的承载能力;
3.或负责完成后端服务的多机房改造,为全球用户提供可靠实时的即时通讯服务;
任职资格
1.熟悉Java、Erlang或C/C++其中两种语言,有Unix/Linux平台相关开发经验;
2.熟悉网络通信机制及常用数据传输协议;
3.算法基础扎实,有ACM、TopCoder或其他比赛经验者优先;
4.熟悉数据库相关开发,了解MySQL数据库,有HBase、Redis或其他NoSQL相关使用经验者优先;
5.有较强的解决问题能力,能够承受压力情况下解决线上问题;
6.能够带领团队成员,研究并攻克技术难关;
7.需要有开放共享的心态,接受开源思想,有Github创建、维护或参与经验更好;
8.5年以上开发工作经验;
项目经理(项目实施)-IM
您的责任:
1.确保项目目标的实现,领导项目团队准时、优质的完成全部工作。
2.及时有效地与客户沟通,了解项目的整体需求,与客户保持持续的联系,及时反馈阶段性的成果,并及时向研发更新客户提出的合理需求。
3.制定开发计划文档,量化任务,并合理分配给相关人员。
4.跟踪项目进度,有效的提高代码质量,并及时与研发、实施部署人员以及QA之间沟通,保证项目以及附属文档的完整和规范。
我们的要求:
1. 正规大学本科及以上学历
2.5年以上软件行业经验,3年以上开发/项目管理工作经验
3.能够独立完成中型项目的整体设计、任务计划和开发进度的管理工作
4.熟悉框架设计、系统设计、数据库设计、编码测试等软件工程知识和规范
5.精通软件开发流程,了解linux/unix系统,并能够熟练使用系统设计、数据库设计工具
6.对软件多层结构、以及各层间使用的软件技术有较全面的了解 ;
7.具有开发队伍的管理能力和经验;
8.具备技术文档编写能力;
9.有乙方项目经理经历,能够与甲方顺畅沟通。
10..有互联网工作经历的优先。
iOS工程师
岗位职责:
1. 负责IM SDK开发与相关应用的开发;
2. 对客户提供解决方案和必要的技术支持;
任职资格:
1. 熟悉iOS开发环境、iOS App开发规范和App开发流程;
2. 熟练使用iOS开发核心库,有一定的文档编写能力;
3. 熟悉iOS SDK中布局、网络、数据库、HTTP协议、XML/JSON解析等;
4. 掌握iOS平台的模块化设计架构,能够设计出恰当的应用方案;
5. 熟悉iOS平台的内存管理机制,懂得内存优化技术;
6. 能够与产品经理、设计师、用户进行深入的沟通和交流;
7. 有即时通讯平台开发经验者优先考虑;
8. 两年以上开发经验,其中一年以上iOS应用开发经验;
9. Github 使用者、熟悉c/c++开发,有开源项目贡献者优先考虑。
安卓工程师
岗位职责:
1. 负责IM SDK开发与相关应用的开发;
2. 对客户提供解决方案和必要的技术支持;
任职资格:
1. 熟悉android开发环境、android应用开发规范和开发流程;
2. 熟练使用android SDK,熟悉JNI开发,有一定的文档编写能力;
3. 熟悉android SDK中布局、网络、数据库、HTTP协议、XML/JSON解析等;
4. 掌握Android 平台的模块化设计架构,能够设计出恰当的应用方案;
5. 熟悉 Android 平台的内存管理机制,懂得内存优化技术;
6. 能够与产品经理、设计师、用户进行深入的沟通和交流;
7. 有即时通讯平台开发经验者优先考虑;
8. 两年以上开发经验,其中一年以上android应用开发经验;
9. Github 使用者、熟悉c/c++开发,有开源项目贡献者优先考虑。
H5前端工程师
工作职责
1.环信Web、IM、SDK等的开发设计
2.环信业务后台管理系统的开发设计
任职资格
1.有web前端经验,熟悉流行的前端技术, 包括但不限于bootstrap、html5、css3、saas、less、jQuery、bower、grunt、webpack、reactJs
2.有H5移动端开发经验
3.熟悉Ajax, Rest等原理和使用方式
4.熟悉Http, WebSocket, Spdy等协议
5.深刻理解Web标准, 对可用性、可访问性等相关知识有实际的了解和实践经验
6.有一定的设计美感
7.简历请同时提供以往项目地址,以及github地址或技术博客地址
加分项:
1.熟悉ruby、python、bash、nodejs等脚本语言优先考虑
2.有开源社区经验者优先考虑
后台工程师
工作职责
1.负责持续改进后端服务,打造业界领先的即时通讯云服务;
2.或负责持续优化服务性能,提高后端服务的承载能力;
3.或负责完成后端服务的多机房改造,为全球用户提供可靠实时的即时通讯服务;
任职资格
1.熟悉Java、Erlang或C/C++其中两种语言,有Unix/Linux平台相关开发经验;
2.熟悉网络通信机制及常用数据传输协议;
3.算法基础扎实,有ACM、TopCoder或其他比赛经验者优先;
4.熟悉数据库相关开发,了解MySQL数据库,有HBase、Redis或其他NoSQL相关使用经验者优先;
5.有较强的解决问题能力,能够承受压力情况下解决线上问题;
6.能够带领团队成员,研究并攻克技术难关;
7.需要有开放共享的心态,接受开源思想,有Github创建、维护或参与经验更好;
8.5年以上开发工作经验;
项目经理(项目实施)-IM
您的责任:
1.确保项目目标的实现,领导项目团队准时、优质的完成全部工作。
2.及时有效地与客户沟通,了解项目的整体需求,与客户保持持续的联系,及时反馈阶段性的成果,并及时向研发更新客户提出的合理需求。
3.制定开发计划文档,量化任务,并合理分配给相关人员。
4.跟踪项目进度,有效的提高代码质量,并及时与研发、实施部署人员以及QA之间沟通,保证项目以及附属文档的完整和规范。
我们的要求:
1. 正规大学本科及以上学历
2.5年以上软件行业经验,3年以上开发/项目管理工作经验
3.能够独立完成中型项目的整体设计、任务计划和开发进度的管理工作
4.熟悉框架设计、系统设计、数据库设计、编码测试等软件工程知识和规范
5.精通软件开发流程,了解linux/unix系统,并能够熟练使用系统设计、数据库设计工具
6.对软件多层结构、以及各层间使用的软件技术有较全面的了解 ;
7.具有开发队伍的管理能力和经验;
8.具备技术文档编写能力;
9.有乙方项目经理经历,能够与甲方顺畅沟通。
10..有互联网工作经历的优先。 收起阅读 »
【环信征文】基于环信开发一个医疗APP-Ⅰ
公司又有了新项目,依然是含有即时通讯功能模块的项目。在经历了上个项目对环信sdk的集成后,对环信EaseUI有了大概的了解。这次果断还是集成环信,一回生二回熟,最主要的还是对环信IM稳定性非常放心!项目医疗类的项目,角色分医生和患者,双方都可主动发起会话,但如果是患者找医生聊天,必须先经过预约,并只能在预约时间区间内才能和医生发送聊天消息、图片、语音、实时音视频。项目基于环信最V3.3.4版本开发,首先在会话界面自定义一个类比如BHChatViewController,继承自EaseMessageViewController类,基本上一个简单的界面就有了。以下就是EaseMessageViewController类的发送各种消息的方法,那么根据需要只需重写以下方法即可。
/*!我在对发送图片的操作进行处理的时候,发现当拍照发图时,走这个方法
@method
@brief 发送文本消息
@discussion
@param text 文本消息
@result
*/
- (void)sendTextMessage:(NSString *)text;
/*!
@method
@brief 发送文本消息
@discussion
@param text 文本消息
@param ext 扩展信息
@result
*/
- (void)sendTextMessage:(NSString *)text withExt:(NSDictionary*)ext;
/*!
@method
@brief 发送图片消息
@discussion
@param image 发送图片
@result
*/
- (void)sendImageMessage:(UIImage *)image;
/*!
@method
@brief 发送位置消息
@discussion
@param latitude 经度
@param longitude 纬度
@param address 地址
@result
*/
- (void)sendLocationMessageLatitude:(double)latitude
longitude:(double)longitude
andAddress:(NSString *)address;
/*!
@method
@brief 发送语音消息
@discussion
@param localPath 语音本地地址
@param duration 时长
@result
*/
- (void)sendVoiceMessageWithLocalPath:(NSString *)localPath
duration:(NSInteger)duration;
/*!
@method
@brief 发送视频消息
@discussion
@param url 视频url
@result
*/
- (void)sendVideoMessageWithURL:(NSURL *)url;
//当你拍照发图时,走这个方法但当从相册选择图片发送时,会发现,不走上面的方法了。
- (void)sendImageMessage:(UIImage *)image;
仔细检查代码发现走了EaseMessageViewController.m的如下方法
然而这个方法,环信并没有放在EaseMessageViewController.h成为公开方法。我们只需手动粘贴方法到.h,然后在自己的子类重写就可以了。
还有一个关于更多下图更多功能区域的问题
如上图所示,相册、拍照、视频等附加功能按钮,环信用EaseChatBarMoreView类来管理的。
如果需要增加功能按钮用这个方法
/*!移除某个功能按钮用这个方法
@method
@brief 新增一个新的功能按钮
@discussion
@param image 按钮图片
@param highLightedImage 高亮图片
@param title 按钮标题
@result
*/
- (void)insertItemWithImage:(UIImage*)image
highlightedImage:(UIImage*)highLightedImage
title:(NSString*)title;
/*!修改一个功能按钮用这个方法
@method
@brief 根据索引删除功能按钮
@discussion
@param index 按钮索引
@result
*/
- (void)removeItematIndex:(NSInteger)index;
/*!可当你添加按钮,或者修改按钮时,会发现按钮的名字设置不了
@method
@brief 修改功能按钮图片
@discussion
@param image 按钮图片
@param highLightedImage 高亮图片
@param title 按钮标题
@param index 按钮索引
@result
*/
- (void)updateItemWithImage:(UIImage*)image
highlightedImage:(UIImage*)highLightedImage
title:(NSString*)title
atIndex:(NSInteger)index;
然后检查环信内部的实现,发现title的值在方法里根本就没用到?!
索性不用updateItemWithImage这个方法了,直接去改内部代码。
修改代码如下
到EaseChatBarMoreView.m修改- (void)setupSubviewsForType:(EMChatToolbarType)type方法。改动的部分在代码后面有标注。
- (void)setupSubviewsForType:(EMChatToolbarType)type本人github:https://github.com/BHAreslee
{
//self.backgroundColor = [UIColor clearColor];
self.accessibilityIdentifier = @"more_view";
_scrollview = [[UIScrollView alloc] init];
_scrollview.pagingEnabled = YES;
_scrollview.showsHorizontalScrollIndicator = NO;
_scrollview.showsVerticalScrollIndicator = NO;
_scrollview.delegate = self;
[self addSubview:_scrollview];
_pageControl = [[UIPageControl alloc] init];
_pageControl.currentPage = 0;
_pageControl.numberOfPages = 1;
[self addSubview:_pageControl];
CGFloat insets = (self.frame.size.width - 4 * CHAT_BUTTON_SIZE) / 5;
_photoButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_photoButton setTitle:@"相册" forState:UIControlStateNormal];//改动
[_photoButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_photoButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_photoButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_photoButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
_photoButton.accessibilityIdentifier = @"image";
[_photoButton setFrame:CGRectMake(insets, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//改动
[_photoButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_photo"] forState:UIControlStateNormal];
[_photoButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_photoSelected"] forState:UIControlStateHighlighted];
[_photoButton addTarget:self action:@selector(photoAction) forControlEvents:UIControlEventTouchUpInside];
_photoButton.tag = MOREVIEW_BUTTON_TAG;
[_scrollview addSubview:_photoButton];
_locationButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_locationButton setTitle:@"位置" forState:UIControlStateNormal];//改动
[_locationButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_locationButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_locationButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_locationButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
_locationButton.accessibilityIdentifier = @"location";
[_locationButton setFrame:CGRectMake(insets * 2 + CHAT_BUTTON_SIZE, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//
[_locationButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_location"] forState:UIControlStateNormal];
[_locationButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_locationSelected"] forState:UIControlStateHighlighted];
[_locationButton addTarget:self action:@selector(locationAction) forControlEvents:UIControlEventTouchUpInside];
_locationButton.tag = MOREVIEW_BUTTON_TAG + 1;
[_scrollview addSubview:_locationButton];
_takePicButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_takePicButton setTitle:@"拍照" forState:UIControlStateNormal];//改动
[_takePicButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_takePicButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_takePicButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_takePicButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
[_takePicButton setFrame:CGRectMake(insets * 3 + CHAT_BUTTON_SIZE * 2, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//改动
[_takePicButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_camera"] forState:UIControlStateNormal];
[_takePicButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_cameraSelected"] forState:UIControlStateHighlighted];
[_takePicButton addTarget:self action:@selector(takePicAction) forControlEvents:UIControlEventTouchUpInside];
_takePicButton.tag = MOREVIEW_BUTTON_TAG + 2;
_maxIndex = 2;
[_scrollview addSubview:_takePicButton];
CGRect frame = self.frame;
if (type == EMChatToolbarTypeChat) {
frame.size.height = 150;
_audioCallButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_audioCallButton setTitle:@"语音" forState:UIControlStateNormal];//改动
[_audioCallButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_audioCallButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_audioCallButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_audioCallButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
[_audioCallButton setFrame:CGRectMake(insets * 4 + CHAT_BUTTON_SIZE * 3, 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//
[_audioCallButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_audioCall"] forState:UIControlStateNormal];
[_audioCallButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_audioCallSelected"] forState:UIControlStateHighlighted];
[_audioCallButton addTarget:self action:@selector(takeAudioCallAction) forControlEvents:UIControlEventTouchUpInside];
_audioCallButton.tag = MOREVIEW_BUTTON_TAG + 3;
[_scrollview addSubview:_audioCallButton];
_videoCallButton =[UIButton buttonWithType:UIButtonTypeCustom];
[_videoCallButton setTitle:@"视频" forState:UIControlStateNormal];//改动
[_videoCallButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];//改动
_videoCallButton.titleLabel.font = [UIFont systemFontOfSize: 12.0];//改动
_videoCallButton.imageEdgeInsets = UIEdgeInsetsMake(-10, 0, 20, 0);//改动
_videoCallButton.titleEdgeInsets = UIEdgeInsetsMake(14, -60, -20, 0);//改动
[_videoCallButton setFrame:CGRectMake(insets, 10 * 2 + CHAT_BUTTON_SIZE + 10, CHAT_BUTTON_SIZE , CHAT_BUTTON_SIZE+10)];//
[_videoCallButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_videoCall"] forState:UIControlStateNormal];
[_videoCallButton setImage:[UIImage easeImageNamed:@"EaseUIResource.bundle/chatBar_colorMore_videoCallSelected"] forState:UIControlStateHighlighted];
[_videoCallButton addTarget:self action:@selector(takeVideoCallAction) forControlEvents:UIControlEventTouchUpInside];
_videoCallButton.tag =MOREVIEW_BUTTON_TAG + 4;
_maxIndex = 4;
[_scrollview addSubview:_videoCallButton];
}
else if (type == EMChatToolbarTypeGroup)
{
frame.size.height = 80;
}
self.frame = frame;
_scrollview.frame = CGRectMake(0, 0, CGRectGetWidth(frame), CGRectGetHeight(frame));
_pageControl.frame = CGRectMake(0, CGRectGetHeight(frame) - 20, CGRectGetWidth(frame), 20);
_pageControl.hidden = _pageControl.numberOfPages<=1;
}
本人简书:http://www.jianshu.com/u/bb53043aaa00
以上就是集成环信时暂时发现的问题,欢迎大家分享你们遇到的问题,也欢迎加入QQ群:372251359,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂
项目完整源码 收起阅读 »
android studio 2.3.3 最新 中文 汉化包 韩梦飞沙 安卓工作室 美化包
汉化包 百度云盘 下载地址:https://pan.baidu.com/s/1pLjwyeB
最新最详细全面最牛逼的汉化!稳定无BUG!设置界面可以打开!不会报错!中英对照!界面酷炫!
使用汉化美化包,让你的开发工具IDE 不再单调普通,彰显个性,与众不同!
中文的 菜单工具设置信息,让你一眼看懂,让你用好这款开发软件,最大发挥它的作用!
收起阅读 »
环信公开课16期回放|环信智能鉴黄:用深度学习实现99%精准度的鉴黄服务
关于环信智能鉴黄:
随着移动互联网的飞速发展和信息量的猛增,大量的色情、赌博、暴力等不良信息图片夹杂在信息流中,严重影响着整个互联网的体验和健康发展。各大互联网公司为了保持自己所提供的服务不触犯国家法律和法规,使得鉴黄工作变得尤为重要。环信智能鉴黄服务基于深度学习的智能鉴黄算法,识别精准度高达99%,可以帮助企业完成95%的图片内容审查工作,节省90%的时间及人工成本。
环信公开课第16期分享内容:
环信公开课第16期视频回放:
参加环信公开课还有大礼相送:
恭喜手机尾号8985的leoNN同学成为本期公开课幸运观众,获得环信定制版瑞士军团双肩背包。
环信智能鉴黄免费体验请联系环信小助手,微信huanxin-hh
收起阅读 »
【开源项目】一个基于环信IM开发的开源的私密社交APP-Baby
Baby这个开源项目基于环信IM开发,刚开始选择IM的时候,看到知乎上黑环信的人挺多的,就亲自下载了几家IM的demo源码跑一遍,从功能、集成难易和消息稳定几个方面对比,最终还是选择了环信。集成这方面环信做的真不错,尤其是有了EaseUi这个包,基本上一天就能集成完毕。项目运行至今没有出现过什么问题,发送消息挺稳定的。先上效果图
开屏页的登录和注册
编辑个人信息
相册页面
首页的Moment
版本更新:
version 1.6
- 加入Tinker 热修复
- 更新部分依赖
- 修复大量细节问题,加入部分注释
version 1.5
- bug fix
- update sth
version 1.4
- 增加长按删除功能
- 优化Rxbus订阅加载数据
- 外国友人优化的一些细节
- 等等
version 1.3
- 增加了评论功能
- 优化了相册加载
- 修复了一些内存泄漏
- 等等
version 1.2
- 修复了一些Bug
- 把登陆注册事件换了个Zip操作符更符合流的思想
version 1.1
- 修复了主页背景无法切换的问题
- 修复了聊天推送的问题
- 修了语音视频的问题
- 做了一些细节修改
Download
github地址 Development Environment & Library MVP这个项目是基于MVP框架写的(大体上,聊天那块直接用环信的了),大部分Base类参考FastAndroid里边的基类,参考这个很快就能布好基本的MVP架构。本来是有考虑过MVVM后来想想还是先学习一下MVP吧,看过几个MVVM项目感觉还是挺好用的,不过还是BETA版不知道有没有什么坑。Material Design早就手痒想体验一把V7包里边的各种控件了,特喜欢coordinatorlayout和collapsingtoolbarlayout的互动让Tollbar隐藏又现的感觉,但是看起来好看还是要点代价的,在这里捣鼓了不少时间,尤其是collapsingtoolbarlayout的Expanded固定让我Google了好久,因为用英文搜索可能我表达的不太好,最后竟然是一句nestedScroll(false)就可以了。。。。 还是感谢Stackoveflow里边的大腿吧。Dagger2依赖注入Dagger2,也是我早就想用的一个框架了,理由是各种配合Mvp十分方便和好用,渐渐也能体会到一次注入到处可用的快感。不过一个新技术真的学习成本,国内没什么中文文档介绍,看国外的看的云里雾里。原理看的明白,用起来好像不太知道如何使用,尤其是在@inject之后对象,也可以在别的地方Inject,原本是被Inject方后来也成了Module提供方。虽然到最后原理还不是特别明白这里,但还是不阻碍用起来的快感。Realm一开始被新技术吸引到的是不会放过任何新东西的包括Realm,不过进了坑不代表这个坑可以跳阿。由于我这次用到了leacncloud,Realm感觉会和LeanCloud的子类化冲突让你只能选择其中之一,不过这个也算了,Leancloud提供了类似Map的Put方法也可以接受就是麻烦了点。但是被坑到的地方是Realm所谓的自动数据同步竟然是一改就是改真实的数据,并不是数据的拷贝。。。感觉和我使用到要缓存的数据有点冲突,因为这个Moment里边的项是有点赞的,点赞要修改当前Recycleview的数据(修改数据要开事务)。修改数据后会出现一些很奇怪的现象,不在Recycleview当前Item会跳到当前Item,点赞的动画也会消失。。。真的是想破脑袋也解决不了,就直接跳坑了。最后感觉这个Realm在保存不跟服务器需要同步的数据会好点。LeanCloud用LeanCloud是因为在知乎太多吹它的人了而且它的确在BAAS这方面功能比较多(后来才发现即时通信没有语音和视频),所以就尝试使用了,SDK整体来说是不错的都挺好用的,满足了我对存储方面的要求。不过就在我开发的这几天,貌似稳定性没有想象中那么好,好几次上传个头像都会SocketTimeOut,查询也会有点慢,不过还好都在接受范围内(不过要是到了收费的标准我就接受不了)。环信baby这个开源项目基于环信IM开发,刚开始选择IM的时候,看到知乎上黑环信的人挺多的,就亲自下载了几家IM的demo源码跑一遍,从功能、集成难易和消息稳定几个方面对比,最终还是选择了环信。集成这方面环信做的真不错,尤其是有了EaseUi这个包,基本上一天就能集成完毕。项目运行至今没有出现过什么问题,发送消息挺稳定的。Rxjava、RxAndroidRxjava我从第一眼看到了就喜欢上了(个人特喜欢那种通过.设置完成的感觉),接触也有几个月,一开始就和Retrofit 、Okhttp一起使用。学习成本还是要有的阿,看了不知道多少篇关于Rxjava使用的文章和例子,对里边的操作符也仅仅停留在那几个最常用的,其他一大堆好多都没用过,看来还用得不够。GlideGlide也是一个后来居上让我喜欢的图片加载库,一开始我喜欢picasso 是觉得轻巧而且好用有保证(主要是我偶像Jake Wharton主导,有加成),慢慢觉得Picasso对内存没有Glide来的友好,Glide在加载速度方面也领先,虽然整个库代码量是Picasso的几倍,但是比起重要的内存和用户体验来说还是Glide的领先一筹。Butterknife、Ucrop等等当让还有其他的一些润色的轮子啦,不过不是那么重要就不一一感谢啦。Thanks
- 感谢Github、LeanCloud、环信、还有造那么多轮子给我们用的Square FaceBook Google的大大们。
- Thanks for improving my code m-ezzat.
- Email:379489343zhi@gmail.com
- QQ:379489343
Copyright 2016 Roger ou收起阅读 »
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
【环信征文】神通广大的JavaScript
——Atwood 2007
就在前几天“JavaScript是世界上最好的语言”这句话火了,PHP的地位遭受了前所未有的挑战。JavaScript到底有何神通,能登上世界上最好的语言的宝座?
JavaScript是诞生于1995年的一种直译式脚本语言,原名Mocha。JavaScript是一种动态类型、弱类型、基于原型的语言,内置支持类型。JavaScript具备简单灵活和跨平台的优势,会成为解决大部分IT问题的优选方案。著名程序员 Jeff Atwood 在2007年发布了著名的 Atwood's Law: “Any application that can be written in JavaScript, will eventually be written in JavaScript. (一切可以用 JavaScript 编写的程序,最终都会使用 JavaScript 编写)”。就像世界上大多数人都是白种人一样,GitHub上用JavaScript写的代码也占据了大多数,JavaScript的开放性和简洁性功不可没。
网页前端
JavaScript最初是用来给HTML网页增加动态功能的。与JavaScript同时出现的JScript、ActionScript和ScriptEase等都几乎销声匿迹,但JavaScript仍然被广泛用于Web应用开发,也用来为网页添加各式各样的动态功能,为用户提供更流畅美观的浏览效果,甚至成为了前端开发的代名词,这就说明了JavaScript的强大之处。
为传统企业做一个展示网站通常耗时以周计,此时开发者只要找一个模板就够了。而开发时间以月计的互联网公司前端开发工作就不得不选择一个合适的框架了,以下是世界主流的JavaScript前端开发框架和类库:
出自Google的前端开发框架Angular.js自带MVC框架,通过新的属性和表达式扩展了 HTML,并且通过被称为指令(directives)的结构让浏览器能够识别新的语法,现在已经凭借数据双向绑定成为了使用人数最多的前端开发框架。
来自FaceBook的前端开发框架React.js的设计思想是用组件套组件的方式来绘制Web画面。现在大家开发前端的思路早已不是当年的 Web page,而是 Application——传统的HEML+CSS已经不适合这个时代了,组件化开发即将成为主流。
国内前端专家尤雨溪的前端开发框架Vue.js在GitHub的Star数量已经非常接近React.js,Vue.js能像织席贩履的刘备一样与出身名门的Angular.js和React.js鼎足而立的原因在于提供了更加简洁、更易于理解的API, 更加轻量级也更加容易上手。自带MVVM架构的Vue.js必将以开源世界中国人的骄傲载入史册。
体量并不能称为一个“框架”的jQuery是一个号称“Write Less,Do More”的JavaScript类库,封装了大多数常见、但写起来复杂的实用代码段,如优化HTML文档操作、事件处理和动画设计等。
服务端和大数据
JavaScript不仅适合前端开发,Node.js的出现使得JavaScript程序员进行后台开发成为可能。Node.js是一个基于 Chrome V8 引擎的 JavaScript 运行环境,其包管理器 npm是全球最大的开源库生态系统。无论公司自备机房还是使用阿里云、金山云等云服务,Node.js都是创业团队的最佳选择。但因为JavaScript是单线程语言,在处理高并发和大数据等问题上常常力不从心。
如果你是一个Android或iOS开发者,服务器仅仅是给自己业余项目或开源项目用的,那么Bmob云(没错,Bmob云端代码也是JavaScript)也能为你提供一个小而美、并且价格低廉的服务器。
网页游戏
网页游戏不都是粗制滥造的“一刀999级”或“屠龙宝刀,注册就送”等圈钱产品,用浏览器玩的游戏也能做到画面精美、特效绚丽。
Cocos2d-x-js是全世界最著名游戏框架Cocos2d-x专为HTML5游戏设计的JavaScript版本,采用原生JavaScript语言编写。随着Flash退出历史舞台,掌握Cocos2d-x-js技术的程序员就是新一代的闪客。
2014年2月创立于北京的Egret是一套完整的HTML5游戏开发解决方案,其核心产品白鹭引擎(Egret Engine)凭借上手简便、性能强大已占据国内超七成的手机页游引擎市场份额。Egret布道师徐聪(笔名:臭臭打不死人)不但能用自己精益求精的技术和助人为乐的精神帮助开发者解决使用Erget时遇到的技术问题,还经常向有探索精神、帮助其他开发者了解Erget的开发者赠送礼物。
移动端
最著名的HTML5移动开发框架当属Facebook发布于2015年的React Native(顾名思义,是上文提到的React.js的一个分支),这是一套跨平台、动态更新的 Javascript 框架,口号是“Learn once, write anywhere”。与之类似有同属舶来的PhoneGap等。
国产的HTML5开发框架在国内也百家争鸣,常见的有HBuilder和AppCan,二者共同特点是都为了便于新手入门制作了专用的编译器。2016年,在Qcon大会上宣布开源的Weex也异军突起,来自阿里的它因为开发的软件与原生App别无二致受到很多人的青睐。
掌握JavaScript的程序员在国内还有一个新出路,就是微信开发。在国内有7亿用户的微信向广大JavaScript程序员提供了无数公众号和小程序开发的就业岗位,并且现在的移动互联网创业公司或者想涉足移动互联网的传统企业都可以先用微信公众号和小程序试水而不必一开始就开发成本高昂、进度缓慢的原生App
VR
2016年被誉为“中国VR元年”,其实VR并不神秘,只要掌握了眼球追踪和立体视觉,一切3D引擎都可以摇身一变成为VR引擎。而JavaScript恰好编写过几款著名的2D引擎
Three.js是3D绘图协议webGL的一款框架,也是增长最迅速的和讨论最热烈的3D游戏引擎;React VR是FaceBook今年推出的基于JavaScript框架的虚拟现实创建工具……这些五光十色的框架大大降低了JavaScript程序员涉足VR的门槛。
Egret Engine3D游戏引擎是国产的3D游戏引擎,不但网页兼容性更好,更支持手机浏览器,加载也更快,还配套了3D骨骼等配套工具,更具备支持将VR游戏发布到微信公众号及小程序的中国软件的种族优势。
尽管目前VR领域仍然是Unity-3d的时代,VR程序员都是写C#的,但JavaScript征服VR世界只是一个时间问题。
AI
AlphaGo击败柯洁的新闻在科技界引发了轩然大波,AI一夜之间登上了各大送索引擎的搜索榜首。
理论上一切图灵完备的语言都能成为AI开发语言,而JavaScript正是图灵完备的。无数JavaScript程序员致力于JavaScript在自然语言处理和手写识别等领域的研究,目前国外已经出现用JavaScript编写的人脸识别工具Landmarker.io
尽管目前业界主流观点还是“AI入门用Python,AI追求性能用C++,AI工业化用Java”,但我们仍然可以坚信克服了AI专业库缺失和无法精确控制内问题的JavaScript终将在AI领域占据一席之地。
loT
loT比一般的软件系统多了一个硬件层,这就决定了loT的架构的复杂程度,常常需要多种语言的配合才行:
1、用Arduino给硬件编写一个控制器
2、用使用C语言编写的Raspberry Pi连接网络,并传输控制信号给硬件
3、用“钩子语言”Python连接以上两条
4、用Java语言编写一个Android应用,用手机作为遥控器
……
万幸这个需要掌握多种语言才能进行loT工作的时代即将成为过去式。三星设计了用JavaScript编写的物联网引擎loT.js,它的运行内存小于64kb,而且全部代码能够存储在不足200KB的ROM上,如此轻量的体积在智能家居等硬件设备上有明显的优势。由此可见,物联网也将成为JavaScript工程师的新蓝海。 收起阅读 »
精通环信开发已成程序员招聘刚需?看别人家的招聘要求
一段不到200字的招聘要求,竟然出现了两次“环信”。眉头一紧,感觉这事不简单了!
去年在环信社区看到《今天面试一个自称两年经验的Android》《我又做了一次面试官》两篇面试经历还不以为然,没想到一年内作者预言成真,精通环信开发等第三方API开发已然成为程序员招聘刚需!
作为一个与时俱进的好司机赶紧打开X度搜索“如何精通环信开发”,还真让我找到了环信Alpha全国开发者培训计划,
环信alpha计划将对所有报名的ISV厂商和开发者提供技术、审核认证及发行等方面的支持。环信“Alpha计划”旨在为ISV和开发者们提供更加全面且专业的支持,帮助其在包括企业IM、协同OA、APP内社交、直播互动、IOT、智能硬件等领域挖掘产生更多落地有商业前景的优质项目,一起建设整个即时通讯云服务生态。
文末有小伙伴愿意去这家福建公司的发送简历到duc@easemob.com邮箱,暗号“我精通环信开发”,我们等的就是你! 收起阅读 »
该用哪种技术或框架来开发
最近,常常被人问到你团队有用甚幺新技术或是框架去开发?或是,我们因该要用什幺新技术和选哪一个框架去开发,这系统比较好?用AngualrJS好像不错。现在很热门,采用SPA开发网页好像可以节省带宽,使得整体反应相当快速…等。突然觉得在这技术爆炸年代,让开发变得很不单纯,又当微软宣布.NET走向开源之后,不管在前端(前端Framework更是雨后春笋般出现)或后端的技术开发,或是新的框架的诞生,真是多到不知道该怎样去选择才好,
有些时候,感觉不去”使用”这些新的语言或是新的开发方式去开发系统,就好像是落伍或是跟不上时代,又或是外界媒体不段在洗脑或是传达某些技术,感觉使用这个才是王道。(注意,这边我是用”使用”一词。因为,学习跟使用 这两者是不同),确实,当时代不断改变,人是必须不断去学习各种程序和新技术所带来的冲击,至少当你是走在信息这个产业时,必须要有的领悟。回到该用那种技术或框架开发系统这一个问题,我个人觉得如果你本身不是公司老板或是在公司的政策强迫下,在使用新技术去开发可以从下面三个层面去思考,
解决问题
这一层面主要是从商业或是业务需求面去看。我认为不管那一种的新技术或是新框架的诞生,都是为了解决当时的一些需求或是某开发上的问题所衍生出来的。因此,当我们去开发一套系统时候,不该一昧认为最新的技术就是最好用的,而是,必须先做事前的分析,了解目前的业务需求举例来说,如果你的系统,未来只会去服务十个用户,而它的目的只是让用户加速他日常工作或是简化一些流程(别笑,很多in House系统就是这样),单纯用自己拿手的WebForm开发就可以解决用户问题?是否有必要采用SPA方式去开发?又或是,当大家都在谈论开发要搭配AngularJS,但,整体需求面看不到,导入AngularJS会解决业务或是架构问题时,是否单纯搭配Javascrip或Jquery就可以呢?不过,如果今天你的系统必须要高性能高可扩充性且需要降低网页传输量,那请使用SPA,甚至ReactJS去开发,或是,一些可以解决这方面的技术,即使困难度很高,还是有其导入必要性。一切都必须从需求和解决问题去思考该用哪一种技术。
开发ROI
这一层面主要是从系统开发过程的投资报酬率去看开发系统的ROI评估,这一点很重要,一套不熟悉的框架或是技术的导入,对一般人来说都是一个高成本的投入,像是在新创团队中,能快速将自己的发想或是解决问题的方法变成产品,并赶紧丢到市场验证,验证回来后再持续快速修正,这才是最有效益的,投入一个你都不熟悉的技术或是框架,等你摸完再开发出来,此时,你的投资回报率已经不见了,因为,你的可能主意已经被别人捷足先登了。而在一般企业中,MIS往往都被时程压着打,甚至,从分析到开发测试,往往只有一两个月就要完成,且通常还会被用系统产出率决定MIS的绩效,与其导入一个比完成需求还复杂的技术或是框架时,还不如采用合宜的目前需求的框架去开发,那样怎样才知道要用那些技术或是框架才合宜呢?这就是开发人员还是要持续的原因有时候学习的广会比学习的深还有帮助
维护成本
这一层面则是从团队文化去看对于开发In House系统来说这是很重要的考量,且往往又是很不好拿捏,就拿内部系统开发来说好了,内部系统大都是像是肝一样,辛苦但往往会被忽视。而且,内部系统不是说时间到就可以升级版本,或是,旧版本就不去维护。也因此,久而久之,可以发现MIS要了解的语言从 VB6到.NET 5都有,还不包括一些林林种种的分支技术。再者,加上公司人员来来去去,系统的Owner不断改变,需求不断增加(新需求往往会被建筑在多年前的系统上)维护成本就越来越高了。从维护成本思考下,就必须了解整个团队对于该技术与框架的熟悉度。若只是,团队中只有一两个人对此框架熟悉,大部分都不熟悉时候,就要强行导入,后续可能就会垫加系统的维护成本了,毕竟,当系统上线有异常时候,团队有办法去维护吗?可被允许的down time是多少?又或是当商业需求改变,要立即增加或是修改系统功能时,所要付出的成本是多少。从以上角度思考,是否要此刻运用此技术或是框架到团队中就是需要评估的,又或是该逐步提升团队技能或是熟悉度再做考量呢?
技术 这东西有如两面刃,它可以带来很大效益,同时,也会伴随许多风险,唯有不断学习和改善才可以去降低使用风险,而无论是架构设计或是技术框架的导入,还是必须依附在商业与业务需求,过多或是不及架构或是一昧听从潮流而去使用的技术,对于产品和系统的帮助都不大。
从团队角度来看,若是成员技术差异很大时候,与其采用一些新技术,还不如先提升成员的技术力,让大家彼此的能力差距缩小,纵使使用一些旧有技术又何妨呢?现在已经是不缺选择使用框架与技术的世代,而是要怎样选择的才是有助于整体开发的思维了。
以上只是个人长期所处产业的开发经验与看法之分享
转载自:该用哪种技术或框架来开发 | Teambition知识文档 收起阅读 »
【环信征文】程序员如何成为别人的男朋友
潘
第一要素“潘”指的是貌若潘安。
程序员素以不修边幅出名,着装仪表各种混搭:发际线像清穿剧里的阿哥,黑眼圈像动物园里的熊猫,上半身的格子衫、冲锋衣像送外卖的骑手,下半身的大裤衩、人字拖像索马里的海盗……这是典型的注孤生打扮。
为了改变妹子们对广大程序员朋友们的刻板印象,我制定了一份程序员外观改造计划,实施之后你也会变得像《微微一笑很倾城》里的肖奈一样帅:
(1)桌子上摆一盆多汁的多肉植物,比如芦荟。电脑显示器辐射都脸部皮肤危害巨大,多肉植物能吸收大量辐射,而且当程序员感觉脸部皮肤干涩的时候可以随手掰掉一块,拿天然的芦荟胶抹自己一脸。
(2)抽屉里常备一把木梳。脑力劳动会造成头部温度过高;并且头部血液供应大脑,导致头皮供血不足;这些都是让程序员聪明绝顶的罪魁祸首。如果在等待编译或者sync的时候用木梳按摩自己的头皮,会刺激毛囊上皮细胞,抑制毛囊进入休止期,让程序员的头发一如既往的茂盛。
(3)买一些时尚的衣服。俗话说“人靠衣装”,衣服的时尚或邋遢会对一个人的外观造成决定性的影响,因此没事常去商城转转,搭配几件经典复古风或者街头休闲风的衣服,能把颜值和魅力提高不止一个档次。
(4)清空收藏夹里没有备注的链接,删除硬盘里的隐藏文件。国家一级演员吴刚表情光明磊落的时候是耿直纯真的市委书记李达康,面目笑里藏刀的时候是阴险狡诈的军统特务陆桥山——气质是一个人外表的重要组成部分,少看点不文明的视频,脸色就不那么枯槁了;少想点不健康的故事,眼神也就不那么猥琐了。
驴
第二要素“驴”指的是身体像驴一样健壮。
程序员是典型的脑力工作者,在充满电脑辐射的室内环境中久坐不动会导致严重的大脑发达、四肢简单的亚健康症状。程序员加班猝死已经不再是新闻,“但愿有头生白发,何忧无地觅黄金”,我们不能为了忙于工作牺牲健康。对于危害程序员健康的几大职业病,我们应该对症下药:
(1)肾结石、前列腺炎。下半身的疾病基本都是久坐不动导致的,最简单的办法就是站立式编程,最好桌子下面放一个跑步机;没有条件的程序员可以在工作时多喝水,这样有助于增加起身上厕所的次数。
(2)肩周炎、颈椎病。程序员的职业生涯读的最后一本书常常是《颈椎病康复指南》,因为屏幕不一定正对着人脸,所以程序员不得不弯腰驼背。如果不能定制桌子,那么可以坐能调节高度的人体工程学座椅,让你只有在保持正确坐姿的情况下才能正对屏幕。没有条件的程序员可以拿几本旧字典把显示器垫高。
(3)失眠、肥胖、骨质疏松。脑力劳动者的运动量普遍偏少,为了避免失眠、肥胖、骨质疏松,程序员可以在夜间做瑜伽、体操、太极拳之类的有氧运动。下班早的话可以跑跑步打打球,但加班到深夜就千万不要做任何剧烈运动,容易猝死。
邓
第三要素“邓”指的是像邓通一样有钱。
程序员账面收入很高,但增量优势在绝对的存量都是浮云。我曾经卧底某一线城市Android千人群,1000人中没一个是有房子的本地人。为了使自己在资产上的劣势不太明显,增加8小时外的收入至关重要。
(1)程序员赚外快最直接的方式就是做一个接单的威客。但需要注意的是,写出客户满意的软件很容易,但找到收到满意的软件之后和你说自己很满意并且乐意付费的客户很难。
(2)录制教学视频。利用自己编程的经验录制教学视频,放在网站上供人付费下载,这种方式就像一本万利的培训机构一样,赚那些觉得程序员是一个“整天坐在办公室玩电脑就有工资的工作”的人的钱。
(3)译书或著书。如果你属于同时精通编程和外语,或者博客阅读量和粉丝数巨大的IT红人,那么版税就是你最重要的被动收入。
(4)前三样都很耗时,如果你想通过一种短平快的方式赚取外快,可以向imGeek投稿。只要你写一篇关键词为“环信”、“移动开发”、“人工智能”等相关的文章,就有可能获得50~500元现金奖励。
小
第四要素“小”指的是脾气小,并对女性体贴入微。
程序员常常遇到客户催逼进度或者产品经理乱改需求的情况,一来二去就变得急躁易怒。再加上程序员与电脑打交道比与人打交道多,因此也不容易对女性体贴入微。
根治程序员常发脾气的毛病不用医生开药方,用机械键盘即可痊愈,越沉重、价格越昂贵的机械键盘疗效越好,HHKB最佳,国产的狼蛛鬼王亦可。
软件工程专业学生Nerd因为大学前三年贪玩LOL不好好学习,基础松松垮垮,概念一知半解,导致大四做毕业设计时常常感觉力不从心,于是常常借口“释放压力”更加沉迷LOL。Nerd搞毕业设计遇到瓶颈的时候,其实谁都知道大多数是玩LOL被猪队友坑了的时候就发脾气,拿键盘砸桌子,在外实习的室友每周回宿舍都能看到一屋子键盘的碎片。好在校园里电子产品商店的东西便宜,键盘20块钱就能买。有一天Nerd过生日,室友送给Nerd一副电竞专用的狼蛛鬼王键鼠套装。Nerd又一次听到“defeat”的声音的时候,条件反射一般抡起了键盘,只不过在砸向桌子的一瞬间住手了——他首先想到的是这个键盘砸坏了之后20块钱买不来新的,然后又想到了1kg的钢板砸下去桌子也碎了。
Nerd脾气变小了以后,身边很快就围过来一群妹子,他终于顺利脱单。
闲
第五要素“闲”指的是有大把的休闲时间。
程序员工资虽高,可这都是默认包含加班费的,因此休闲时间常常不能得到保障。但陪妹子的时间就像北漂地下室蚁族程序员的牙膏一样,挤不出来拿擀面杖也能擀出来。
在8小时之内要合理利用设计模式。每天拿出一小时学习设计模式,第二天可以节省一小时复制粘贴高耦合度代码的时间。但需要注意很多设计模式都是牺牲运行效率换开发速度,因此并非所有设计模式都适合对性能要求高或者硬件质量严苛的软件。
在8小时之外要减少无用社交。积极回答IT新人的问题是一个好习惯,谁知道隔着屏幕的那个人是不是3年前的自己。不过百度前两页就有答案的问题就不要回答了,不要把时间浪费在不值得帮助的人身上。
收起阅读 »
基于办公的 IM 的基础设计
所以,这些 IM 在操作界面上会有一个会话列表:表现出来会是联系人名单、聊天群列表等等。选中会话列表中的项目,进入会话查看聊天记录、发言,就是这类 IM 的使用逻辑。
我认为,这种对即时通讯的抽象方式,其实是不适合办公环境的。和日常个人社交环境不同,办公群体其实是一个相对关系密切的团体,我们通常不会拉黑一个同事不让他给你发消息,也不会拒收公司发的通告,也不会因为一个同事平常不和你打交道就拒绝建立联系。项目组里的讨论,也未见得是多么保密的事情,需要防止隔壁组的同事旁听。你也很少会在办公 IM 上和妹子私聊谈人生理想。
我们这几年使用腾讯的 RTX 作为公司办公使用,我就感受到了太多这类设计缺陷。比如,有同事找我有事,我忽略了他的私聊信息;找人一般在对方活跃的项目群组里吼;程序群沦为了日常扯淡的位置,常常同时讨论着不同的问题,线索及其混乱。“群”这个设计,我在很多年前就思考过 ,我一直觉得需要在根本上换个角度看待社交聊天的需求。
我现在的想法是这样的:
作为办公 IM ,我们不应该基于固定会话(群)来设计,而应该是“通知”和“话题”。
所谓通知,就是有人发起了一条消息,他需要把这条消息传达给某些对象,对象可以是人,也可以是某个组织:比如程序、游戏项目组、等等。
组织并非是群那样的聊天室,而仅仅是一个标签,由人来关注标签,而不是去组织这个聊天室里有多少听众。
而话题,则是由消息或旧话题衍生而来。任何通知消息、话题内部消息,都可以变成一个新话题。话题也可以包含在一则消息里转发给某个对象。
用户的客户端应该把所有的通知按时间线排列在一起,呈现在同一个地方。也就是说,无论是谁给我发消息(默认就是通知)都应该投递在一起,而不是像现在 RTX 那样只是在系统托盘里闪烁提醒、也不是微信 qq 那样,联系人名单上多出一个小红点。
而一旦我回复一个通知消息,其实就把这则通知转化成了一个话题,在时间线上,话题内的消息是归属在一起的。同一时刻,无论你的思维切换多么快,其实在短时间内你只能聚焦在一个话题上,所以客户端界面是很容易表达的,把当前话题展开在主界面(通知的时间线)即可,切换话题后自然可以折叠起来。
话题并不是聊天室、它更像是论坛的帖子。一个话题可以有很多人参与(至少发言一次),更应该支持更多的人浏览。我们不应该按聊天室的思路:用户只有在加入聊天室的那一刻开始,才能收到后续的消息,而应该像论坛那样,他只是打开了这个话题帖,可以随时聊天过去到现在发生的事情。话题内的任何一个消息,都可以由用户展开为新话题,老话题对新话题只是一个引用链接而已,并不需要有层级关系,我们也可以把任意一个话题或尚未转化为话题的消息转发出去,如果有人对他评论,就生成了新话题。
话题是一个有时效性的东西,对于办公来说,如果一个话题超过 8 小时没有新的消息,就可以认为这个话题已经结束了。但是事后我们依然可以对老话题浏览,或是继续讨论,而继续讨论就是生成的一个新话题了。
只要生成话题足够方便,每个用户的主时间线上就只会有不多的通知消息,信息传达更为有效。而管理每天的消息、检索旧消息也有很强的时间线。不像现有的 IM 群聊天,每天的聊天内容会被自然的组织成话题,这些话题上标识了参与人数、归属的组织的 tag 、继承于哪个父话题或通知、经历的时间段、衍生出哪些后续话题,等等。
即使是两个人之间的对话,也同样应该是话题的形式,而不应该把消息直接组织成一长串的聊天历史。话题未必有明确的主题,只是一种更自然的信息聚合形式而已。
对于办公场合来说,有意个最重要的优势:用户群有足够的自律。基于这种自律,我认为上面的思路若实现出来很容易推广使用。
在自律之外,或许还需要一些权限管理。这些权限管理应该是相对松散简单的,主要是限制用户订阅特定组织的 tag (比如一般员工不能订阅管理层的 tag ),限制围观特定话题(比如两人之间的私聊话题默认就是不对第三人开放权限的),话题可以锁定不准转发。权限设置的细节还需要进一步推敲。
本文转自云风的BLOG,原文地址http://blog.codingnow.com/ 收起阅读 »
【移动战略说 · 第一期】智能硬件产品开发从0到1
开发一款智能硬件产品涉及的环节很多。本次活动,APICloud联合华强聚丰和智石科技,从样品生产、App开发和近场通讯技术在智能硬件中的应用跟大家分享智能硬件产品如何快速从0到1!
活动概况
【活动时间】2017年8月19日(周六),13:30-16:30活动议程
【面向人群】制造业企业、智能硬件管理层、产品负责人、技术负责人,其他相关从业者
【活动咨询/合作】请加微信:appdev1,备注819
【13:30-14:00】签到分享嘉宾
【14:00-14:40】如何快速完成样品生产
内容概要:产品硬件开发者希望快速拿到样品,进行方案验证和调试,发现设计问题,快速进行方案修正,以便进入下一开发环节,完成开发工作。怎样解决这些困难?怎样才能让生产环节快速顺利完成样品生产?
【14:40-15:20】自主研发or外包?智能硬件App开发指南
内容概要:现在市场上智能硬件往往需要一款App配合,无论是控制设备还是查看数据。企业不但需要考虑成本,还要兼顾产品体验。本环节APICloud将会为大家介绍App开发技术如何选型;自己招团队与找外包的对比;以及项目准备、开发、测试、上线各个阶段可能遇到的问题和注意事项。
【15:20-16:00】室内精准位置物联网络搭建
【16:00-】幸运抽奖&自由交流
报名地址活动报名 收起阅读 »
【环信征文】程序员为灾区祈福,我听说过的语言差不多都有了
~trace("ActionScript程序员为灾区祈福!");
~TEXT_IO.PUT_LINE ("Ada程序员为灾区祈福!");
~<% Response.Write("ASP程序员为灾区祈福!") %>
~MsgBox(1,'','AutoIt程序员为灾区祈福!')
~BEGIN { print "AWK程序员为灾区祈福!" }
~echo 'Bash程序员为灾区祈福!'
~? "BASIC程序员为灾区祈福!"
~WRITES ("BCPL程序员为灾区祈福")
~Print "BlitzBasic程序员为灾区祈福!"
~print "BOO程序员为灾区祈福!"
~printf("C程序员为灾区祈福!");
~cout << "C++程序员为灾区祈福!"<<endl;
~System.Console.WriteLine("C#程序员为灾区祈福");
~PROCEDURE DIVISION.DISPLAY "COBOL程序员为灾区祈福!".STOP RUN.
~echo Linux Shell程序员为灾区祈福!
~io.put_string("Eiffel程序员为灾区祈福!")
~hello_world() -> io:fwrite("Erlang程序员为灾区祈福!").
~." Forth程序员为灾区祈福!" CR
~WRITE(*,*) 'Fortran程序员为灾区祈福!'
~HTML程序员为灾区祈福!
~System.out.println("Java程序员为灾区祈福!");
~<%=("JSP程序员为灾区祈福!")%>
~(format t "Lisp程序员为灾区祈福!")
~print "Lua程序员为灾区祈福!"
~Print["Mathematica程序员为灾区祈福!"]
~Nuva程序员为灾区祈福!
~NSLog(@"Objective-C程序员为灾区祈福!");
~print_endline "OCaml程序员为灾区祈福!";
~writeln('Pascal程序员为灾区祈福!');
~say "Perl程序员为灾区祈福!";
~<?= "PHP程序员为灾区祈福!"?>~
~write("Pike程序员为灾区祈福!");
~write("Prolog程序员为灾区祈福!").
~#!/usr/bin/env pythonprint("Python程序员为灾区祈福!")
~say "REXX程序员为灾区祈福!"
~#!/usr/bin/rubyputs "Ruby程序员为灾区祈福!"
~Om:"Sbyke Laborana程序员为灾区祈福!"
~(display "Scheme程序员为灾区祈福!")
~sed -ne '1s/.*/sed程序员为灾区祈福/p'
~writeln("Seed7程序员为灾区祈福!");
~Transcript show: 'Smalltalk程序员为灾区祈福!'
~TextWindow.WriteLine("Small Basic程序员为灾区祈福!")
~OUTPUT = "SNOBOL程序员为灾区祈福!"
~print 'SQL程序员为灾区祈福!'
~println("Swift程序员为灾区祈福!")
~#!/usr/local/bin/tclputs "Tcl程序员为灾区祈福!"
~? "TScript程序员为灾区祈福!"
~put "Turing程序员为灾区祈福!"
~<includeonly>UNIX-style shell程序员为灾区祈福!</includeonly>
~ShowMessage('Delphi程序员为灾区祈福!');
~Print "Visual Basic程序员为灾区祈福!"
~? "Visual FoxPro程序员为灾区祈福!"
~QLabel label("X11程序员为灾区祈福!");
~alert("JavaScript程序员为灾区祈福!");
~(PostScript程序员为灾区祈福!) show
~println("Scala程序员为灾区祈福!")
~println("Kotlin程序员为灾区祈福!");
~调试输出(“易语言程序员为灾区祈福!”) 收起阅读 »
【环信征文】请不要说自己是Android程序员
软件行业是一个非常强调人的价值的行业,价值就体现在有效的推动产品前进,而语言只是实现这个价值的工具。
一个软件产品往往涉及很多方面的知识,比如网络、数据库、Cache、编译环境工具等。如果这些必要基础知识不足,很难很好的独立完成一个产品的某个部分。
另一方面,一个人的聪明程度、对新知识的好奇心、自我驱动意识、为问题找到最佳解决方案的决心,才是他能不能成为一个好程序员的关键。举个例子,我的一位在某米当cto学长的告诉我,有位同事本来是服务器端以C#语言为主做开发的,完全没有过android开发经验,但他表现出对移动开发很有兴趣,并且在做服务器端开发时,表现出良好的学习能力,后来我把他调到Android组,负责android SDK和APNs相关的工作,结果只花了几个星期,Android SDK的稳定性大幅提升,解决了多个致命问题。
不要仅仅把自己定位为某种语言的程序员,说自己是Java程序员,C#程序员,Python程序员等等。一方面会限制自己的发展,一方面对团队整体的能力提升也不利。几乎所有的语言都有它自己的适用场景,在合适的地方用合适的语言,才能极大的提升生产效率。
正确的做法是,首先要有良好的基础知识,深刻的掌握2~3门语言,然后适用于不同场景的语言要了解概念。基础知识包括各种计算机原理、数据方面的知识,在学校没认真学的,现在有时间也要补充。语言方面比如掌握了C/Java,那C++/Python/Bash/Javascript/CSS等都可以了解下概念,至少要理解在一个完整的产品链里,它们分别适用于哪个环节。
标题用“请不要说自己是Android程序员”没有贬低Android程序员的意思,Java是目前被采用得最多的语言,主要用Java的程序员里,也是有大量牛人。另外,同样的,也不要说自己是C程序员、Python程序员。
古语说的好,“书中自有黄金屋”。这句话告诉我们书籍是学习知识的第一大根本方向。在与Java相关的专业书籍中,相继记述着关于这门课程的基础知识及进阶内容,先易后难、步步深入,非常适合初学者去学习。
虚心求教不可少。
往往很多高深莫测,经验丰富,功力深厚的人都埋藏在自己的身边,不容自己去察觉。所以如果大家想要从事Java行业,不妨请假身边从事过该行业的朋友,求学不在高低贵贱之分,只要碰到不懂的地方,就去虚心求教,世界这么大,而且这门知识又是如此让人追捧,比自己懂的人岂止千百?从这些人身上自己一定能够受益匪浅。
现在以Java语言为主的工作非常之多,另外在学校里就以学习Java为主的人也越来越多。但是,从学校就以学习Java这种高级语言为主的人,很多基础知识比较薄弱。高级语言掩盖了太多细节,提高了生产力,但在学习阶段,却不利于基础知识累积。
“Nicholas C. Zakas是全世界最著名的JavaScript程序员之一,之前是在雅虎将近工作5年。三年前,他写了一篇长文,回顾自己的职业生涯,提到七个对他来说最重要的建议,希望对大家的职业生涯有帮助:
1、 不要别人点什么,就做什么
我的第一份工作,只干了8个月,那家公司就倒闭了。我问经理,接下来我该怎么办,他说:"小伙子,千万不要当一个被人点菜的厨师,别人点什么,你就烧什么。不要接受那样一份工作,别人下命令你该干什么,以及怎么干。你要去一个地方,那里的人肯定你对产品的想法,相信你的能力,放手让你去做。"
我从此明白,单单实现一个产品是不够的,你还必须参与决定怎么实现。好的工程师并不仅仅服从命令,而且还给出反馈,帮助产品的拥有者改进它。
2、 推销自己
我进入雅虎公司以后,经理有一天跟我谈话,他觉得我还做得不够。
"你工作得很好,代码看上去不错,很少出Bug。但是,问题是别人都没看到这一点。为了让其他人相信你,你必须首先让别人知道你做了什么。你需要推销自己,引起别人的注意。"
我这才意识到,即使做出了很好的工作,别人都不知道,也没用。做一个角落里静静编码的工程师,并不可取。你的主管会支持你,但是他没法替你宣传。公司的其他人需要明白你的价值,最好的办法就是告诉别人你做了什么。一封简单的Email:"嗨,我完成了XXX,欢迎将你的想法告诉我",就很管用。
3、 学会带领团队
工作几年后,已经没人怀疑我的技术能力了,大家知道我能写出高质量的可靠代码。有一次,我问主管,怎么才能得到提升,他说:"当你的技术能力过关以后,就要考验你与他人相处的能力了。"
于是,我看到了,自己缺乏的是领导能力,如何带领一个团队,有效地与其他人协同工作,取到更大的成果。
4、 生活才是最重要的
有一段时间,我在雅虎公司很有挫折感,对公司的一些做法不认同,经常会对别人发火。我问一个同事,他怎么能对这种事情保持平静,他回答:"你要想通,这一切并不重要。有人提交了烂代码,网站下线了,又怎么样?工作并不是你的整个生活。它们不是真正的问题,只是工作上的问题。真正重要的事情都发生在工作以外。我回到家,家里人正在等我,这才重要啊。"
从此,我就把工作和生活分开了,只把它当作"工作问题"看待。这样一来,我对工作就总能心平气和,与人交流也更顺利了。
5、 自己找到道路
我被提升为主管以后,不知道该怎么做。我请教了上级,他回答:"以前都是我们告诉你做什么,从现在开始,你必须自己回答这个问题了,我期待你来告诉我,什么事情需要做。"
很多工程师都没有完成这个转变,如果能够做到,可能就说明你成熟了,学会了取舍。你不可能把时间花在所有事情上面,必须找到一个重点。
6、 把自己当成主人
我每天要开很多会,有些会议我根本无话可说。我对一个朋友说,我不知道自己为什么要参加这个会,也没有什么可以贡献,他说:"不要再去开这样的会了。你参加一个会,那是因为你参与了某件事。如果不确定自己为什么要在场,就停下来问。如果这件事不需要你,就离开。不要从头到尾都静静地参加一个会,要把自己当成负责人,大家会相信你的。"
从那时起,我从没有一声不发地参加会议。我确保只参加那些需要我参加的会议。
7、 找到水平更高的人
最后,让我从自己的经历出发,给我的学员一个建议。
"找到那些比你水平更高、更聪明的人,尽量和他们在一起,吃饭或者喝咖啡,向他们讨教,了解他们拥有的知识。你的职业,甚至你的生活,都会因此变得更好。"
我的感受是IT行业是当今社会的热门行业,说它热门是因为它的发展潜力是无穷的,所以我们能进入到这个行业是一种幸运。在此,我特别感谢上家公司带我教我前辈们和师傅,在学习期间给了我莫大的帮助,在我遇到困难时,给我很大的鼓励和帮助,让我更加有信心坚持下来,找到工作。最后送大家一句话:相信自己没有选错行业,相信自己有立足的能力,为自己制定明确的目标,然后努力地去学习、体会、感悟、进步!
收起阅读 »
如何阅读计算机科学类的书
作为一个研发工程师,无论你是否喜爱阅读,相信你都一定读过不少关于计算机技术的书籍。这其中不乏《21天学会JAVA》这样的语言入门书籍,也有《算法导论》这样的专题书籍,也有《人月神话》这样关于软件管理学的实用性的书籍。也许你已经读过他们中的大部分,也许你现在还在不断地购入新的书籍来补充你的知识库。但请稍等一下,你是否思考过这样的问题,面对大量的计算机科学书籍,你是否都真正读懂了它们呢?有多少本书,当你将他放在书架上之后,就再也没有重新打开过?有多少知识是真正被存储在你的大脑中,并随时可以提供调用?拿到一本书后,高效阅读的正确姿势的什么?如果你有以上的疑惑,那么接下来,我们将一起探讨一个问题,如何阅读一本计算机科学类书籍。
阅读的四种层次
首先,我们先要学会如何阅读。你可能会觉得不可思议,我已经接受过高等教育,怎么可能还不会阅读。然而可悲的是,现代教育体系中,恰恰忽略了对阅读能力的训练。我们在初中之后,阅读水平就几乎没有机会再得到提升。总体来说,阅读分为四种层次,分别是:
- 基础阅读
- 检视阅读
- 分析阅读
- 主题阅读
这其中的概念来源于莫提默·J·艾德勒和查尔斯·范多伦的著作《如何阅读一本书(How To Read A Book)》,这里我必须对其中的概念做简单的总结,以便在后续的篇幅中,我们能统一对阅读名词的理解。
基础阅读
当我们完成中学学业后,我们中的绝大部分人,都已经掌握了基础阅读的能力。在这个层次中,我们关心的是,书里的每句话是什么意思。这是一个最基础的层次。
检视阅读
检视阅读,我们也可以称之为快速阅读。快速浏览全书,了解书的主题,架构全书,提出核心问题。这并不是很新鲜的概念,但很多人可能并没有思考过,为什么要做检视阅读。检视阅读作用是为了帮助我们筛选这本书是否值得阅读,同时为接下来的分析阅读打下基础。在这个层次中,我们关心的是,这本书在讲什么。
分析阅读
分析阅读是一个更为高级的阅读层次,目标让我们能充分理解本书,与作者对话。其中包含了多个阶段,这里不再详述,有兴趣的同学可以研读原著。
主题阅读
当我们跨越过分析阅读后,这本书已经被我们掌握。此时,我们会就相同的主题,阅读不同的书籍,找出其中关联与矛盾,倾听不同的作者的不同声音,从而对某个主题产生更加深刻的认识。这个阶段,我们关注的不再是某一本书,而是一个具体的问题。
计算机科学书籍的特征
原著中针对不同类型的书籍,给予了不同的阅读建议。但由于所著时间很早,就计算机科学类图书的阅读建议,在书中并没有专门设计章节阐述。根据我的阅读经历,深感计算机科学类书籍,较其他类型图书有着其独特性:
单本书籍的信息量大
相较其他学科,绝大多数计算机科学类书籍并不是以得出结论并且论证结论为核心,而偏重于阐述方法和解释原理。有很多计算机书籍旨在剖析某个系统。这里的系统不仅仅指代诸如操作系统这样的实体系统,还包括一门语言或者一套管理方法论这样的理论系统。而系统通常是由多个部分组成的综合体,这其中势必包含不同组成部分的不同细节,信息量之大可见一斑。
注重实践
计算机科学是一门实用性的学科。这里的实用性可以理解为,计算机科学诞生的目的就是为了解决实际问题。因此,几乎所有的计算机科学书籍,都是以指导实践为目标而作。
更新速度快
计算机科学的更迭速度可以准确地被描述为日新月异。有些技术很快地火爆起来,又很快地消亡,所以有些书也就跟着很快地淹没在时代的进程中。
分类细致但同质度高
计算机科学对自己有着过分清晰的划分,不同的技术之间往往边界清晰。我们很少见操作系统和数据库系统在同一本书中论述,也不常见集不同语言之成的大作。由于领域划分细致,相同领域的书籍,多数时候往往论述的是同样的主题。
阅读计算机科学书籍的误区
绝大多数读者的错误意识在于把所有的书籍都认为是层层推进的论述过程。这样的阅读经验一旦沿用在计算机科学类书籍中,就会感觉举步维艰。前文说过,大多数的计算机书籍都是在剖析系统,一个系统又是由许多相互关联的部分组成。解读这类书籍,如同拆解一个机械,我们在拆解的过程,常常会犯下这些错误。
通读全书
在你的头脑中没有对全书的结构有整体了解的情况下,从头至尾通读全书,意味着试图从细节窥视一个系统的全貌。这是一种低效的读书方式。当读到中落时,你会因为没有全局概念,而迷失在各种细节中,以至于完全失去了阅读的方向和目标。
跳过序言
序言往往是很多人忽略的内容,似乎序言只是重复了正文的内容。而正因为如此,序言以简短精炼的语言,为你分解了整本书的架构,帮助你把握系统的整体。这项工作本来应该是读者在阅读全书之前的必备工作,绝大多数的作者都已经帮你完成了,而你需要做的仅仅是认真的阅读它。
脱离实践
前文说过,计算机科学类书籍重视实践,脱离了实践,往往就不能完全理解书中所述的理论和方法,过目就忘,纸上谈兵。
忽视基础
封装在计算机的世界中是一个非常重要的概念。计算机的发展史,总的来说就是一部封装史:将底层不断包装,提供简单的调用方式,由此不断的扩展计算机的边界和能力。新的技术层出不穷,而他们的很多所依赖的环境和系统,从设计之初就没有发生过质的变化。
有时,在追逐新的技术之前,深入了解他们所在的系统;在学习新的算法之前,掌握好其基础的数学原理。只有牢固的基础才能支撑足够结实的上层建筑。
阅读计算机科学书籍的建议
当了解阅读误区后,你们是不是已经发现阅读这类书籍的核心原理呢?那就是将整本书当做一个系统,从整体到局部,层层递进,逐步剖析。根据这个核心原理,我总结了一些好的实践方式。
检视阅读
当你拿到一本计算机科学书籍,第一步就应该快速浏览序言和目录,然后用检视阅读的方式整理出整本书的大纲。这样,你对这本书是介绍理论还是关注实践,所属什么分类,哪些问题是本书将会讨论,而哪些问题是不被详细讨论的,这些信息你都会有整体上的认知。这时,你就可以很轻松地判断,这本书值不值的阅读,哪些内容是你已经熟知的,哪些内容是你关注的重点,这样做阅读的效率将会大大的提高。
如果从来没有使用过这种阅读方式,开始实践时,会受到一定的心理上的阻力。可能你对某个专有名词完全没有概念,以至于整章的内容都模棱两可。这时,你应该坚持继续阅读,对不甚理解的内容,先记住有这样的概念。绝大多数的时候,经过检视阅读后,过程中的问题都会有所释怀,剩下依然没有明白的内容,视其重要性,再决定是否对其进行分析阅读。
提取问题
当你了解了整本书的全貌,一般而言,你会发现,有些章节你已经熟悉,有些章节你全然不知。这时就要对这些章节进行分析阅读。分析阅读的很多步骤和方法在《如何阅读一本书(How To Read A Book)》有详细的介绍,这里不展开细说。但有时,你在阅读的过程中,会发现阅读的兴趣在下降。信息量愈大,阅读的动力愈弱,最后你就迷失在信息的汪洋之中。
我们应该如何避免这样的信息疲劳呢?答案就是去掉冗余的干扰信息。在上一个建议中,我们强调了检视阅读的重要性。那检视阅读的成果是什么呢?那就是你对每个部分(不一定是书中给你划分的章节)所提出的问题,也可以称之为阅读目标。而你要做的就是,找到这些问题的答案,完成自己的阅读目标。
这样做过滤了很多作者认为重要,其实和你关心的主旨没有联系的信息,减少了信息疲劳。同时,不同部分之间有关联的问题,可以帮助你更好的串联全书阐述的核心概念,把握整本书的主要脉络。
例如,我在阅读《深入理解计算机系统》的异常控制流时,就提出这样的问题:进程是如何管理内存?而部分的答案,在下一个章节虚拟内存中。当我解答这个问题时,我就会将这两个分离的章节的内容,通过一个问题联系在一起,加深了自己的理解。
持续重读
一本经典优秀的计算机科学书籍,值得你反复的阅读。不要觉得整本书我已经完全理解,就再也不需要重新回顾阅读了。因为此类书籍存在大量信息,而这些信息并没有必要占据我们大脑有限的记忆存储空间。我们要做的就是认真做好第一条建议,当我们需要使用这些书籍解决问题的时候,能第一时间在其中找到我们需要的信息。毫不夸张的说,计算机科学类的书籍生来就是供人反复翻阅的。
鉴别烂书
作为阅读爱好者,谁能说自己没读过几本烂书呢。在计算机科学这个类别中,烂书的比例一点也不比其他学科低。信息重复(抄袭),结构混乱,论证不清晰(作者对某个技术一知半解)等等,都是烂书的特征。关于烂书,我们要做的就是第一时间将其鉴别出来,然后放到自己的黑名单中。具体如何鉴别烂书,由于本篇幅太长,我可能会新开一篇文章单独讨论。
结语
以上就是我对于如何阅读计算机科学类书籍的理解。本来想缩短些篇幅,但最后还是决定保留那些我觉得应该详细论述的部分。毕竟这篇文章的初心并非是厕所读物,而是一个阅读爱好者认真地与读者探讨一个严肃的话题。如果可以,我希望在通过我不断地探索,阅读能力的持续提升,我还能在此宝地继续这个话题,完善我的理论。
我在下面列出我认为经典优秀的计算机科学书籍,也欢迎大家补充,排名不分先后。 收起阅读 »
【环信征文】没有几样强迫症,不配自称程序员
0 数字强迫症
数字强迫症的症状是数数从 0 开始,这是中了大多数编程语言的毒导致的。
数字强迫症的另一种症状就是对二进制有执念,很多程序员员都认为世界上有 10 种人:一种懂二进制,另一种不懂。
数字强迫症的晚期症状是认为 256 和 1024 等 2 的 n 次方很完美,常常有 1kg == 1024g 或者 1L = 1024mL 的错觉。
1 格式强迫症
格式强迫症的症状是对代码的缩进要求极其严格,代码务必美观。即使遇到缩进不能再整齐的代码,如果有的缩进是 1 个Tab而有的缩进是 4 个Space都会浑身难受。
当代的IDE做到了Enter换行自动缩进和Ctrl + Alt + L整理格式,大大减少了格式强迫症的发病率,格式强迫症也顺理成章发生了变异。格式强迫症最常见的变异就是从只追求左边的对齐变成了也追求右边的对齐,患者会把IDE的字体都换为等宽字体。
2 命名强迫症
命名强迫症的症状是对类、接口、变量、常量、方法、枚举等的命名既追求简短,又追求直白,希望能一目了然——但一般来说简短和直白就如同物美和价廉一样不可兼得。当命名强迫症作为输入强迫症的并发症出现时,经常会因为一列对象的命名字数不一致而有砸电脑的冲动。
中国的程序员有种特殊的命名强迫症,就是不喜欢拼音命名,看见前任遗留代码中的拼音命名就会火冒三丈。
命名强迫症的另一种症状是不喜欢看到笼统的命名,例如data_1、msg_2、view_3甚至干脆就是i、j、k(方法内部循环除外);更不喜欢看到有误导的命名,比如突然发现这么一句注释:“//以下所有left代表右,所有right代表左”。
命名强迫症的晚期症状就是对驼峰命名法有莫名其妙的痴迷,就连新注册网站的用户名都要严格遵循驼峰命名法。
3 保存强迫症
在Eclipse + NetBean的时代,IDE没有自动保存功能,很多程序员养成了随时Ctrl+S的习惯。而当代IDE基本上都有自动保存的功能,他们的习惯,这就是保存强迫症。
前端程序员上网的时候会不断Ctrl+S。如果网页有文本编辑器,在Ctrl+S的时候会弹出对话框:“文字已成功保存于某年月日”,然后会莫名紧张:“怎么又弹窗了?”好久才反应过来自己在上网。
保存强迫症并非一无是处,患者玩单机游戏会自带“随时使用S/L大法”技能,会大大避免前功尽弃的可能。
4 维修强迫症
维修强迫症的症状是在U盘或者移动硬盘里保存各类杀毒软件、木马库、系统镜像、越狱工具、Android root工具以便随时维修电脑和手机。病因是被七大姑八大姨“你不是程序员吗怎么连电脑/手机都不会修?”逼的。
维修强迫症没有晚期症状,三舅妈的大姑姐找程序员帮她修智能洗衣机等loT设备或者四叔的小舅子找程序员把科学计算器刷成Android系统时就把程序员直接逼死了。
5 硬件强迫症
硬件强迫症的症状是程序员对自己工作有关的硬件要求极高。以下常见的致病硬件的逼格和获得的成本递增:
移动硬盘:移动硬盘是线下的Git,保存无数代码、文档以及秘钥。在“考研资料/政治/马克思主义哲学/第十八章/课程H”下面也隐藏着不为人知的东西。
机械键盘:噼里啪啦的手感和不菲的身价,HHKB是每个程序员的信仰,买不起HHKB的程序员会用国产的机械键盘凑合着用。
iMac或者Macbook Pro:苹果的电脑性能都非常好,编译程序速度非常快。更重要的一点:OS X系统不能玩LOL,避免了浪费写代码的时间。
双显示器:对于前端程序员来说,双显示器不仅是装逼用的,一台竖屏显示器显示WebStorm,而另一台横屏显示器显示Chrome对编程很有帮助的。显示器的价格并不昂贵,昂贵的是能呈 120 度角摆两台显示器的桌子下面的地皮在北上广深杭写字楼里的租金。
人体工程学座椅:五花八门的不正常办公家具包括人体工程学座椅和支持站立编程的桌子等,美其名曰保护程序员的颈椎、腰、屁股和前列腺,受到程序员喜爱的真实原因你懂的。
程序员鼓励师:大多数程序员渴望但不曾拥有过的硬件是只属于自己的程序员鼓励师,换句话说就是在你写代码时红袖添香的女朋友。
6 白盒强迫症
白盒强迫症的常见症状是看见代码就想优化一下。说程序员只怕“error”不怕“warning”是非常错误的,很多程序员见不得黄字和中划线,也见不得蓝色的“// TODO”。
白盒强迫症很多时候都是有益的,可以让代码变得整洁,隐藏的漏洞也会减少。
白盒强迫症的晚期患者每次打开一个网页都要右键查看源代码,已经无法正常上网。
7 黑盒强迫症
黑盒强迫症的常见症状是每次看见闭源的软件都想研究一下里面的原理,再想想自己能不能做得更好。比如用支付宝扫码支付的时候想的是识别二维码、通信加密、支付安全等原理;或者乘坐电梯时看着电梯的按钮面板(现实世界的UI)会开始思考电梯的调度算法,比如多个实例之间状态可以互相影响,还有一些优先级、加速度、预判方面的东西。
黑盒强迫症的晚期症状是看见现实世界中办事的流程都想用算法知识优化一下,常见的是想着如何优化公司报销和升职的审批流程;再举个反面例子,看《人民的名义》或《官场现形记》时都想着怎么优化贪官和奸商的“办事”流程。
8 收藏强迫症
收藏强迫症的症状是在GitHub上看见好源码必star,技术博客上看到好文章必然收藏,没有收藏功能的个人站也要加入收藏夹。收藏虽多,但不会再看。明知如此,还感觉不收藏就会吃亏。
9 身份强迫症
身份强迫症的早期症状就是头脑中“程序员 == 我自己”的概念根深蒂固,看到和程序员有关的话题都要打开看一下,尽管大多数程序员不会因为应勤是程序员就看《欢乐颂2》,但你打开本文一定是因为本文标题有“程序员”。读完本文的患者还会把自己和同事们作为一个数组,本文中 10 种强迫症作为另一个数组,然后在自己的大脑里做一个递归,查查自己和同事们分别中了几枪。
身份强迫症的晚期症状是把现实世界中见到的一切理解为IT知识,忘记了自己在职场外怎么做一个正常人:走火入魔的患者偶然有一天没有在家写代码,出门看见太阳想到的是“单例模式”,看见双胞胎想到的是“拷贝”,看到摩天轮想到的“循环”,看到排队想到的是“队列”。
身份强迫症进入日薄西山阶段的症状是患者已经无法用人类的语言进行交流了,QQ聊天时每句话的最后都要家一个“;”,没错,是半角的分号;更有甚者还会把脏话用“/*”和“*/”框起来,以为对方就看不见了;看见卖西瓜就只买一个包子的程序员听说学姐留学归来,会四门语言的第一反应是问她那四门语言是Java、PHP、Python和JavaScript还是C、C++、C#和Objective-C。
身份强迫症进入回光返照阶段的情况是试图把别的语言、工具、领域的程序员改造成自己同行的程序员,曾高呼“PHP是最好的语言”的程序员在移动互联网时代改行Android后会纠结怎么把iMac或者Macbook Pro屏幕背面的Apple形状的灯改成Android形状的。
如果你读到最后,不但一枪没中,也没把自己身边的朋友和同事套在这十大强迫症上做个递归,那么你一定不是一个程序员。 收起阅读 »
战狼3剧透!!!
冷锋回到中国后尽管已经恢复了军职,还受到了人民的爱戴,冷锋拥有了以前不可能拥有的荣耀,但是他忘不了的还是龙小云,几年后,他费劲千辛万苦终于得到了龙小云的消息,大家都以为龙小云在几年前被反政府武装的雇佣兵杀死了,令人庆幸的是龙小云被南非的救援中心救了下来。
冷锋的到消息后立马跑去南非找龙小云,可是在欧洲臭名远扬的雇佣兵也知道了这个消息,原来老爹的幕后大咖就是他的父亲飞鱼,飞鱼为了给儿子报仇雪恨竟也来带走龙小云,还出动了大批的先进专备,于是又一轮的世纪大战又开始了。
冷锋在期间困难重重但他还是咬牙坚持下去了,后来冷锋救回龙小云后,他们决定回到北京生活,不久后他们在北京开了互联网公司,还亲自找环信学习即时通讯的集成,生意做得风生水起!从此,过上了幸福的生活!!![鼓掌][鼓掌][鼓掌]冷锋为了感谢环信,还将那个子弹头送给了环信!你也想他一样嘛!?赶紧报名参加环信的Alpha计划培训吧。
环信Alpha计划北京场报名已满,参加的小伙伴请选择上海和深圳场,报名地址环信Alpha计划报名 收起阅读 »
看看30万程序员怎么评论:在网吧写代码是怎样一种体验?
最后再来给程序员提几点建议:
1.写代码好像没试过,不过那个时候做个人网站,家里没有网,写好代码winzip打包,拷软盘里。找网吧前台小妹放软盘(那个网吧只有前台的电脑有软驱)。共享,在我的机器上拷出来,ftp上传到免费空间。周围和我同龄的孩子们基本都是qq 红警 星际之类的。我一直因为不会打游戏也不会去聊天室和妹纸聊天没法和他们融在一起。在所有人的鄙视甚至类似于今天的类似“装逼”等词汇的鄙视中,完成工作。唯一欣慰的是有几个女生看到我的网站会投来些许崇拜的目光(也仅仅是些许)。
2.程序员工作空闲之余也就是逛逛论坛,上上网,聊聊天。下班时间宅在家里,打打游戏,写写代码,写写博客,很少锻炼身体,以至于某天的头条就有可能是某某公司大老猝死了,所以大伙们懂的。 收起阅读 »
2017年的八大顶级开源项目
摘要:本文介绍了在开源界比较有名的八个项目。如果你对其中的某个项目不了解的话,赶快来学习一下吧。以下是译文。原文:Top Open Source Projects In 2017
作者:William Belk
翻译:雁惊寒
今天,让我们一起来看一下2017年开源界的八个顶级玩家。下面列出的几个开源项目反映了开源社区在过去几年来发展的成熟度。这里列出的所有项目(Lab41除外)都是在2014年及以后发布的,每个项目都在各自的社区里发挥着重要的作用。
TensorFlow
Google的TensorFlow发布于2015年,它是一个可扩展的基于神经元的机器学习库。我们可以使用TensorFlow构造流水线来对图像和文本这类东西进行分类,甚至还可以构造出更复杂的问题场景,例如“X类型的用户会买Y吗?”。
许多行业目前对于机器学习的研究或应用还只是流于表面。尽管在我们的意识中一直认为自己可以用AI来实现任何目的,但机器学习还是会受到计算资源和数据训练的限制。在未来的几年里,数据的训练可能依然是大家忽略的问题,许多人低估了能够解决复杂问题所需的可靠训练数据的数量。也就是说,机器学习是为真实场景服务的,并且会很快出现在我们每天使用的很多应用程序之中,隐匿于应用程序的底层。我们还将看到许多有趣的项目和展望,这些来源于机器学习的东西说明了目前还存在着太多的公开数据可供使用。
如果你想了解更多有关TensorFlow的内容,请查阅这篇来自于Google的博文。
Hyperledger
Hyperledger发布于2015年,由Linux基金会赞助,旨在推动区块链技术在未来商业的应用。 Hyperledger开发了模块化的工具,可以作为分布式区块链基础来解决各种商业问题,包括合同安全、匿名账户和身份管理,以及基于社区的历史交易记录。
Hyperledger已经使得IBM、思科、红帽、VMWare,摩根大通、富国银行、埃森哲等公司对其产生了巨大的兴趣。
Node.js / React Native
我们得承认 Node.js 社区的胜利,它现在无处不在。Node.js使得新一代程序员在服务器端编码方面摆脱了束缚。我们在谈论React Native的时候,不能不承认Node.js将继续在软件工程领域保持强劲的势头,特别是对于消费者和移动应用。
React Native于2015年推出,并且许下了一个美好的愿望:只使用一个代码库就能将应用程序部署到多个平台上。例如,使用单个代码库来为苹果iOS、Android和Web编译应用程序。
这为什么是一个诱人的想法呢?对于消费者网站而言,我们可以使用最常用的语言:javascript。我们无需把团队根据不同语言的特点拆分开来,例如javascript、ruby/python/php、java、Objective C。我们可以快速地进行构建。我们可以利用本地设备组件来解决像图像处理这样的“硬骨头”。我们可以只维护单个应用程序,然后将其核心应用分发到每一个需要的平台上。
React Native还有哪些酷炫的地方呢? 应用广泛,就像Facebook、特斯拉、Airbnb、Instagram、腾讯、彭博和Uber一样。
Dolores
Dolores是一套“可定制”、“可私有化部署”的OA办公系统,一套完整的企业通信解决方案,一个完整的企业沟通工具(以下简称企业IM),支持以下几个功能:IM消息服务、组织架构管理、工作流集成。
公司想自己开发一套IM系统应该从哪里开始呢? 企业通讯录怎么保持同步呢? 企业通讯录的权限管理应该怎么做?
三个关于OA办公系统的究极问题,从开源的OA办公项目-Dolores(朵拉)诞生迎刃而解了。Dolores项目遵循Apache Licence 2.0 开源协议,可以直接拿来用,也可以修改代码来满足需要并作为开源或商业产品发布/销售。
Kubernetes
当Google在2014年发布Kubernetes的时候,这个项目的前途看起来很光明。该项目的目标非常远大,试图解决在多个层次、组和角色之间对分布式服务器容器协调的问题。例如,一家公司可能在四个城市的三个环境层(开发、预备、生产)上运行了200多个容器,这管理起来非常头疼。
我们必须要承认,在过去的几年里,虚拟服务器协作在大型企业的复杂部署中占有举足轻重的地位。这是Amazon Web Services目前如此成功的其中一个原因。即使像Docker这种虚拟化的容器部署逐渐兴起,但问题依然存在。公司必须依靠脆弱的开源项目、昂贵的专有平台或者依靠广泛的内部工具来管理虚拟集群和容器。
在大规模的容器协作方面,Kubernetes似乎明显处于领先地位,并与纽约时报、高盛、SoundCloud、Box、Comcast 和 易趣 等用户建立了合作关系。
Lab41
Lab41是一个“挑战实验室”,在那里美国情报界与他们在学术界工业界中的同行一起处理大数据。
虽然Lab41本身并不是一个开源项目,但它提出了一些有趣的问题,进而引出了一些开源代码,并对开源社区做出了一定的贡献。它展示了开源原则、风险投资和政府优先事项的交叉点,这是一个非常独特的东西。
Vault
Vault可以保护、存储和严格控制对现代计算中的令牌、密码、证书、API密钥和其他机密内容的访问。
如果你看看下面这张有关全球数据泄露的交互信息图的话,就能马上理解为什么Vault如此重要了。
凡信
凡信是一个开源的高仿微信项目,截止目前已经更新了3个大版本,从基础的好友聊天做起,到朋友圈、红包功能等功能愈发完善,直播、阅后即焚等新功能层出不穷,整个项目完全免费,Android/ios/服务端所有代码全部开源。由于凡信的1.0和2.0都是基于环信SDK 2.x系列开发,而当前环信官方力推的是3.x的系列SDK,在此背景下,作者决定将凡信迁移至3.x的demo上。迁移的同时,对存储机制和网络接口做了一定的优化。与此同时,针对时下火热的直播APP,结合环信的聊天室功能和ucloud,做了两个模块-观看直播和进行直播;针对IM场景中常见的发红包/抢红包,集成了由环信提供的红包SDK,对于想做红包以及账户管理的开发者,是一种非常值得推荐的解决方案,一是开发者不用头疼于安全问题,以及开发中逻辑不严谨导致的资金转移丢包的问题。 收起阅读 »
春华秋实,环信Android/ios V3.3.4SDK发布,同一账号可在电脑手机间互传消息与文件
春华秋实,听说秋天APP和环信更配!环信发布了V3.3.4版本SDK ,同一账号可在电脑手机间互传消息与文件,并增加消息撤回接口和回调,同时Android端更新了新版环信推送(HMS)。
Android V3.3.4 2017-08-04新功能
- 新增加API请查看链接3.3.4api修改
- 增加接口支持获取历史消息(消息漫游);
- 新增PC与移动端互发消息和文件的功能;
- 增加消息撤回的接口和回调;
- 支持华为新版推送功能(HMS);
- 新增:PC端和手机端登录同一个账号,两个设备之间互发消息;
- 新增:消息漫游,从服务器分页获取历史消息;
- 新增:消息撤回。
- 优化删除一组会话时,回调只返回一次;
- iOS SDK不再支持i386;
- 修复录制音频文件时,音频权限判断。
版本历史:Android SDK更新日志 ios SDK更新日志
下载地址:SDK下载 收起阅读 »
月薪五千和五万销售的区别:一只丑桔引发的大单子(环信真实案例改编)
这是一个初冬的早晨。王向东迈着轻快的步伐,走进了“黄桃园”集团大楼,直奔物业管理公司CEO陶福成办公室。与陶总交换名片后,陶总看着名片,抬头说:“你就是那个什么环信公司的销售经理?你在电话上说有一笔大生意要谈?简单说说吧,我只有十分钟时间。”陶总抬手看了眼手表。
王向东从包里拿出一只丑桔,放到大班台上,说:“这是丑桔,想必陶总吃过。”陶总微微点了下头。“我要和陶总谈的生意与丑桔有关。”陶总好奇地问:“我一个物业公司,怎么会和丑桔生意有关呢?”
“我先问陶总一个经营上的问题。现在由于人工费用上涨很快,物业公司从业主收来的物业费却多年没有做相应的调整,物业公司的利润逐年下滑,甚至出现亏损,不知是不是属实?”陶总点了下头,心里却想你个毛头小子还和我说盈亏,真不知天高地厚。
“所以物业公司不得不想别的办法,拓展收入来源来弥补物业费的亏空。”陶总一笑:“所以你想推荐丑桔生意?”王向东指着台上的丑桔说:“是的!咱们算笔账。陶总物业公司管理着三个高档小区,一共有3万2千住户。”陶总眼睛从半眯状到睁大状。“丑桔是新开发的一个水果品种,口味独特,很受欢迎,超市里卖到24块每公斤。如果能以18块每公斤卖给您的住户,想必一定卖的很好。如果直接和原产地进货,进货价格是10块每公斤,这样的话毛利是8块每公斤。假设有1万5千住户每户购买一箱20公斤,总共30万公斤,毛利240万。”陶总深深点了下头:“240万不少,但对于我这样的物业公司来说,还真不是什么了不起的收入。”
“如果我说丑桔贡献240万,精品东北大米贡献300万,陕西红富士苹果贡献300万。。。。。。这些收入合起来贡献2000万毛利,够不够大?”“够大!但是我要把这个生意做成,需要店面,仓库,运输,配送,押款。。。。。。费用支出多大,你知道吗?”
“知道。但如果我有办法把这些费用降到零呢?”陶总瞪大了眼睛:“什么办法?”“就是利用移动互联技术,构建客服平台,起到一石三鸟作用。”“哪三鸟?”“一是解决咱们物业管理老本行与住户的交流和住户服务请求和相应;二是形成电子商务平台,网上推广产品;三是网上缴费,既交物业费,又是电子商务资金流通道。”
陶总站起来,拉住王向东的手:“快说说,你能帮我建设这个什么客服平台吗?”“可以,环信就是这方面的专家。”
陶总快步走到门口,对秘书说:“马上通知总裁办主任,客服部主管,IT部主管,财务部主管到我这里开会!”
几分钟后,主管们到齐。陶总说:“来,跟大家介绍一下这位小兄弟,王向东,他可是给我们带来了好东西,先听听他的介绍。”王向东站起来谦逊地个跟每个主管打了招呼,才坐下简要地介绍了刚才跟陶总交流的内容。陶总站起来说:“王兄弟带来的方案,揭开了困扰我们好长时间的难题,有了这个客服平台,可以大幅度提高我们的物业服务质量,同时开辟了扩大收入的渠道,是个非常有价值的建议。我要求你们和小王兄弟一起尽快拿出方案,做出预算,在2个月内上线!”
所有主管都响亮地答应下来,同时心里在猜测这位“小王兄弟”后台有多硬,是陶总的什么关系?
没过几天,方案出来了,预算也出来了。一期先建设即时通讯软件平台和客户交互平台,建设费用320万;二期建设智能客服机器人系统,建设费用180万;采用vpc形式,每年支付环信托管费用50万;环信提供战略和业务咨询,每年咨询费40万。
一个由丑桔引起的“大单子”就这么发生了!(由环信真实销售案例改编,文中均为化名) 收起阅读 »
环信移动客服v5.23已发布,支持添加多个不同功能网页插件
摘要:环信移动客服v5.23版本更新,发布了新版网页插件,支持在客服工作台创建多个网页插件,分别设置每个网页插件的功能,并对网页聊天窗口的实际效果进行预览。新版网页插件集成更便捷,只需在页添加一行代码,并支持随时预览网页插件的实际效果。客服模式
客服同事消息提醒
当收到客服同事的消息时,会话页面“客服同事”页签名称旁显示红点,提醒客服有未读消息。
支持在工单页面新建工单
当客户在线咨询的问题需要后续跟进处理而会话已结束时,客服可以在工单页面为客户创建工单,由工单系统的专家继续为客户解答问题。
进入工单页面,点击右上角“新建工单”按钮,填写工单相关信息,并保存。
注:工单为增值服务,需要管理员进入“管理员模式 > 工单 > 申请工单”页面,申请开通工单功能。
管理员模式
新版网页插件
网页插件配置方式升级。支持在客服工作台创建多个网页插件,分别设置每个网页插件的功能,并对网页聊天窗口的实际效果进行预览。
新版网页插件有如下特点:
- 多个网页插件:支持添加多个网页插件,并设置不同的功能,用于不同的网页。
- 极简集成:支持在客服工作台设置网页插件的UI、功能,只需在您的网页添加一行代码即可。
- 效果预览:支持随时预览网页插件的实际效果。
- 兼容性:兼容旧版网页插件的代码集成方式,升级新版后,不影响已有的网页聊天窗口功能。
升级新版网页插件
1. 进入“管理员模式 > 渠道管理 > 网页”,点击右上角“升级新版网页插件”按钮。
2. 了解新版网页插件功能,确认升级至新版网页插件。点击“马上升级”按钮。
注意:升级至新版网页插件后,无法退回至旧版网页插件页面,但原有的配置方式依然生效。
新版网页插件依然支持桌面聊天窗口和H5网页两种方式:
桌面聊天窗口
在“管理员模式 > 渠道管理 > 网页”页面,将网页插件的代码复制并粘贴到您的网站的</body>标签之前,保存并发布。
H5网页
在浏览器地址栏输入以下地址,并将{configId}替换为您的网页插件页面显示的configId的值。
http://kefu.easemob.com/webim/im.html?configId={configId}关于新版网页插件更详细的使用说明,请查看网页渠道集成(新版)
技能组成员管理优化
技能组页面改版,支持根据客服昵称搜索技能组成员,根据客服在线状态筛选技能组成员,以及批量更新技能组成员。
- 搜索:在搜索框中,输入客服昵称或登录邮箱,系统自动显示搜索到的技能组成员;
- 筛选:在成员列表右上方,勾选客服的在线状态(默认全部勾选),系统自动显示处于该状态的技能组成员。
- 批量更新:点击“成员管理”,并点击右上角“代码模式”,进入代码模式。在该页面添加或删除客服的登录邮箱地址(用换行隔开),用于批量更新技能组成员。
欢迎语菜单指定技能组
新增欢迎语菜单指定技能组功能。可以设置欢迎语菜单,并将菜单项与技能组绑定。当客户点击菜单项时,将会话分配给对应技能组。
设置方式:进入“管理员模式 > 设置 > 系统开关”页面,打开“欢迎语菜单指定技能组”开关,添加菜单项,并将菜单项与技能组绑定。
注:暂时仅网页访客端支持显示欢迎语菜单。欢迎语菜单指定技能组功能为入口指定的一种,需要在“设置 > 会话分配规则 > 路由规则”页面,将“入口指定”设置为优先。
网页访客端示例:
通过关键字匹配提醒客服
设置正则表达式用于匹配客户消息中的关键字,当匹配到关键字时,在会话窗口显示预设的消息提醒客服。该功能可用于固定回复的提示、敏感信息的提醒,等等。
设置方式:进入“管理员模式 > 设置 > 关键字匹配”页面,点击“添加关键字匹配规则”,填写规则名称、设置规则条件(正则表达式)和执行动作(在坐席端提示消息,或,在坐席和访客端提示消息),并保存。
- 在坐席端提示消息:在会话窗口显示预设的消息提醒客服,消息仅对客服可见。
- 在坐席端和访客端提示消息:以调度员身份将设定的消息发送给客户,消息对客户和客服可见。
注:关键字匹配功能为增值服务,如需开通,请提供租户ID并联系环信商务经理。
在坐席端提示消息示例:
PC客服工作台
当前版本:V2.1.2017.07030
支持记录历史登录数据
PC客服工作台支持记录历史登录数据。设置保存登录数据后,可以使用历史登录数据快速登录客服系统。
网页插件
当前版本:V47.14.1
支持显示企业欢迎语菜单
网页访客端支持显示企业欢迎语菜单。
管理员在“管理员模式 > 设置 > 系统开关”页面设置“欢迎语菜单指定技能组”功能后,当客户点击欢迎语的菜单项时,会话自动分配给对应技能组。
支持显示满意度评分标签
网页访客端支持显示满意度评分提示和标签。
管理员在“管理员模式 > 设置 > 满意度评价邀请设置”页面设置满意度评分选项后,网页访客端收到的满意度评价邀请显示对应的满意度评分提示和标签。客户选择满意度星级后,需要再次选择标签,才能完成满意度评价。
环信移动客服更新日志http://docs.easemob.com/cs/releasenote/5.23
环信移动客服登陆地址http://kefu.easemob.com/ 收起阅读 »
【环信征文】|两处小改动,解决环信V3.0官方版本关于转发的bug
最近接手了一个集成即时通讯功能的项目,用的是环信的SDK。用环信的接口可以快速实现即时通讯的很多功能。并且对官方demo稍加改动基本能够满足项目需求。真机测试时,发现图片的转发,每次都是转发失败。我开始以为是我集成时有疏漏,逐行检查代码。发现并不是我的问题。从app store下载的官方demo同样是转发失败!!坑我啊!!原因是ContactListSelectViewController这个控制器里无法正确获取到想转发的图片的缓存地址。
修改如下图:
ContactListSelectViewController.m
代码拷走直接用
- (BOOL)messageViewController:(EaseMessageViewController *)viewControllerContactListSelectViewController是取数据,那么存数据要在ChatViewController控制器做存数据的操作。消息类型写死为EMChatTypeChat,是因为,不论是从单聊界面转发,还是从群聊界面转发,都只能转发给个人,所以这里写死,目前没有问题。
didLongPressRowAtIndexPath:(NSIndexPath *)indexPath
{
id object = [self.dataArray objectAtIndex:indexPath.row];
if (![object isKindOfClass:[NSString class]]) {
EaseMessageCell *cell = (EaseMessageCell *)[self.tableView cellForRowAtIndexPath:indexPath];
//////////////////////////解决转发问题的代码///////////////////////////////
EMImageMessageBody *imageBody = (EMImageMessageBody*)[cell.model.message body];
EMMessageBodyType ty = cell.model.bodyType;
if (ty == EMMessageBodyTypeImage) {
NSString *str = cell.model.message == nil ? cell.model.thumbnailFileURLPath : [imageBody localPath];
[[NSUserDefaults standardUserDefaults] setValue:str forKey:@"imgTosand"];
}
/////////////////////////解决转发问题的代码////////////////////////
[cell becomeFirstResponder];
self.menuIndexPath = indexPath;
[self showMenuViewController:cell.bubbleView andIndexPath:indexPath messageType:cell.model.bodyType];
}
return YES;
}
如下图:
ChatViewController.m
代码拷走直接用
#pragma mark - EMUserListViewControllerDelegate上面一定要判断一下消息体类型,只有消息体为图片类型(EMMessageBodyTypeImage)才需要保存图片本地。如果不做判断的话,点击气泡马上崩掉。
- (void)userListViewController:(EaseUsersListViewController *)userListViewController
didSelectUserModel:(id<IUserModel>)userModel
{
if (!self.messageModel) {
return;
}
if (self.messageModel.bodyType == EMMessageBodyTypeText) {
EMMessage *message = [EaseSDKHelper sendTextMessage:self.messageModel.text to:userModel.buddy messageType:EMChatTypeChat messageExt:self.messageModel.message.ext];
__weak typeof(self) weakself = self;
[[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *aError) {
if (!aError) {
// NSMutableArray *array = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]];
UIViewController *chatController = nil;
#ifdef REDPACKET_AVALABLE
chatController = [[RedPacketChatViewController alloc] initWithConversationChatter:userModel.buddy conversationType:EMConversationTypeChat];
#else
chatController = [[ChatViewController alloc]
initWithConversationChatter:userModel.buddy conversationType:EMConversationTypeChat];
#endif
chatController.title = userModel.nickname.length != 0 ? [userModel.nickname copy] : [userModel.buddy copy];
// if ([array count] >= 3) {
// [array removeLastObject];
// [array removeLastObject];
// }
// [array addObject:chatController];
// [weakself.navigationController setViewControllers:array animated:YES];
[weakself.navigationController popViewControllerAnimated:YES];
} else {
[self showHudInView:self.view hint:Localized(@"transpondFail")];
}
}];
} else if (self.messageModel.bodyType == EMMessageBodyTypeImage) {
[self showHudInView:self.view hint:Localized(@"transponding")];
__weak typeof(self) weakSelf = self;
NSString *localPath = [(EMImageMessageBody *)self.messageModel.message.body thumbnailLocalPath];
//////////////////////////解决转发问题的代码////////////////////////////
localPath = [[NSUserDefaults standardUserDefaults] valueForKey:@"imgTosand"];
//////////////////////////解决转发问题的代码//////////////////////////
UIImage *image = [UIImage imageWithContentsOfFile:localPath];
void (^block)() = ^(EMMessage *message){
EMImageMessageBody *imgBody = (EMImageMessageBody *)message.body;
NSString *from = [[EMClient sharedClient] currentUsername];
EMImageMessageBody *newBody = [[EMImageMessageBody alloc] initWithData:nil thumbnailData:[NSData dataWithContentsOfFile:imgBody.thumbnailLocalPath]];
newBody.thumbnailLocalPath = imgBody.thumbnailLocalPath;
newBody.thumbnailRemotePath = imgBody.thumbnailRemotePath;
newBody.remotePath = imgBody.remotePath;
EMMessage *newMsg = [[EMMessage alloc] initWithConversationID:userModel.buddy from:from to:userModel.buddy body:newBody ext:message.ext];
// newMsg.chatType = message.chatType;//此为环信代码
newMsg.chatType = EMChatTypeChat;//这里是我加的
[[EMClient sharedClient].chatManager sendMessage:newMsg progress:nil completion:^(EMMessage *message, EMError *error) {
if (error) {
[weakSelf showHudInView:self.view hint:Localized(@"transpondFail")];
[weakSelf performSelector:@selector(backAction) withObject:nil afterDelay:1];
return ;
}
[(EMImageMessageBody *)message.body setLocalPath:imgBody.localPath];
[[EMClient sharedClient].chatManager updateMessage:message completion:nil];
// NSMutableArray *array = [NSMutableArray arrayWithArray:[weakSelf.navigationController viewControllers]];
#ifdef REDPACKET_AVALABLE
RedPacketChatViewController *chatController = [[RedPacketChatViewController alloc] initWithConversationChatter:userModel.buddy conversationType:EMConversationTypeChat];
#else
ChatViewController *chatController = [[ChatViewController alloc] initWithConversationChatter:userModel.buddy conversationType:EMConversationTypeChat];
#endif
chatController.title = userModel.nickname.length != 0 ? userModel.nickname : userModel.buddy;
// if ([array count] >= 3) {
// [array removeLastObject];
// [array removeLastObject];
// }
// [array addObject:chatController];
// [weakSelf.navigationController setViewControllers:array animated:YES];
[weakSelf.navigationController popViewControllerAnimated:YES];//转发完跳回去
}];
};
if (!image) {
[[EMClient sharedClient].chatManager downloadMessageThumbnail:self.messageModel.message progress:nil completion:^(EMMessage *message, EMError *error) {
if (error) {
[weakSelf showHudInView:self.view hint:Localized(@"transpondFail")];
[weakSelf performSelector:@selector(backAction) withObject:nil afterDelay:1];
return ;
}
block(message);
}];
} else {
block(self.messageModel.message);
}
}
}
个人感觉虽然能解决图片转发的问题,但并不是最好的解决办法,虽然对环信demo的代码改动最少。有更好的办法,欢迎在评论区交流。
(本人github:https://github.com/BHAreslee)(若转载,请告知本人并附上原文链接,谢谢) 收起阅读 »
从不加班的大数据创业公司招聘一个写代码的
随着移动互联网寒冬越来越冷,靠App的情怀已经骗不来融资了,作为互联网连续创业者的本人决定中止全部App开发,战略方向调整为大数据的研究。本人新开办了一家大数据创业公司,我有一个能超越阿里腾讯的创意(不需要市场调查、原型设计、推广方案),就差个写代码的了,要求和待遇如下:
1.转正月薪¥1000W,试用期月薪¥0,试用期视能力而定,从100年到千秋万代不等
2.每周上班8天,每天工作25小时,从不加班,每周少上一天班扣三天工资
3.每个工位配备反人体工学老虎凳
4.辣椒水无限畅饮
5.来自日本的程序员鼓励师穿着制服陪伴工作
。
。
。
。
。
。
。
。
。
。
只不过手里拿着皮鞭和刺刀 收起阅读 »
环信Web IM v1.4.12已发布,支持离线状态发送消息并自动重连
Web IM v1.4.12 2017-07-17新功能:
- [sdk] 修改delivery ack和read ack的格式
- [sdk] 用户在离线状态下发送消息,会自动重连并将未成功发送的消息发送出去
- [sdk] WEBIM支持多设备,添加加入聊天室事件
- [sdk] 给delivered和ack加上from字段
- [demo] 添加Rest Interface的 Test case
- [demo] sdk/demo上传功能兼容ie8
Bug修复:
- [sdk] 提升ie8的兼容性
- [sdk] 自己发送的消息的已读ack,不再发送给自己
- [demo] 新建需要审批的公有群,加入必须有审批流程
- [demo] 鼠标悬浮在群禁言图标上出现提示信息“禁言”
- [demo] demo.html中从cdn引入sdk
- [demo] 修复无法准确统计离线消息数的bug
- [demo] window.history.pushState在windows的chrome上有兼容性问题,统一改成window.location.href
- [demo] window.location.href = xxxx,如果修改的是href.search参数(?a=x&b=y)时候, 如果遇到file方式打开本地index.html会直接跳转页面,造成登录一直不成功,改成修改 href.hash 参数(#a=x&b=y)
- [demo] 将群管理员可操作的项目展示给管理员
webim在线体验:https://webim.easemob.com
版本历史:更新日志
SDK下载:下载地址 收起阅读 »
环信Android/ios V3.3.3 SDK 已发布,支持多设备消息漫游及管理
Android版本 V3.3.3 2017-07-21
新功能
- 新增加API请查看链接3.3.3api修改
- 支持在多个设备登录同一个账号,多个设备间可以同步消息,好友及群组的操作(多设备登录属于增值服务,需要联系商务开通);
- 添加群共享文件的大小属性;
- 增加获取同一账号登录的设备列表的接口,并可以选择踢掉某个设备上的登录;
- 修复分页获取聊天室成员接口无法传入cursor的问题;
- 修复邀请群成员时没有附带信息的bug;
- 修复群组操作时必须获取所有已加入群组的问题;
- 修复附件消息在web IM中右键另存时不能正确显示名字的问题;
- 修复android 共享文件名为中文时显示乱码的问题;
- 修复下载附件路径不存在或者打开错误时仍然下载成功的bug;
- 修复切换账号时某些场景下崩溃的bug;
- 修复获取群成员时最后一页cursor未更新的问题;
- 新增:支持在多个设备登录同一个账号,多个设备间可以同步消息,好友及群组的操作(多设备登录属于增值服务,需要联系商务开通);
- 新增:群共享文件的大小属性;
- 新增:获取同一账号登录的设备列表的接口,并可以选择踢掉某个设备上的登录;
- 修复邀请群成员时没有附带信息的bug;
- 修复群组操作时必须获取所有已加入群组的问题;
- 修复下载附件路径不存在或者打开错误时仍然下载成功的bug;
- 修复切换账号时某些场景下崩溃的bug;
- 修复获取群成员时最后一页cursor未更新的问题;
- 修复调用异步删除好友接口,参数传“YES”不能删除会话。
版本历史:Android SDK更新日志 ios SDK更新日志
下载地址:SDK下载 收起阅读 »