环信

环信

0
评论

【活动推荐】ECUG Con 2018 拥抱下一个十年 ECUG Con 2018 许式伟 ECUG 七牛云

beyond 发表了文章 • 91 次浏览 • 2018-12-03 15:47 • 来自相关话题

国内云计算领域大咖 许式伟
倾情发起的技术盛宴
引领国内云领域风向的高端峰会
ECUG Con 2018
2018 年 12 月 22-23 日 深圳
全新启程!ECUG Con 2018

七牛云 CEO 许式伟

PingCAP CEO 刘奇

七牛云产品副总裁戴文军

Gopher 社区创始人 Asta Xie

阿里巴巴技术专家孙宏亮

《Kubernetes IN ACTION》作者 Marko Lukša

华为云 AI 推理平台&云搜索技术总监胡斐然

七牛云技术总监陈超

阿里云高级开发工程师严明明

京东云区块链实验室与数据库部负责人郭里靖

网易研究院云计算资深架构师朱剑峰

腾讯云高级工程师刘兆瑞

货拉拉数据分析负责人高遥

......
超豪华讲师阵容!

超有料精彩分享!

ECUG 历经十年蜕变

邀您共同开启下个十年

让我们坚持技术情怀,秉承技术精神

开启新的云计算布道篇章!
 
时  间

2018 年 12 月 22-23 日

地  点

深圳市南山区软件产业基地 

更多详情请见下方海报~




扫描上方二维码 ,立即购买早鸟票

与大咖讲师共同探索云计算的下一个十年!
活动详情:了解更多 查看全部
国内云计算领域大咖  许式伟 
倾情发起的技术盛宴
引领国内云领域风向的高端峰会
ECUG Con 2018
2018 年 12 月 22-23 日 深圳
全新启程!
ECUG Con 2018

七牛云 CEO 许式伟

PingCAP CEO 刘奇

七牛云产品副总裁戴文军

Gopher 社区创始人 Asta Xie

阿里巴巴技术专家孙宏亮

《Kubernetes IN ACTION》作者 Marko Lukša

华为云 AI 推理平台&云搜索技术总监胡斐然

七牛云技术总监陈超

阿里云高级开发工程师严明明

京东云区块链实验室与数据库部负责人郭里靖

网易研究院云计算资深架构师朱剑峰

腾讯云高级工程师刘兆瑞

货拉拉数据分析负责人高遥

......
超豪华讲师阵容!

超有料精彩分享!

ECUG 历经十年蜕变

邀您共同开启下个十年

让我们坚持技术情怀,秉承技术精神

开启新的云计算布道篇章!
 
时  间

2018 年 12 月 22-23 日

地  点

深圳市南山区软件产业基地 

更多详情请见下方海报~
30943258454939062.jpg

扫描上方二维码 ,立即购买早鸟票

与大咖讲师共同探索云计算的下一个十年!
活动详情:了解更多
0
评论

【我最喜爱的 Cloud Studio 插件评选大赛】终于开始了! Cloud Studio Cloud Studio 插件评选大赛 腾讯云开发者平台 coding 编程大赛

beyond 发表了文章 • 146 次浏览 • 2018-11-26 15:37 • 来自相关话题

由 环信、腾讯云和 CODING 共同举办的 我最喜爱的 Cloud Studio 插件评选大赛正式开始了!在这场比赛里,将会有技术上的碰撞,大牛评委的专业点评,愉快的技术交流,好玩的插件尝试。





参赛者可以围绕 Git、实用小工具、腾讯云产品对接、UI 强化、语言支持等 14 个主题提交插件,再加上最具娱乐奖,代码最简单奖,设置功能最复杂奖等;近 30 种奖项,超高中奖率;插件只要提交上架,就有 50 元的话费相赠;只要关注 CODING 公众号并转发活动讯息到朋友圈,即可获得手机充值小礼!

参与方式

注册并登陆腾讯云开发者平台(https://dev.tencent.com) -> 点击进入活动页面 -> 点击进行插件的编写与提交(需要选择参与评选的类别)-> 审核无误后即可上架自动参与评选。

赛程时间




 
环信特别奖




基于环信开发一款聊天插件,即有机会获得特别奖,根据作品还将获得环信提供的神秘奖品
更多活动信息,请浏览我们的活动页面。

进入活动页面> 查看全部

2.jpg


由 环信、腾讯云和 CODING 共同举办的 我最喜爱的 Cloud Studio 插件评选大赛正式开始了!在这场比赛里,将会有技术上的碰撞,大牛评委的专业点评,愉快的技术交流,好玩的插件尝试。

6ccda21fgy1fxeim29mncj20ik0e6dn4.jpg

  • 参赛者可以围绕 Git、实用小工具、腾讯云产品对接、UI 强化、语言支持等 14 个主题提交插件,再加上最具娱乐奖,代码最简单奖,设置功能最复杂奖等;
  • 近 30 种奖项,超高中奖率;
  • 插件只要提交上架,就有 50 元的话费相赠;
  • 只要关注 CODING 公众号并转发活动讯息到朋友圈,即可获得手机充值小礼!


参与方式

注册并登陆腾讯云开发者平台https://dev.tencent.com) -> 点击进入活动页面 -> 点击进行插件的编写与提交(需要选择参与评选的类别)-> 审核无误后即可上架自动参与评选。

赛程时间
6ccda21fly1fxejmnr8oej20ow03odfy.jpg

 
环信特别奖
tb16@2x.png

基于环信开发一款聊天插件,即有机会获得特别奖,根据作品还将获得环信提供的神秘奖品
更多活动信息,请浏览我们的活动页面。

进入活动页面>
11
回复

收集基于环信SDK开发的开源项目 开源项目

xiaoyan2015 回复了问题 • 13 人关注 • 11743 次浏览 • 2018-11-21 23:59 • 来自相关话题

4
评论

【开源项目】全国首个开源直播小程序源码 环信公开课 小程序 直播

beyond 发表了文章 • 4077 次浏览 • 2018-07-20 17:30 • 来自相关话题

今天你看直播了吗?拥有10亿微信生态用户的小程序已经成为了继移动互联后的又一个现象级风口,随着微信小程序对外开放实时音视频录制及播放等更多连接能力,小程序与直播强强联合,在各行各业找到了非常多的玩法,小程序直播相比微信直播和APP直播更加简洁、流畅、低延时、多入口等众多优势迅速向商业直播领域及泛娱乐直播领域蔓延。从小游戏、内容付费、工具、大数据、社交电商创业者到传统品牌商们,都在努力搭上小程序直播这辆快车,以免错过微信生态里新的流量洼地。
 





作为一名环信生态圈资深开发者,本着对技术的热衷,对环信的眷恋和对党的忠诚,基于环信即时通讯云写了“直播购物小程序”,目前项目源码已全部免费开放,希望对有需求的企业和开发者提供一个思路和参考。
直播购物小程序源码github地址:https://github.com/YuTongNetworkTechnology/wechat_live/tree/master 
git打不开可直接点下面链接下载


小程序直播demo_2018-06-21.zip







直播购物小程序运行预览图 
 
小程序体验指南(仅需两步):
 
1、下载微信小程序开发工具,下载地址:https://developers.weixin.qq.c ... .html 
 




2、导入源码:将附件的源码解压直接导入 







环信小程序直播技术文档
一、 使用的技术
1、 环信IM直播室。
2、 微信小程序实时音视频播放组件live-player。
3、 推流软件(obs、易推流)等推流。
4、 视频流服务器(UCLOUD、七牛、腾讯)等视频流服务器。
二、 系统使用流程。
1、 视频推流软件将视频流推到流服务器。
2、 打开视频直播demo小程序注册环信账号。
3、 进入软件直播室进行测试。
三、 技术流程及使用的SDk
1、 注册环信账号
打开https://www.easemob.com/ 环信官网,点击右上角注册按钮,选择[注册即时通讯云]




填写对相关信息进行注册





注册成功后进行登录




注:新注册用户需进行账号的认证。
2、 直播应用创建
登录成功点击应用列表选择创建应用




输入应用名称等信息
 





创建成功后点击应用进入





需要注意的是应用的OrgName 和AppName这两个是以后都需要用到的两个参数变量




3、 直播创建
1)在创建直播之前需要对应用进行设置首先需要设置应用的直播流地址
第一步获取应用管理员的Tokencurl -X POST "https://a1.easemob.com/[应用OrgName]/[应用AppName]/token" -d '{"grant_type":"client_credentials","client_id":"[应用client_id]","client_secret":"[应用] client_secret"}'返回格式{
"access_token":"YWMtWY779DgJEeS2h9OR7fw4QgAAAUmO4Qukwd9cfJSpkWHiOa7MCSk0MrkVIco",
"expires_in":5184000,
"application":"c03b3e30-046a-11e4-8ed1-5701cdaaa0e4"












第二步设置直播流地址curl -X POST -H "Authorization: Bearer [管理员Token]" " https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms/stream_url -d '{"pc_pull":"[pc拉流地址]","pc_push":"[pc推流地址]","mobile_pull":"[手机拉流地址]","mobile_push":"[手机推流地址]"}'"成功返回格式:{
"action": "post",
"application": "e1a09de0-0e03-11e7-ad8e-a1d913615409",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"pc_pull": true,
"mobile_push": true,
"mobile_pull": true,
"pc_push": true
},
"timestamp": 1494084474885,
"duration": 1,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












2)创建主播
点击IM用户





点击注册IM用户





填写用户信息





创建用户的过程同样也可以通过REST API形式进行curl -X POST -i " https://a1.easemob.com/[应用OrgName]/[应用AppName]/users" -d '{"username":"[用户名]","password":"[密码]"}'
注:应用必须为开放注册





将注册的用户添加为主播curl -X POST -H "Authorization: [管理员Token]" https://a1.easemob.com/[应用OrgName]/[应用AppName]/super_admin -d'{"superadmin":"[IM用户名]"}'返回结果示例:{
"action": "post",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"result": "success"
},
"timestamp": 1496236798886,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












3)创建直播
点击直播





点击新建房间





填写房间信息




创建房间同时也可以使用REST API形式进行详情可以查看http://docs.easemob.com/im/live/server-integration环信官方文档。
4、 小程序demo集成使用
小程序直播购物demo集成官方WebIM SDK详情请查看https://github.com/easemob/webim-weixin-xcx
Demo具体配置如下
打开demo 下sdk配置文件





修改appkey为自己应用的appkey





打开pages/live/index.js修改房间默认拉流地址及直播间房间号





四、 扩展说明
Demo中房间为固定测试房间,实际使用中应获取环信直播的房间信息及房间列表。具体如下:
获取直播间列表:curl -X GET -H "Authorization: Bearer [用户Token]" https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms?ongoing=true&limit=[获取数量]&cursor=[游标地址(不填写为充开始查询)]
响应:{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"params": {
"cursor": [
"ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6MzE"
],
"ongoing": [
"true"
],
"limit": [
"2"
]
},
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": [
{
"id": "1924",
"chatroom_id": "17177265635330",
"title": "具体了",
"desc": "就咯",
"startTime": 1495779917352,
"endTime": 1495779917352,
"anchor": "wuls",
"gift_count": 0,
"praise_count": 0,
"current_user_count": 8,
"max_user_count": 9,
"status": "ongoing",
"cover_picture_url": "",
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1"
},
{
"id": "1922",
"chatroom_id": "17175003856897",
"title": "香山",
"desc": "随便",
"startTime": 1495777760957,
"endTime": 1495777760957,
"anchor": "sx001",
"gift_count": 0,
"praise_count": 8,
"current_user_count": 1,
"max_user_count": 3,
"status": "ongoing",
"cover_picture_url": "http://127.0.0.1:8080/easemob- ... ot%3B,
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1"
}
],
"timestamp": 1496303336669,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"cursor": "ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6NDk",
"count": 2
}












获取直播间详情:curl -X GET -H "Authorization: Bearer [用户Token]" " https://a1.easemob.com/[应用OrgName]/[应用AppName]/[房间id]/status"响应:{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"liveRoomID": "1946",
"status": "ongoing"
},
"timestamp": 1496234759930,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"count": 0
}














 
使用环信直播购物小程序遇到任何问题欢迎跟帖讨论。 查看全部
今天你看直播了吗?
拥有10亿微信生态用户的小程序已经成为了继移动互联后的又一个现象级风口,随着微信小程序对外开放实时音视频录制及播放等更多连接能力,小程序与直播强强联合,在各行各业找到了非常多的玩法,小程序直播相比微信直播和APP直播更加简洁、流畅、低延时、多入口等众多优势迅速向商业直播领域及泛娱乐直播领域蔓延。从小游戏、内容付费、工具、大数据、社交电商创业者到传统品牌商们,都在努力搭上小程序直播这辆快车,以免错过微信生态里新的流量洼地。
 
微信图片_20180725162426.jpg


作为一名环信生态圈资深开发者,本着对技术的热衷,对环信的眷恋和对党的忠诚,基于环信即时通讯云写了“直播购物小程序”,目前项目源码已全部免费开放,希望对有需求的企业和开发者提供一个思路和参考。
直播购物小程序源码github地址:https://github.com/YuTongNetworkTechnology/wechat_live/tree/master 
git打不开可直接点下面链接下载



预览图.jpg

直播购物小程序运行预览图 
 
小程序体验指南(仅需两步):
 
1、下载微信小程序开发工具,下载地址:https://developers.weixin.qq.c ... .html 
 
Catch9A07(07-20-17-38-30).jpg

2、导入源码:将附件的源码解压直接导入 


Catch1C69(07-20-17-38-30).jpg


环信小程序直播技术文档
一、 使用的技术
1、 环信IM直播室。
2、 微信小程序实时音视频播放组件live-player。
3、 推流软件(obs、易推流)等推流。
4、 视频流服务器(UCLOUD、七牛、腾讯)等视频流服务器。
二、 系统使用流程。
1、 视频推流软件将视频流推到流服务器。
2、 打开视频直播demo小程序注册环信账号。
3、 进入软件直播室进行测试。
三、 技术流程及使用的SDk
1、 注册环信账号
打开https://www.easemob.com/ 环信官网,点击右上角注册按钮,选择[注册即时通讯云]
1.png

填写对相关信息进行注册

2.png

注册成功后进行登录
3.png

注:新注册用户需进行账号的认证。
2、 直播应用创建
登录成功点击应用列表选择创建应用
4.png

输入应用名称等信息
 

5.png

创建成功后点击应用进入

6.png

需要注意的是应用的OrgName 和AppName这两个是以后都需要用到的两个参数变量
7.png

3、 直播创建
1)在创建直播之前需要对应用进行设置首先需要设置应用的直播流地址
第一步获取应用管理员的Token
curl -X POST "https://a1.easemob.com/[应用OrgName]/[应用AppName]/token" -d '{"grant_type":"client_credentials","client_id":"[应用client_id]","client_secret":"[应用] client_secret"}'
返回格式
{
"access_token":"YWMtWY779DgJEeS2h9OR7fw4QgAAAUmO4Qukwd9cfJSpkWHiOa7MCSk0MrkVIco",
"expires_in":5184000,
"application":"c03b3e30-046a-11e4-8ed1-5701cdaaa0e4"












第二步设置直播流地址
curl -X POST -H "Authorization: Bearer [管理员Token]"  " https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms/stream_url -d '{"pc_pull":"[pc拉流地址]","pc_push":"[pc推流地址]","mobile_pull":"[手机拉流地址]","mobile_push":"[手机推流地址]"}'"
成功返回格式:
{
"action": "post",
"application": "e1a09de0-0e03-11e7-ad8e-a1d913615409",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"pc_pull": true,
"mobile_push": true,
"mobile_pull": true,
"pc_push": true
},
"timestamp": 1494084474885,
"duration": 1,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












2)创建主播
点击IM用户

8.png

点击注册IM用户

9.png

填写用户信息

10.png

创建用户的过程同样也可以通过REST API形式进行
curl -X POST -i " https://a1.easemob.com/[应用OrgName]/[应用AppName]/users" -d '{"username":"[用户名]","password":"[密码]"}'

注:应用必须为开放注册

11.png

将注册的用户添加为主播
curl -X POST -H "Authorization: [管理员Token]"  https://a1.easemob.com/[应用OrgName]/[应用AppName]/super_admin -d'{"superadmin":"[IM用户名]"}'
返回结果示例:
{
"action": "post",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"result": "success"
},
"timestamp": 1496236798886,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












3)创建直播
点击直播

12.png

点击新建房间

13.png

填写房间信息
14.png

创建房间同时也可以使用REST API形式进行详情可以查看http://docs.easemob.com/im/live/server-integration环信官方文档。
4、 小程序demo集成使用
小程序直播购物demo集成官方WebIM SDK详情请查看https://github.com/easemob/webim-weixin-xcx
Demo具体配置如下
打开demo 下sdk配置文件

15.png

修改appkey为自己应用的appkey

16.png

打开pages/live/index.js修改房间默认拉流地址及直播间房间号

17.png

四、 扩展说明
Demo中房间为固定测试房间,实际使用中应获取环信直播的房间信息及房间列表。具体如下:
获取直播间列表:
curl -X GET -H "Authorization: Bearer  [用户Token]"  https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms?ongoing=true&limit=[获取数量]&cursor=[游标地址(不填写为充开始查询)]

响应:
{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"params": {
"cursor": [
"ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6MzE"
],
"ongoing": [
"true"
],
"limit": [
"2"
]
},
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": [
{
"id": "1924",
"chatroom_id": "17177265635330",
"title": "具体了",
"desc": "就咯",
"startTime": 1495779917352,
"endTime": 1495779917352,
"anchor": "wuls",
"gift_count": 0,
"praise_count": 0,
"current_user_count": 8,
"max_user_count": 9,
"status": "ongoing",
"cover_picture_url": "",
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1"
},
{
"id": "1922",
"chatroom_id": "17175003856897",
"title": "香山",
"desc": "随便",
"startTime": 1495777760957,
"endTime": 1495777760957,
"anchor": "sx001",
"gift_count": 0,
"praise_count": 8,
"current_user_count": 1,
"max_user_count": 3,
"status": "ongoing",
"cover_picture_url": "http://127.0.0.1:8080/easemob- ... ot%3B,
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1"
}
],
"timestamp": 1496303336669,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"cursor": "ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6NDk",
"count": 2
}












获取直播间详情:
curl -X GET -H "Authorization: Bearer [用户Token]" " https://a1.easemob.com/[应用OrgName]/[应用AppName]/[房间id]/status"
响应:
{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"liveRoomID": "1946",
"status": "ongoing"
},
"timestamp": 1496234759930,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"count": 0
}














 
使用环信直播购物小程序遇到任何问题欢迎跟帖讨论。
19
评论

【新手快速入门】集成环信常见问题+解决方案汇总 常见问题

dujiepeng 发表了文章 • 18374 次浏览 • 2017-05-22 15:51 • 来自相关话题

   这里整理了集成环信的常见问题和一些功能的实现思路,希望能帮助到大家。感谢热心的开发者贡献,大家在观看过程中有不明白的地方欢迎直接跟帖咨询。
 
ios篇
APNs证书创建和上传到环信后台头像昵称的简述和处理方案音视频离线推送Demo实现环信服务器聊天记录保存多久?离线收不到好友请求IOS中环信聊天窗口如何实现文件发送和预览的功能ios集成常见问题环信推送的一些常见问题实现名片|红包|话题聊天室等自定义cell
 
Android篇
Android sdk 的两种导入方式环信3.0SDK集成小米推送教程EaseUI库中V4、v7包冲突解决方案Android EaseUI里的百度地图替换为高德地图android扩展消息(名片集成)关于会话列表的置顶聊天java.lang.UnsatisfiedLinkError: 的问题android 端 app 后台被杀死收不到消息的解决方案
昵称头像篇
android中如何显示开发者服务器上的昵称和头像 Android中显示头像(接上一篇文章看)环信(Android)设置头像和昵称的方法(最简单暴力的基于环信demo的集成)IOS中如何显示开发者服务器上的昵称和头像【环信公开课第12期视频回放】-所有关于环信IM昵称头像的问题听这课就够了
 
直播篇
一言不合你就搞个直播APP
 
客服集成
IM-SDK和客服SDK并存开发指南—Android篇IM-SDK和客服SDK并存开发指南—iOS篇
 
开源项目
Android简版demoios简版demo凡信2.0:超仿微信的开源项目 凡信3.0:携直播和红包而来高仿微信:Github 3,515 Star方圆十里:环信编程大赛冠军项目泛聊:定一个小目标写一个QQSlack聊天机器人:一天时间做一个聊天机器人TV视频通话:在电视上视频通话视频通话:Android手机视频通话酷信:ios高仿微信公众号助手:与订阅用户聊天沟通
 
持续更新ing...小伙伴们还有什么想知道欢迎跟帖提出。
  查看全部
   这里整理了集成环信的常见问题和一些功能的实现思路,希望能帮助到大家。感谢热心的开发者贡献,大家在观看过程中有不明白的地方欢迎直接跟帖咨询。
 
ios篇

 
Android篇

昵称头像篇

 
直播篇
  1. 一言不合你就搞个直播APP

 
客服集成
  1. IM-SDK和客服SDK并存开发指南—Android篇
  2. IM-SDK和客服SDK并存开发指南—iOS篇

 
开源项目

 
持续更新ing...小伙伴们还有什么想知道欢迎跟帖提出。
 
0
评论

0 元福利手慢无 | 年尾盛会——2018 · 支付学院年会环信用户免费报名 活动推荐 环信 ping++

beyond 发表了文章 • 97 次浏览 • 2018-11-27 15:13 • 来自相关话题

文能提笔抒骚情
武能切图画交互





 作为一个产品经理

学习不是忙里偷闲的充电

而是写进岗位职责里的日日功

公司一步步发展,业务一步步扩张
 
 支付 

一个熟悉又陌生的词映入眼帘
从 2014 年起,Ping++ 用 4 年的沉淀积累,化繁为简,实现「 7 行代码接入支付」的聚合支付、会员账户系统、多级商户系统等产品,首次提出「聚合支付」,在聚合支付领域树立标杆、建立规则。曾经踩过的无数坑,都成为了支付这一领域内宝贵的经验。所以说,不如为所有的产品经理们办一个「支付学院」吧!就这样,支付学院第一期款款而来。





「你们应该继续办下去啊!支持你们!」
「这次真的收获满满,老师讲得我还要再捋捋,太多了一下吸收不了。」
「可以私底下给秋秋老师打 Call 吗?请替我表白!」
「PPT 我打印出来学习,你们下次别用黑底白字了,打印起来反白很麻烦。」
「……」




受宠若惊,十分惶恐。因此,领域即便如此狭窄,架构即便大同小异,也要像宰相的女儿山鲁佐德一样,奉上个个迥异的故事,直到第一千零一夜。















于是就又举办了第二期、第三期,以及现在如约而至的 2018 年会。




❤ 作为一名严肃活泼认真可爱的支付从业者,你一定知道支付的前提是合规,监管即是这开头的 1 ;而后作为一个产品商业化的核心,支付系统与交易系统应为业务敞开怀抱,随着需求的变化而迭代以支撑业务十倍百倍的增长,0 是谦虚也是包容;在当今经济下行的处境下,很多企业为了寻求进一步的发展,纷纷选择了出海,去海外寻求新的增长点,因此跨境就像尾部的 1,代表了新的起点和开始。

❤ 1001 个支付故事,其实也是 4 个支付故事。2018 支付学院年会来为大家讲解关于交易系统、支付系统、监管和跨境支付的故事。
 
年会不同以往的是,大家热热闹闹开开心心相聚才是最重要的,因此这次人数应该远超以往,如果想要 0 元听老师讲课,那你就需要手快一些了。

0 元票兑换码
feqylt1
 
有道是,相逢即是有缘,有缘自会相逢。

我觉得我们已经很有缘了,故事也有了,来年会一起聊聊吧。
 
活动详情:免费报名 查看全部
文能提笔抒骚情
武能切图画交互


微信图片_20181127145045.jpg

 作为一个产品经理

学习不是忙里偷闲的充电

而是写进岗位职责里的日日功

公司一步步发展,业务一步步扩张
 
 支付 

一个熟悉又陌生的词映入眼帘
从 2014 年起,Ping++ 用 4 年的沉淀积累,化繁为简,实现「 7 行代码接入支付」的聚合支付、会员账户系统、多级商户系统等产品,首次提出「聚合支付」,在聚合支付领域树立标杆、建立规则。曾经踩过的无数坑,都成为了支付这一领域内宝贵的经验。所以说,不如为所有的产品经理们办一个「支付学院」吧!就这样,支付学院第一期款款而来。

微信图片_20181127151035.jpg

「你们应该继续办下去啊!支持你们!」
「这次真的收获满满,老师讲得我还要再捋捋,太多了一下吸收不了。」
「可以私底下给秋秋老师打 Call 吗?请替我表白!」
「PPT 我打印出来学习,你们下次别用黑底白字了,打印起来反白很麻烦。」
「……」
微信图片_20181127151054.jpg

受宠若惊,十分惶恐。因此,领域即便如此狭窄,架构即便大同小异,也要像宰相的女儿山鲁佐德一样,奉上个个迥异的故事,直到第一千零一夜。

微信图片_20181127151125.jpg


微信图片_20181127151137.jpg


微信图片_20181127151148.jpg

于是就又举办了第二期、第三期,以及现在如约而至的 2018 年会。
微信图片_20181127151202.jpg

❤ 作为一名严肃活泼认真可爱的支付从业者,你一定知道支付的前提是合规,监管即是这开头的 1 ;而后作为一个产品商业化的核心,支付系统与交易系统应为业务敞开怀抱,随着需求的变化而迭代以支撑业务十倍百倍的增长,0 是谦虚也是包容;在当今经济下行的处境下,很多企业为了寻求进一步的发展,纷纷选择了出海,去海外寻求新的增长点,因此跨境就像尾部的 1,代表了新的起点和开始。

❤ 1001 个支付故事,其实也是 4 个支付故事。2018 支付学院年会来为大家讲解关于交易系统、支付系统、监管和跨境支付的故事。
 
年会不同以往的是,大家热热闹闹开开心心相聚才是最重要的,因此这次人数应该远超以往,如果想要 0 元听老师讲课,那你就需要手快一些了。

0 元票兑换码
feqylt1

 
有道是,相逢即是有缘,有缘自会相逢。

我觉得我们已经很有缘了,故事也有了,来年会一起聊聊吧。
 
活动详情:免费报名
2
评论

NIUDAY 11.23 北京站 |环信CEO刘俊彦现场讲述人工智能赋能客户互动之现状与未来 刘俊彦 人工智能 环信 七牛云

beyond 发表了文章 • 145 次浏览 • 2018-11-15 16:36 • 来自相关话题

2018 年是见证「奇迹」的一年。AI 从多年的热门话题中开始走下神坛,逐渐深入到了各个行业,加速经济结构优化及行业智慧化升级,AI 已不再是难以企及的神话而是可触摸的美好未来。 政策支持加上资本推动,无论是从新兴行业还是传统行业都出现了人工智能方面的布局者和佼佼者,智慧教育、移动社交、智能语音、智慧客服、传统媒体等行业都在突破技术上和流程上的难点和困惑。

11 月 23 日,一场由七牛云主办主题为「AI 产业技术的渗透与融合」的 NIUDAY 小牛汇共享日将在北京举行。会上,将邀请众多行业内知名企业及技术专家,针对当前 AI 在技术上以及行业中遇到的一些壁垒问题,进行深入探讨和分享。

智慧教育、移动未来,体验指尖上的 AI

在此次活动中,除行业专家的视点剖析之外,对于 AI 与行业的渗透与融合度是理论大于实践亦或是理论与实践已完美结合,已经应用的行业代表案例有哪些?对于这些问题,大家可以在此次活动中得以解惑。




刘俊彦
手机电商、手机软件系统的快速更迭让在线客服、移动客服有了更大的发展空间,成了市场中的一片蓝海,究竟现状如何、客户体验的真实反馈是什么?环信 CEO 刘俊彦先生带来的《人工智能赋能客户互动之现状与未来》让你更贴近生活,更能体会 AI 的无处不在。




谢华亮

科技发展教育先行,技术与教育的结合又将碰撞出怎样的火花,会上,将有好未来 SEG 智慧教育事业部技术总监谢华亮带来主题为《AI 在教育行业中的应用》的精彩演讲。




佘超杰

移动互联网的发展已影响到我们身边的每一个人,游戏、娱乐、社交等手机平台的火爆更是带来了巨大的信息流量。但如何应对这些突然爆发的信息流,如何让产品与技术更好地去结合以吸引更多的受众人群,成为人们关注的话题。以作为专注于移动互联网社交的知名企业 Blued 为例,实践与技术并重的技术专家佘超杰将分享给我们《AI 在 Blued 上的应用》。
                
连线行业专家,洞悉专业视点

人工智能技术在飞速发展过程中得到了国家以及政府的极大关注与大力支持,中国人工智能产业发展联盟作为国家发展改革委、科学技术部、工业和信息化部、中央网信办四部委共同指导下的人工智能产业权威联盟机构,也将加入到此次 NIUDAY 小牛汇共享日活动中来。





孙明俊

中国信息通信研究院人工智能部副主任,中国人工智能产业发展联盟总体组组长、数据中心联盟秘书长孙明俊女士将出席本次活动,并将从行业专家的角度带来主题为《人工智能产业发展水平分析》的演讲,向大家解析产业发展水平、分享行业利好政策等。

战略签约中国网 传统与创新的再突破





杨新华

值得一提的是,本次 NIUDAY 小牛汇共享日活动上七牛云将与中国互联网新闻中心举行战略合作签约仪式。届时,中国互联网新闻中心·中国网副总编辑杨新华先生将带来《AI 如何讲好中国故事》的演讲,介绍七牛云在未来媒体平台构建中发挥的作用,以及正处于变革中的媒体行业对 AI 的思考。

当然作为本次 NIUDAY 小牛汇活动的主办方,七牛云也准备了满满的干货带给大家。七牛云技术总监陈超《数据智能时代的智慧工厂实践》、七牛云人工智能实验室资深产品经理杨叶青《一站式审核助力无忧运营》带你体会七牛云两大重要产品线的技术与发展。

更多大咖嘉宾,请往下看~ 





关于环信机器人:

环信机器人已经在中通快递、新东方、天津农商行、宜家、环球捕手等头部企业的“双十一”中发挥着中流砥柱的作用,机器人可以帮助解决80%以上的常见问题,在售后环节能替代超90%的人工,轻松实现7*24无间断客户服务,AI从此让我们的客服人员告别苦逼,云淡风轻,笑对各种节假日促销、狂欢节。

目前,环信机器人已经广泛服务于包括保险、证券、银行、教育、物流、商旅、电商、汽车等行业的数万客户,日机器人会话超千万条。
活动报名地址:http://www.huodongxing.com/event/2464773427600 查看全部

2018 年是见证「奇迹」的一年。AI 从多年的热门话题中开始走下神坛,逐渐深入到了各个行业,加速经济结构优化及行业智慧化升级,AI 已不再是难以企及的神话而是可触摸的美好未来。 政策支持加上资本推动,无论是从新兴行业还是传统行业都出现了人工智能方面的布局者和佼佼者,智慧教育、移动社交、智能语音、智慧客服、传统媒体等行业都在突破技术上和流程上的难点和困惑。



11 月 23 日,一场由七牛云主办主题为「AI 产业技术的渗透与融合」的 NIUDAY 小牛汇共享日将在北京举行。会上,将邀请众多行业内知名企业及技术专家,针对当前 AI 在技术上以及行业中遇到的一些壁垒问题,进行深入探讨和分享。

智慧教育、移动未来,体验指尖上的 AI

在此次活动中,除行业专家的视点剖析之外,对于 AI 与行业的渗透与融合度是理论大于实践亦或是理论与实践已完美结合,已经应用的行业代表案例有哪些?对于这些问题,大家可以在此次活动中得以解惑。

微信图片_20181115162453.jpg

刘俊彦


手机电商、手机软件系统的快速更迭让在线客服、移动客服有了更大的发展空间,成了市场中的一片蓝海,究竟现状如何、客户体验的真实反馈是什么?环信 CEO 刘俊彦先生带来的《人工智能赋能客户互动之现状与未来》让你更贴近生活,更能体会 AI 的无处不在。

微信图片_20181115162531.jpg

谢华亮



科技发展教育先行,技术与教育的结合又将碰撞出怎样的火花,会上,将有好未来 SEG 智慧教育事业部技术总监谢华亮带来主题为《AI 在教育行业中的应用》的精彩演讲。

微信图片_20181115162544.jpg

佘超杰



移动互联网的发展已影响到我们身边的每一个人,游戏、娱乐、社交等手机平台的火爆更是带来了巨大的信息流量。但如何应对这些突然爆发的信息流,如何让产品与技术更好地去结合以吸引更多的受众人群,成为人们关注的话题。以作为专注于移动互联网社交的知名企业 Blued 为例,实践与技术并重的技术专家佘超杰将分享给我们《AI 在 Blued 上的应用》。
                
连线行业专家,洞悉专业视点

人工智能技术在飞速发展过程中得到了国家以及政府的极大关注与大力支持,中国人工智能产业发展联盟作为国家发展改革委、科学技术部、工业和信息化部、中央网信办四部委共同指导下的人工智能产业权威联盟机构,也将加入到此次 NIUDAY 小牛汇共享日活动中来。

微信图片_20181115162600.jpg


孙明俊



中国信息通信研究院人工智能部副主任,中国人工智能产业发展联盟总体组组长、数据中心联盟秘书长孙明俊女士将出席本次活动,并将从行业专家的角度带来主题为《人工智能产业发展水平分析》的演讲,向大家解析产业发展水平、分享行业利好政策等。

战略签约中国网 传统与创新的再突破

微信图片_20181115162615.jpg


杨新华



值得一提的是,本次 NIUDAY 小牛汇共享日活动上七牛云将与中国互联网新闻中心举行战略合作签约仪式。届时,中国互联网新闻中心·中国网副总编辑杨新华先生将带来《AI 如何讲好中国故事》的演讲,介绍七牛云在未来媒体平台构建中发挥的作用,以及正处于变革中的媒体行业对 AI 的思考。

当然作为本次 NIUDAY 小牛汇活动的主办方,七牛云也准备了满满的干货带给大家。七牛云技术总监陈超《数据智能时代的智慧工厂实践》、七牛云人工智能实验室资深产品经理杨叶青《一站式审核助力无忧运营》带你体会七牛云两大重要产品线的技术与发展。

更多大咖嘉宾,请往下看~ 

5bed2dcd27fe6.jpg

关于环信机器人:

环信机器人已经在中通快递、新东方、天津农商行、宜家、环球捕手等头部企业的“双十一”中发挥着中流砥柱的作用,机器人可以帮助解决80%以上的常见问题,在售后环节能替代超90%的人工,轻松实现7*24无间断客户服务,AI从此让我们的客服人员告别苦逼,云淡风轻,笑对各种节假日促销、狂欢节。

目前,环信机器人已经广泛服务于包括保险、证券、银行、教育、物流、商旅、电商、汽车等行业的数万客户,日机器人会话超千万条。
活动报名地址:http://www.huodongxing.com/event/2464773427600
0
回复

Android studio导入easeui运行编译报错 Android 环信

回复

₁₉₉₃₀₄₀₇の陳小垚 发起了问题 • 1 人关注 • 453 次浏览 • 2018-09-27 22:07 • 来自相关话题

1
回复

导出聊天记录报错:Array ( [error] => apiname is invalid ) 环信集成 环信

kaibisikai 回复了问题 • 2 人关注 • 1083 次浏览 • 2018-09-25 10:37 • 来自相关话题

2
回复

群成员主动退出,但是群里面获取所有成员还是能获取到已经退出的成员 环信

孩子气 Rc 回复了问题 • 3 人关注 • 2091 次浏览 • 2018-08-09 15:09 • 来自相关话题

4
回复

牛逼啊,这么大个环信连做到头像和昵称保存的方法都没有 环信

陈日明 回复了问题 • 2 人关注 • 577 次浏览 • 2018-08-08 10:49 • 来自相关话题

1
回复

OC_SDK集成参考视频 建议 环信 iOS

beyond 回复了问题 • 2 人关注 • 418 次浏览 • 2018-07-26 10:48 • 来自相关话题

2
回复

iOS pod集成后点击进入单聊界面崩溃 并提示libc++abi.dylib: terminating with uncaught exception of type NSException 环信 iOS

KevinGong 回复了问题 • 2 人关注 • 609 次浏览 • 2018-06-27 18:51 • 来自相关话题

1
回复

都添加哪些库,视频里看不清啊? 环信 iOS

KevinGong 回复了问题 • 2 人关注 • 467 次浏览 • 2018-06-05 11:52 • 来自相关话题

0
评论

环信Rest java sdk吐槽+你想怎么写? 环信

环信沈冲 发表了文章 • 546 次浏览 • 2018-05-22 00:50 • 来自相关话题

先附上java sdk以及示例代码的GitHub地址:
https://github.com/easemob/emchat-server-examples/tree/master/emchat-server-java
 
相信各位服务端的朋友都已经瞅过了,最后是否使用了这个sdk呢?如果没有使用,为什么不使用呢?你..你...你能不能告诉我为什么??尽情的喷我吧,告诉我该怎么写,我改还不行吗..
 
先行感谢各位诚恳的意见和建议,期望得到您的回复。 查看全部
先附上java sdk以及示例代码的GitHub地址:
https://github.com/easemob/emchat-server-examples/tree/master/emchat-server-java
 
相信各位服务端的朋友都已经瞅过了,最后是否使用了这个sdk呢?如果没有使用,为什么不使用呢?你..你...你能不能告诉我为什么??尽情的喷我吧,告诉我该怎么写,我改还不行吗..
 
先行感谢各位诚恳的意见和建议,期望得到您的回复。
1
回复

Could not successfully update network info during initialization这是什么原因啊? 环信 iOS

驱马历长洲 回复了问题 • 2 人关注 • 5211 次浏览 • 2018-04-29 15:05 • 来自相关话题

0
回复

你们用的环信ios 稳定吗? 环信 环信_iOS

回复

tianwaifeixian 发起了问题 • 1 人关注 • 637 次浏览 • 2018-04-25 15:56 • 来自相关话题

0
评论

基于环信的仿QQ即时通讯的简单实现 QQ 环信

beyond 发表了文章 • 837 次浏览 • 2018-03-08 16:01 • 来自相关话题

概述
 
今天看了环信的API,就利用下午的时间动手试了试,然后做了一个小Demo。详细

我的博客地址

之前一直想实现聊天的功能,但是感觉有点困难,今天看了环信的API,就利用下午的时间动手试了试,然后做了一个小Demo。
因为没有刻意去做聊天软件,花的时间也不多,然后界面就很简单,都是一些基本知识,如果觉得功能简单,可以自行添加,我这就不多介绍了。

照例先来一波动态演示:




 
功能很简单,注册用户 —> 用户登录 —> 选择聊天对象 —> 开始聊天

使用到的知识点:
RecyclerViewCardView环信的API的简单使用

依赖的库
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.android.support:cardview-v7:24.1.1'
compile 'com.android.support:recyclerview-v7:24.0.0' 1、聊天页面

首先是看了郭神的《第二行代码》做了聊天界面,用的是RecyclerView

a. 消息类的封装
public class MSG {
public static final int TYPE_RECEIVED = 0;//消息的类型:接收
public static final int TYPE_SEND = 1; //消息的类型:发送
private String content;//消息的内容
private int type; //消息的类型
public MSG(String content, int type) {
this.content = content;
this.type = type;
}
public String getContent() {
return content;
}
public int getType() {
return type;
}
}b. RecyclerView子项的布局​
<LinearLayout
android:id="@+id/ll_msg_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
<!-- 设置点击效果为水波纹(5.0以上) -->
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
android:padding="2dp">
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="20dp"
app:cardPreventCornerOverlap="false"
app:cardUseCompatPadding="true">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:scaleType="centerCrop"
android:src="@mipmap/man" />
</android.support.v7.widget.CardView>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/message_left"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_msg_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:textColor="#fff" />
</LinearLayout>
</LinearLayout>这是左边的部分,至于右边应该也就简单了。我用CardView把ImageView包裹起来,这样比较好看。效果如下:




c. RecyclerView适配器​
public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.MyViewHolder> {
private List<MSG> mMsgList;
public MsgAdapter(List<MSG> mMsgList) {
this.mMsgList = mMsgList;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(parent.getContext(), R.layout.item_msg, null);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MSG msg = mMsgList.get(position);
if (msg.getType() == MSG.TYPE_RECEIVED){
//如果是收到的消息,显示左边布局,隐藏右边布局
holder.llLeft.setVisibility(View.VISIBLE);
holder.llRight.setVisibility(View.GONE);
holder.tv_Left.setText(msg.getContent());
} else if (msg.getType() == MSG.TYPE_SEND){
//如果是发送的消息,显示右边布局,隐藏左边布局
holder.llLeft.setVisibility(View.GONE);
holder.llRight.setVisibility(View.VISIBLE);
holder.tv_Right.setText(msg.getContent());
}
}
@Override
public int getItemCount() {
return mMsgList.size();
}
static class MyViewHolder extends RecyclerView.ViewHolder{
LinearLayout llLeft;
LinearLayout llRight;
TextView tv_Left;
TextView tv_Right;
public MyViewHolder(View itemView) {
super(itemView);
llLeft = (LinearLayout) itemView.findViewById(R.id.ll_msg_left);
llRight = (LinearLayout) itemView.findViewById(R.id.ll_msg_right);
tv_Left = (TextView) itemView.findViewById(R.id.tv_msg_left);
tv_Right = (TextView) itemView.findViewById(R.id.tv_msg_right);
}
}
}这部分应该也没什么问题,就是适配器的创建,我之前的文章也讲过 传送门:简单粗暴——RecyclerView

d. RecyclerView初始化

就是一些基本的初始化,我就不赘述了,讲一下添加数据的细节处理
 
btSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String content = etInput.getText().toString().trim();
if (!TextUtils.isEmpty(content)){
...//环信部分的发送消息
MSG msg = new MSG(content, MSG.TYPE_SEND);
mList.add(msg);
//当有新消息时,刷新RecyclerView中的显示
mAdapter.notifyItemInserted(mList.size() - 1);
//将RecyclerView定位到最后一行
mRecyclerView.scrollToPosition(mList.size() - 1);
etInput.setText("");
}
}
});至此界面已经结束了,接下来就是数据的读取

2. 环信API的简单应用

官网有详细的API介绍 环信及时通讯V3.0,我这里就简单介绍如何简单集成

a. 环信开发账号的注册

环信官网

创建应用得到Appkey后面要用




b. SDK导入

你可以直接下载然后拷贝工程的libs目录下

Android Studio可以直接添加依赖
 
将以下代码放到项目根目录的build.gradle文件里
repositories {
maven { url "https://raw.githubusercontent. ... ot%3B }
}在你的module的build.gradle里加入以下代码
android {
//use legacy for android 6.0
useLibrary 'org.apache.http.legacy'
}
dependencies {
compile 'com.android.support:appcompat-v7:23.4.0'
//Optional compile for GCM (Google Cloud Messaging).
compile 'com.google.android.gms:play-services-gcm:9.4.0'
compile 'com.hyphenate:hyphenate-sdk:3.2.3'
}如果想使用不包含音视频通话的sdk,用compile 'com.hyphenate [:hyphenate-sdk-lite:] 3.2.3'
 
c. 清单文件配置
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="Your Package"
android:versionCode="100"
android:versionName="1.0.0">
<!-- Required -->
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:name="Your Application">
<!-- 设置环信应用的AppKey -->
<meta-data android:name="EASEMOB_APPKEY" android:value="Your AppKey" />
<!-- 声明SDK所需的service SDK核心功能-->
<service android:name="com.hyphenate.chat.EMChatService" android:exported="true"/>
<service android:name="com.hyphenate.chat.EMJobService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true"
/>
<!-- 声明SDK所需的receiver -->
<receiver android:name="com.hyphenate.chat.EMMonitorReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<data android:scheme="package"/>
</intent-filter>
<!-- 可选filter -->
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.USER_PRESENT" />
</intent-filter>
</receiver>
</application>
</manifest>APP打包混淆
-keep class com.hyphenate.** {*;}
-dontwarn com.hyphenate.**d. 初始化SDK
在自定义Application的onCreate中初始化
public class MyApplication extends Application {
private Context appContext;
@Override
public void onCreate() {
super.onCreate();
EMOptions options = new EMOptions();
options.setAcceptInvitationAlways(false);
appContext = this;
int pid = android.os.Process.myPid();
String processAppName = getAppName(pid);
// 如果APP启用了远程的service,此application:onCreate会被调用2次
// 为了防止环信SDK被初始化2次,加此判断会保证SDK被初始化1次
// 默认的APP会在以包名为默认的process name下运行,如果查到的process name不是APP的process name就立即返回
if (processAppName == null || !processAppName.equalsIgnoreCase(appContext.getPackageName())) {
Log.e("--->", "enter the service process!");
// 则此application::onCreate 是被service 调用的,直接返回
return;
}
//初始化
EMClient.getInstance().init(getApplicationContext(), options);
//在做打包混淆时,关闭debug模式,避免消耗不必要的资源
EMClient.getInstance().setDebugMode(true);
}
private String getAppName(int pID) {
String processName = null;
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
List l = am.getRunningAppProcesses();
Iterator i = l.iterator();
PackageManager pm = this.getPackageManager();
while (i.hasNext()) {
ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) (i.next());
try {
if (info.pid == pID) {
processName = info.processName;
return processName;
}
} catch (Exception e) {
// Log.d("Process", "Error>> :"+ e.toString());
}
}
return processName;
}
}e. 注册和登陆

注册要在子线程中执行
//注册失败会抛出HyphenateException
EMClient.getInstance().createAccount(username, pwd);//同步方法
EMClient.getInstance().login(userName,password,new EMCallBack() {//回调
@Override
public void onSuccess() {
EMClient.getInstance().groupManager().loadAllGroups();
EMClient.getInstance().chatManager().loadAllConversations();
Log.d("main", "登录聊天服务器成功!");
}
@Override
public void onProgress(int progress, String status) {
}
@Override
public void onError(int code, String message) {
Log.d("main", "登录聊天服务器失败!");
}
});f. 发送消息
//创建一条文本消息,content为消息文字内容,toChatUsername为对方用户或者群聊的id,后文皆是如此
EMMessage message = EMMessage.createTxtSendMessage(content, toChatUsername);
//发送消息
EMClient.getInstance().chatManager().sendMessage(message);g. 接收消息
msgListener = new EMMessageListener() {
@Override
public void onMessageReceived(List<EMMessage> messages) {
//收到消息
String result = messages.get(0).getBody().toString();
String msgReceived = result.substring(5, result.length() - 1);
Log.i(TAG, "onMessageReceived: " + msgReceived);
final MSG msg = new MSG(msgReceived, MSG.TYPE_RECEIVED);
runOnUiThread(new Runnable() {
@Override
public void run() {
mList.add(msg);
mAdapter.notifyDataSetChanged();
mRecyclerView.scrollToPosition(mList.size() - 1);
}
});
}
@Override
public void onCmdMessageReceived(List<EMMessage> messages) {
//收到透传消息
}
@Override
public void onMessageRead(List<EMMessage> list) {
}
@Override
public void onMessageDelivered(List<EMMessage> list) {
}
@Override
public void onMessageChanged(EMMessage message, Object change) {
//消息状态变动
}
};接收消息的监听器分别需要在OnResume()和OnDestory()方法中注册和取消注册
EMClient.getInstance().chatManager().addMessageListener(msgListener);//注册
EMClient.getInstance().chatManager().removeMessageListener(msgListener);//取消注册需要注意的是,当接收到消息,需要在主线程中更新适配器,否则会不能及时刷新出来

项目文件截图:





到此,一个简单的及时聊天Demo已经完成,功能很简单,如果需要添加额外功能的话,可以自行参考官网,官网给出的教程还是很不错的!

最后希望大家能多多支持我,需要你们的支持喜欢!! 查看全部
概述
 
今天看了环信的API,就利用下午的时间动手试了试,然后做了一个小Demo。详细

我的博客地址

之前一直想实现聊天的功能,但是感觉有点困难,今天看了环信的API,就利用下午的时间动手试了试,然后做了一个小Demo。
因为没有刻意去做聊天软件,花的时间也不多,然后界面就很简单,都是一些基本知识,如果觉得功能简单,可以自行添加,我这就不多介绍了。

照例先来一波动态演示:
4043475-d16a88926805236a.gif

 
功能很简单,注册用户 —> 用户登录 —> 选择聊天对象 —> 开始聊天

使用到的知识点:
  1. RecyclerView
  2. CardView
  3. 环信的API的简单使用


依赖的库
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.android.support:cardview-v7:24.1.1'
compile 'com.android.support:recyclerview-v7:24.0.0'
1、聊天页面

首先是看了郭神的《第二行代码》做了聊天界面,用的是RecyclerView

a. 消息类的封装
public class MSG {
public static final int TYPE_RECEIVED = 0;//消息的类型:接收
public static final int TYPE_SEND = 1; //消息的类型:发送
private String content;//消息的内容
private int type; //消息的类型
public MSG(String content, int type) {
this.content = content;
this.type = type;
}
public String getContent() {
return content;
}
public int getType() {
return type;
}
}
b. RecyclerView子项的布局​
<LinearLayout
android:id="@+id/ll_msg_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
<!-- 设置点击效果为水波纹(5.0以上) -->
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
android:padding="2dp">
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="20dp"
app:cardPreventCornerOverlap="false"
app:cardUseCompatPadding="true">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:scaleType="centerCrop"
android:src="@mipmap/man" />
</android.support.v7.widget.CardView>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/message_left"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_msg_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:textColor="#fff" />
</LinearLayout>
</LinearLayout>
这是左边的部分,至于右边应该也就简单了。我用CardView把ImageView包裹起来,这样比较好看。效果如下:
4043475-76ea5370b4d09d89.png

c. RecyclerView适配器​
 public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.MyViewHolder> {
private List<MSG> mMsgList;
public MsgAdapter(List<MSG> mMsgList) {
this.mMsgList = mMsgList;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(parent.getContext(), R.layout.item_msg, null);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MSG msg = mMsgList.get(position);
if (msg.getType() == MSG.TYPE_RECEIVED){
//如果是收到的消息,显示左边布局,隐藏右边布局
holder.llLeft.setVisibility(View.VISIBLE);
holder.llRight.setVisibility(View.GONE);
holder.tv_Left.setText(msg.getContent());
} else if (msg.getType() == MSG.TYPE_SEND){
//如果是发送的消息,显示右边布局,隐藏左边布局
holder.llLeft.setVisibility(View.GONE);
holder.llRight.setVisibility(View.VISIBLE);
holder.tv_Right.setText(msg.getContent());
}
}
@Override
public int getItemCount() {
return mMsgList.size();
}
static class MyViewHolder extends RecyclerView.ViewHolder{
LinearLayout llLeft;
LinearLayout llRight;
TextView tv_Left;
TextView tv_Right;
public MyViewHolder(View itemView) {
super(itemView);
llLeft = (LinearLayout) itemView.findViewById(R.id.ll_msg_left);
llRight = (LinearLayout) itemView.findViewById(R.id.ll_msg_right);
tv_Left = (TextView) itemView.findViewById(R.id.tv_msg_left);
tv_Right = (TextView) itemView.findViewById(R.id.tv_msg_right);
}
}
}
这部分应该也没什么问题,就是适配器的创建,我之前的文章也讲过 传送门:简单粗暴——RecyclerView

d. RecyclerView初始化

就是一些基本的初始化,我就不赘述了,讲一下添加数据的细节处理
 
  btSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String content = etInput.getText().toString().trim();
if (!TextUtils.isEmpty(content)){
...//环信部分的发送消息
MSG msg = new MSG(content, MSG.TYPE_SEND);
mList.add(msg);
//当有新消息时,刷新RecyclerView中的显示
mAdapter.notifyItemInserted(mList.size() - 1);
//将RecyclerView定位到最后一行
mRecyclerView.scrollToPosition(mList.size() - 1);
etInput.setText("");
}
}
});
至此界面已经结束了,接下来就是数据的读取

2. 环信API的简单应用

官网有详细的API介绍 环信及时通讯V3.0,我这里就简单介绍如何简单集成

a. 环信开发账号的注册

环信官网


创建应用得到Appkey后面要用

4043475-e4dd45e05060467f.png


b. SDK导入

你可以直接下载然后拷贝工程的libs目录下

Android Studio可以直接添加依赖
 
将以下代码放到项目根目录的build.gradle文件里
repositories {
maven { url "https://raw.githubusercontent. ... ot%3B }
}
在你的module的build.gradle里加入以下代码
android {
//use legacy for android 6.0
useLibrary 'org.apache.http.legacy'
}
dependencies {
compile 'com.android.support:appcompat-v7:23.4.0'
//Optional compile for GCM (Google Cloud Messaging).
compile 'com.google.android.gms:play-services-gcm:9.4.0'
compile 'com.hyphenate:hyphenate-sdk:3.2.3'
}
如果想使用不包含音视频通话的sdk,用compile 'com.hyphenate [:hyphenate-sdk-lite:] 3.2.3'
 
c. 清单文件配置
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="Your Package"
android:versionCode="100"
android:versionName="1.0.0">
<!-- Required -->
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:name="Your Application">
<!-- 设置环信应用的AppKey -->
<meta-data android:name="EASEMOB_APPKEY" android:value="Your AppKey" />
<!-- 声明SDK所需的service SDK核心功能-->
<service android:name="com.hyphenate.chat.EMChatService" android:exported="true"/>
<service android:name="com.hyphenate.chat.EMJobService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true"
/>
<!-- 声明SDK所需的receiver -->
<receiver android:name="com.hyphenate.chat.EMMonitorReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<data android:scheme="package"/>
</intent-filter>
<!-- 可选filter -->
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.USER_PRESENT" />
</intent-filter>
</receiver>
</application>
</manifest>
APP打包混淆
-keep class com.hyphenate.** {*;}
-dontwarn com.hyphenate.**
d. 初始化SDK
在自定义Application的onCreate中初始化
public class MyApplication extends Application {
private Context appContext;
@Override
public void onCreate() {
super.onCreate();
EMOptions options = new EMOptions();
options.setAcceptInvitationAlways(false);
appContext = this;
int pid = android.os.Process.myPid();
String processAppName = getAppName(pid);
// 如果APP启用了远程的service,此application:onCreate会被调用2次
// 为了防止环信SDK被初始化2次,加此判断会保证SDK被初始化1次
// 默认的APP会在以包名为默认的process name下运行,如果查到的process name不是APP的process name就立即返回
if (processAppName == null || !processAppName.equalsIgnoreCase(appContext.getPackageName())) {
Log.e("--->", "enter the service process!");
// 则此application::onCreate 是被service 调用的,直接返回
return;
}
//初始化
EMClient.getInstance().init(getApplicationContext(), options);
//在做打包混淆时,关闭debug模式,避免消耗不必要的资源
EMClient.getInstance().setDebugMode(true);
}
private String getAppName(int pID) {
String processName = null;
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
List l = am.getRunningAppProcesses();
Iterator i = l.iterator();
PackageManager pm = this.getPackageManager();
while (i.hasNext()) {
ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) (i.next());
try {
if (info.pid == pID) {
processName = info.processName;
return processName;
}
} catch (Exception e) {
// Log.d("Process", "Error>> :"+ e.toString());
}
}
return processName;
}
}
e. 注册和登陆

注册要在子线程中执行
//注册失败会抛出HyphenateException
EMClient.getInstance().createAccount(username, pwd);//同步方法
EMClient.getInstance().login(userName,password,new EMCallBack() {//回调
@Override
public void onSuccess() {
EMClient.getInstance().groupManager().loadAllGroups();
EMClient.getInstance().chatManager().loadAllConversations();
Log.d("main", "登录聊天服务器成功!");
}
@Override
public void onProgress(int progress, String status) {
}
@Override
public void onError(int code, String message) {
Log.d("main", "登录聊天服务器失败!");
}
});
f. 发送消息
//创建一条文本消息,content为消息文字内容,toChatUsername为对方用户或者群聊的id,后文皆是如此
EMMessage message = EMMessage.createTxtSendMessage(content, toChatUsername);
//发送消息
EMClient.getInstance().chatManager().sendMessage(message);
g. 接收消息
msgListener = new EMMessageListener() {
@Override
public void onMessageReceived(List<EMMessage> messages) {
//收到消息
String result = messages.get(0).getBody().toString();
String msgReceived = result.substring(5, result.length() - 1);
Log.i(TAG, "onMessageReceived: " + msgReceived);
final MSG msg = new MSG(msgReceived, MSG.TYPE_RECEIVED);
runOnUiThread(new Runnable() {
@Override
public void run() {
mList.add(msg);
mAdapter.notifyDataSetChanged();
mRecyclerView.scrollToPosition(mList.size() - 1);
}
});
}
@Override
public void onCmdMessageReceived(List<EMMessage> messages) {
//收到透传消息
}
@Override
public void onMessageRead(List<EMMessage> list) {
}
@Override
public void onMessageDelivered(List<EMMessage> list) {
}
@Override
public void onMessageChanged(EMMessage message, Object change) {
//消息状态变动
}
};
接收消息的监听器分别需要在OnResume()和OnDestory()方法中注册和取消注册
EMClient.getInstance().chatManager().addMessageListener(msgListener);//注册
EMClient.getInstance().chatManager().removeMessageListener(msgListener);//取消注册
需要注意的是,当接收到消息,需要在主线程中更新适配器,否则会不能及时刷新出来

项目文件截图:

HyTYCEDIj4uugpEvJ59.jpg

到此,一个简单的及时聊天Demo已经完成,功能很简单,如果需要添加额外功能的话,可以自行参考官网,官网给出的教程还是很不错的!

最后希望大家能多多支持我,需要你们的支持喜欢!!
0
回复

加载EaseUI封装的聊天页面的添加id找不到 Android 环信

回复

gorky_19 发起了问题 • 1 人关注 • 860 次浏览 • 2018-02-08 14:46 • 来自相关话题

0
回复

java.lang.IllegalArgumentException: No view found for id 0x7f07003a for fragment EaseChatFragment Android 环信

回复

gorky_19 发起了问题 • 1 人关注 • 1078 次浏览 • 2018-02-08 11:27 • 来自相关话题

2
最佳

看视频如果出现问题可以看这里 dyld: Library not loaded: @rpath/Hyphenate.framework/Hyphenate iOS 环信

Rickie_Lambert 回复了问题 • 3 人关注 • 5714 次浏览 • 2017-11-27 15:51 • 来自相关话题

7
回复

【环信官方外包一个项目】利用环信IM实现一个在线白板 环信

g711ab 回复了问题 • 8 人关注 • 3070 次浏览 • 2017-11-23 15:52 • 来自相关话题

1
回复

.a文件没找到 iOS 环信

dujiepeng 回复了问题 • 2 人关注 • 879 次浏览 • 2017-11-06 18:24 • 来自相关话题

0
回复

环信即时通讯 Unity,为什么只有用户的name,没有对应的id呢 环信

回复

叶孤城的橙 发起了问题 • 1 人关注 • 876 次浏览 • 2017-10-24 12:11 • 来自相关话题

3
回复

环信离线推送消息自定义 离线 推送 环信 通知

╰☆╮末↘ 回复了问题 • 2 人关注 • 1829 次浏览 • 2017-09-14 11:42 • 来自相关话题

0
评论

【环信征文】集成环信,并实现消息免打扰 即时通讯 环信 消息免打扰 IM iOS

cokeyer 发表了文章 • 640 次浏览 • 2017-09-14 11:27 • 来自相关话题

现在大多数社交app都有消息免打扰功能,因为环信SDK主要是对即时通讯模块进行封装,因此如果要实现消息免打扰功能则需要开发者自己对此功能逻辑进行处理。
先解释一下,本人项目中对消息免打扰功能的定义:正常情况下,我们收到的每一条聊天消息都会收到小红点、声音、震动的提示。如果对某个好友设置消息免打扰功能,则只提示小红点,声音和震动则不再提示。

下面简述结合环信SDK时,此功能的实现方法。
环信将即时聊天的所有功能分为四大模块进行管理://聊天模块:
[EMClient sharedClient].chatManager
//好友模块 :
[EMClient sharedClient].contactManager
//群组模块 :
[EMClient sharedClient].groupManager
//聊天室模块:
[EMClient sharedClient].roomManager消息免打扰的功能借助聊天模块[EMClient sharedClient].chatManager的API就能实现。
一般来说,在app内不管当前在哪个界面,只要收到消息都需要被判断是否需要免打扰,因此可以在appdelegate里写如下代码,app通常都有tabBarController,那么也可以让tabBarController来实现如下代码。
首先让控制器tabBarController遵守代理EMChatManagerDelegate
然后成为代理
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];

EMChatManagerDelegate中有一个代理方法- (void)didReceiveMessages:(NSArray *)aMessages;实现此代理方法- (void)didReceiveMessages:(NSArray *)aMessages{
[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;
}
}方法中有一个aMessages参数。这个参数是一个消息组,每一个元素都是EMMessage类型的实例。
因为通常都只有一条信息。因此只需要取出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,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂 查看全部
现在大多数社交app都有消息免打扰功能,因为环信SDK主要是对即时通讯模块进行封装,因此如果要实现消息免打扰功能则需要开发者自己对此功能逻辑进行处理。
先解释一下,本人项目中对消息免打扰功能的定义:正常情况下,我们收到的每一条聊天消息都会收到小红点、声音、震动的提示。如果对某个好友设置消息免打扰功能,则只提示小红点,声音和震动则不再提示。

下面简述结合环信SDK时,此功能的实现方法。
环信将即时聊天的所有功能分为四大模块进行管理:
//聊天模块:
[EMClient sharedClient].chatManager
//好友模块 :
[EMClient sharedClient].contactManager
//群组模块 :
[EMClient sharedClient].groupManager
//聊天室模块:
[EMClient sharedClient].roomManager
消息免打扰的功能借助聊天模块[EMClient sharedClient].chatManager的API就能实现。
一般来说,在app内不管当前在哪个界面,只要收到消息都需要被判断是否需要免打扰,因此可以在appdelegate里写如下代码,app通常都有tabBarController,那么也可以让tabBarController来实现如下代码。
首先让控制器tabBarController遵守代理EMChatManagerDelegate
然后成为代理
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];

EMChatManagerDelegate中有一个代理方法
- (void)didReceiveMessages:(NSArray *)aMessages;
实现此代理方法
- (void)didReceiveMessages:(NSArray *)aMessages{
[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;
}
}
方法中有一个aMessages参数。这个参数是一个消息组,每一个元素都是EMMessage类型的实例。
因为通常都只有一条信息。因此只需要取出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,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂

qrcode_for_gh_bc92a063b4a2_430.jpg
0
评论

【环信征文】基于环信开发一个医疗APP-Ⅰ iOS 环信 即时通讯 IM

cokeyer 发表了文章 • 545 次浏览 • 2017-09-12 17:56 • 来自相关话题

公司又有了新项目,依然是含有即时通讯功能模块的项目。在经历了上个项目对环信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
{
//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;
}




本人github:https://github.com/BHAreslee
本人简书:http://www.jianshu.com/u/bb53043aaa00
以上就是集成环信时暂时发现的问题,欢迎大家分享你们遇到的问题,也欢迎加入QQ群:372251359,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂





 
项目完整源码 查看全部
公司又有了新项目,依然是含有即时通讯功能模块的项目。在经历了上个项目对环信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的如下方法

环信2.png

然而这个方法,环信并没有放在EaseMessageViewController.h成为公开方法。我们只需手动粘贴方法到.h,然后在自己的子类重写就可以了。

还有一个关于更多下图更多功能区域的问题

EaseChatBarMoreView.png

如上图所示,相册、拍照、视频等附加功能按钮,环信用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
{
//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;
}




本人github:https://github.com/BHAreslee
本人简书:http://www.jianshu.com/u/bb53043aaa00
以上就是集成环信时暂时发现的问题,欢迎大家分享你们遇到的问题,也欢迎加入QQ群:372251359,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂

qrcode_for_gh_bc92a063b4a2_430.jpg

 
项目完整源码
0
回复

收到消息的代理回调不会执行 环信 iOS

回复

Aries 发起了问题 • 1 人关注 • 1073 次浏览 • 2017-09-12 10:28 • 来自相关话题

0
评论

环信公开课16期回放|环信智能鉴黄:用深度学习实现99%精准度的鉴黄服务 环信 环信公开课 环信智能鉴黄 鉴黄

beyond 发表了文章 • 1024 次浏览 • 2017-09-04 17:01 • 来自相关话题

   8月31日,环信公开课以“智能鉴黄”为主题,为大家普及了内容审查工作的前世今生,以及环信智能鉴黄算法、技术实现和行业解决方案。
 
关于环信智能鉴黄:
   随着移动互联网的飞速发展和信息量的猛增,大量的色情、赌博、暴力等不良信息图片夹杂在信息流中,严重影响着整个互联网的体验和健康发展。各大互联网公司为了保持自己所提供的服务不触犯国家法律和法规,使得鉴黄工作变得尤为重要。环信智能鉴黄服务基于深度学习的智能鉴黄算法,识别精准度高达99%,可以帮助企业完成95%的图片内容审查工作,节省90%的时间及人工成本。
环信公开课第16期分享内容:


















































环信公开课第16期视频回放:





参加环信公开课还有大礼相送:
恭喜手机尾号8985的leoNN同学成为本期公开课幸运观众,获得环信定制版瑞士军团双肩背包。

环信智能鉴黄免费体验请联系环信小助手,微信huanxin-hh 查看全部
   8月31日,环信公开课以“智能鉴黄”为主题,为大家普及了内容审查工作的前世今生,以及环信智能鉴黄算法、技术实现和行业解决方案。
 
关于环信智能鉴黄:

   随着移动互联网的飞速发展和信息量的猛增,大量的色情、赌博、暴力等不良信息图片夹杂在信息流中,严重影响着整个互联网的体验和健康发展。各大互联网公司为了保持自己所提供的服务不触犯国家法律和法规,使得鉴黄工作变得尤为重要。环信智能鉴黄服务基于深度学习的智能鉴黄算法,识别精准度高达99%,可以帮助企业完成95%的图片内容审查工作,节省90%的时间及人工成本。


环信公开课第16期分享内容:
001.png


002.png


003.png


004.png


005.png


006.png


007.png


008.png


009.png


010.png


环信公开课第16期视频回放:






参加环信公开课还有大礼相送:
恭喜手机尾号8985的leoNN同学成为本期公开课幸运观众,获得环信定制版瑞士军团双肩背包。

环信智能鉴黄免费体验请联系环信小助手,微信huanxin-hh
3a36009c9eb571b9a3a2797f17c4ae25.gif
1
评论

精通环信开发已成程序员招聘刚需?看别人家的招聘要求 环信 招聘

beyond 发表了文章 • 550 次浏览 • 2017-08-25 15:46 • 来自相关话题

今天在一个2000人技术交流群里看到一家互联网公司招聘Android/ios开发











一段不到200字的招聘要求,竟然出现了两次“环信”。眉头一紧,感觉这事不简单了!






去年在环信社区看到《今天面试一个自称两年经验的Android》《我又做了一次面试官》两篇面试经历还不以为然,没想到一年内作者预言成真,精通环信开发等第三方API开发已然成为程序员招聘刚需!

作为一个与时俱进的好司机赶紧打开X度搜索“如何精通环信开发”,还真让我找到了环信Alpha全国开发者培训计划,



环信alpha计划将对所有报名的ISV厂商和开发者提供技术、审核认证及发行等方面的支持。环信“Alpha计划”旨在为ISV和开发者们提供更加全面且专业的支持,帮助其在包括企业IM、协同OA、APP内社交、直播互动、IOT、智能硬件等领域挖掘产生更多落地有商业前景的优质项目,一起建设整个即时通讯云服务生态。

文末有小伙伴愿意去这家福建公司的发送简历到duc@easemob.com邮箱,暗号“我精通环信开发”,我们等的就是你! 查看全部
今天在一个2000人技术交流群里看到一家互联网公司招聘Android/ios开发

TIM截图20170825163121.png


timg.jpg


一段不到200字的招聘要求,竟然出现了两次“环信”。眉头一紧,感觉这事不简单了!

TIM图片20170825160503.jpg


去年在环信社区看到《今天面试一个自称两年经验的Android》《我又做了一次面试官》两篇面试经历还不以为然,没想到一年内作者预言成真,精通环信开发等第三方API开发已然成为程序员招聘刚需!

作为一个与时俱进的好司机赶紧打开X度搜索“如何精通环信开发”,还真让我找到了环信Alpha全国开发者培训计划
TIM截图20170825160913.png
环信alpha计划将对所有报名的ISV厂商和开发者提供技术、审核认证及发行等方面的支持。环信“Alpha计划”旨在为ISV和开发者们提供更加全面且专业的支持,帮助其在包括企业IM、协同OA、APP内社交、直播互动、IOT、智能硬件等领域挖掘产生更多落地有商业前景的优质项目,一起建设整个即时通讯云服务生态。

文末有小伙伴愿意去这家福建公司的发送简历到duc@easemob.com邮箱,暗号“我精通环信开发”,我们等的就是你!
条新动态, 点击查看
expawtest

expawtest 回答了问题 • 2015-05-08 15:04 • 17 个回复 不感兴趣

为什么添加好友,通知收不到啊?

赞同来自:

> forum.php?mod=redirect&goto=findpost&pid=2572&ptid=1121
所以让你检查逻辑啊,毕竟是你写的代码,demo也不会这样


不就是在MainAct中设置监听,然后后面添加好友,然后监听到吗?
逻辑不对吗... 显示全部 »
> forum.php?mod=redirect&goto=findpost&pid=2572&ptid=1121
所以让你检查逻辑啊,毕竟是你写的代码,demo也不会这样


不就是在MainAct中设置监听,然后后面添加好友,然后监听到吗?
逻辑不对吗??
lifei9241

lifei9241 回答了问题 • 2015-06-28 17:22 • 2 个回复 不感兴趣

创建群之后在修改群的类型可以吗?

赞同来自:

创建之后,群组的类型不能更改了。可以更改groupname,description,maxusers这三个属性,http://www.easemob.com/docs/rest/groups/#update
创建之后,群组的类型不能更改了。可以更改groupname,description,maxusers这三个属性,http://www.easemob.com/docs/rest/groups/#update
Half12345

Half12345 回答了问题 • 2015-06-29 16:51 • 1 个回复 不感兴趣

iOS cocoapods2.1.8一直在更新 安装不上

赞同来自:

1、pod setup
2、pod search EaseMobSDK
3、加到podfile
4、pod install
 
1、pod setup
2、pod search EaseMobSDK
3、加到podfile
4、pod install
 
见代码板块:  http://www.imgeek.org/page/code  
见代码板块:  http://www.imgeek.org/page/code  
这个方法更新本地的消息,您需要更新本地的消息的话,将消息更新之后,调用updateMessage消息的内容会被保存到本地,再次获取本地的消息获取到的就是更新后的消息
这个方法更新本地的消息,您需要更新本地的消息的话,将消息更新之后,调用updateMessage消息的内容会被保存到本地,再次获取本地的消息获取到的就是更新后的消息
ChrisWu

ChrisWu 回答了问题 • 2016-12-06 17:06 • 1 个回复 不感兴趣

集成easeui时一直报错

赞同来自:

把你的v4包的版本改高一点,它默认的是19+
 
把你的v4包的版本改高一点,它默认的是19+
 
我前几天也被这个问题绊住了一天。最后发现是环信IM的音视频SDK与百度地图静态SDK冲突,更换成环信SDK最新版V3.2.3(framework动态库)即可。或者用没有包含音视频功能的环信SDK!亲测有效!
我前几天也被这个问题绊住了一天。最后发现是环信IM的音视频SDK与百度地图静态SDK冲突,更换成环信SDK最新版V3.2.3(framework动态库)即可。或者用没有包含音视频功能的环信SDK!亲测有效!
这个 问题很可能就是 导入的环信依赖库重复了, 即导入了包含实时音视频的依赖库,又导入了不包含实时音视频的依赖库。 可以检查一下,导入的依赖库是否导入错了, 重新导入,就可以解决这个问题了。
这个 问题很可能就是 导入的环信依赖库重复了, 即导入了包含实时音视频的依赖库,又导入了不包含实时音视频的依赖库。 可以检查一下,导入的依赖库是否导入错了, 重新导入,就可以解决这个问题了。
0
评论

【活动推荐】ECUG Con 2018 拥抱下一个十年 ECUG Con 2018 许式伟 ECUG 七牛云

beyond 发表了文章 • 91 次浏览 • 2018-12-03 15:47 • 来自相关话题

国内云计算领域大咖 许式伟
倾情发起的技术盛宴
引领国内云领域风向的高端峰会
ECUG Con 2018
2018 年 12 月 22-23 日 深圳
全新启程!ECUG Con 2018

七牛云 CEO 许式伟

PingCAP CEO 刘奇

七牛云产品副总裁戴文军

Gopher 社区创始人 Asta Xie

阿里巴巴技术专家孙宏亮

《Kubernetes IN ACTION》作者 Marko Lukša

华为云 AI 推理平台&云搜索技术总监胡斐然

七牛云技术总监陈超

阿里云高级开发工程师严明明

京东云区块链实验室与数据库部负责人郭里靖

网易研究院云计算资深架构师朱剑峰

腾讯云高级工程师刘兆瑞

货拉拉数据分析负责人高遥

......
超豪华讲师阵容!

超有料精彩分享!

ECUG 历经十年蜕变

邀您共同开启下个十年

让我们坚持技术情怀,秉承技术精神

开启新的云计算布道篇章!
 
时  间

2018 年 12 月 22-23 日

地  点

深圳市南山区软件产业基地 

更多详情请见下方海报~




扫描上方二维码 ,立即购买早鸟票

与大咖讲师共同探索云计算的下一个十年!
活动详情:了解更多 查看全部
国内云计算领域大咖  许式伟 
倾情发起的技术盛宴
引领国内云领域风向的高端峰会
ECUG Con 2018
2018 年 12 月 22-23 日 深圳
全新启程!
ECUG Con 2018

七牛云 CEO 许式伟

PingCAP CEO 刘奇

七牛云产品副总裁戴文军

Gopher 社区创始人 Asta Xie

阿里巴巴技术专家孙宏亮

《Kubernetes IN ACTION》作者 Marko Lukša

华为云 AI 推理平台&云搜索技术总监胡斐然

七牛云技术总监陈超

阿里云高级开发工程师严明明

京东云区块链实验室与数据库部负责人郭里靖

网易研究院云计算资深架构师朱剑峰

腾讯云高级工程师刘兆瑞

货拉拉数据分析负责人高遥

......
超豪华讲师阵容!

超有料精彩分享!

ECUG 历经十年蜕变

邀您共同开启下个十年

让我们坚持技术情怀,秉承技术精神

开启新的云计算布道篇章!
 
时  间

2018 年 12 月 22-23 日

地  点

深圳市南山区软件产业基地 

更多详情请见下方海报~
30943258454939062.jpg

扫描上方二维码 ,立即购买早鸟票

与大咖讲师共同探索云计算的下一个十年!
活动详情:了解更多
0
评论

【我最喜爱的 Cloud Studio 插件评选大赛】终于开始了! Cloud Studio Cloud Studio 插件评选大赛 腾讯云开发者平台 coding 编程大赛

beyond 发表了文章 • 146 次浏览 • 2018-11-26 15:37 • 来自相关话题

由 环信、腾讯云和 CODING 共同举办的 我最喜爱的 Cloud Studio 插件评选大赛正式开始了!在这场比赛里,将会有技术上的碰撞,大牛评委的专业点评,愉快的技术交流,好玩的插件尝试。





参赛者可以围绕 Git、实用小工具、腾讯云产品对接、UI 强化、语言支持等 14 个主题提交插件,再加上最具娱乐奖,代码最简单奖,设置功能最复杂奖等;近 30 种奖项,超高中奖率;插件只要提交上架,就有 50 元的话费相赠;只要关注 CODING 公众号并转发活动讯息到朋友圈,即可获得手机充值小礼!

参与方式

注册并登陆腾讯云开发者平台(https://dev.tencent.com) -> 点击进入活动页面 -> 点击进行插件的编写与提交(需要选择参与评选的类别)-> 审核无误后即可上架自动参与评选。

赛程时间




 
环信特别奖




基于环信开发一款聊天插件,即有机会获得特别奖,根据作品还将获得环信提供的神秘奖品
更多活动信息,请浏览我们的活动页面。

进入活动页面> 查看全部

2.jpg


由 环信、腾讯云和 CODING 共同举办的 我最喜爱的 Cloud Studio 插件评选大赛正式开始了!在这场比赛里,将会有技术上的碰撞,大牛评委的专业点评,愉快的技术交流,好玩的插件尝试。

6ccda21fgy1fxeim29mncj20ik0e6dn4.jpg

  • 参赛者可以围绕 Git、实用小工具、腾讯云产品对接、UI 强化、语言支持等 14 个主题提交插件,再加上最具娱乐奖,代码最简单奖,设置功能最复杂奖等;
  • 近 30 种奖项,超高中奖率;
  • 插件只要提交上架,就有 50 元的话费相赠;
  • 只要关注 CODING 公众号并转发活动讯息到朋友圈,即可获得手机充值小礼!


参与方式

注册并登陆腾讯云开发者平台https://dev.tencent.com) -> 点击进入活动页面 -> 点击进行插件的编写与提交(需要选择参与评选的类别)-> 审核无误后即可上架自动参与评选。

赛程时间
6ccda21fly1fxejmnr8oej20ow03odfy.jpg

 
环信特别奖
tb16@2x.png

基于环信开发一款聊天插件,即有机会获得特别奖,根据作品还将获得环信提供的神秘奖品
更多活动信息,请浏览我们的活动页面。

进入活动页面>
4
评论

【开源项目】全国首个开源直播小程序源码 环信公开课 小程序 直播

beyond 发表了文章 • 4077 次浏览 • 2018-07-20 17:30 • 来自相关话题

今天你看直播了吗?拥有10亿微信生态用户的小程序已经成为了继移动互联后的又一个现象级风口,随着微信小程序对外开放实时音视频录制及播放等更多连接能力,小程序与直播强强联合,在各行各业找到了非常多的玩法,小程序直播相比微信直播和APP直播更加简洁、流畅、低延时、多入口等众多优势迅速向商业直播领域及泛娱乐直播领域蔓延。从小游戏、内容付费、工具、大数据、社交电商创业者到传统品牌商们,都在努力搭上小程序直播这辆快车,以免错过微信生态里新的流量洼地。
 





作为一名环信生态圈资深开发者,本着对技术的热衷,对环信的眷恋和对党的忠诚,基于环信即时通讯云写了“直播购物小程序”,目前项目源码已全部免费开放,希望对有需求的企业和开发者提供一个思路和参考。
直播购物小程序源码github地址:https://github.com/YuTongNetworkTechnology/wechat_live/tree/master 
git打不开可直接点下面链接下载


小程序直播demo_2018-06-21.zip







直播购物小程序运行预览图 
 
小程序体验指南(仅需两步):
 
1、下载微信小程序开发工具,下载地址:https://developers.weixin.qq.c ... .html 
 




2、导入源码:将附件的源码解压直接导入 







环信小程序直播技术文档
一、 使用的技术
1、 环信IM直播室。
2、 微信小程序实时音视频播放组件live-player。
3、 推流软件(obs、易推流)等推流。
4、 视频流服务器(UCLOUD、七牛、腾讯)等视频流服务器。
二、 系统使用流程。
1、 视频推流软件将视频流推到流服务器。
2、 打开视频直播demo小程序注册环信账号。
3、 进入软件直播室进行测试。
三、 技术流程及使用的SDk
1、 注册环信账号
打开https://www.easemob.com/ 环信官网,点击右上角注册按钮,选择[注册即时通讯云]




填写对相关信息进行注册





注册成功后进行登录




注:新注册用户需进行账号的认证。
2、 直播应用创建
登录成功点击应用列表选择创建应用




输入应用名称等信息
 





创建成功后点击应用进入





需要注意的是应用的OrgName 和AppName这两个是以后都需要用到的两个参数变量




3、 直播创建
1)在创建直播之前需要对应用进行设置首先需要设置应用的直播流地址
第一步获取应用管理员的Tokencurl -X POST "https://a1.easemob.com/[应用OrgName]/[应用AppName]/token" -d '{"grant_type":"client_credentials","client_id":"[应用client_id]","client_secret":"[应用] client_secret"}'返回格式{
"access_token":"YWMtWY779DgJEeS2h9OR7fw4QgAAAUmO4Qukwd9cfJSpkWHiOa7MCSk0MrkVIco",
"expires_in":5184000,
"application":"c03b3e30-046a-11e4-8ed1-5701cdaaa0e4"












第二步设置直播流地址curl -X POST -H "Authorization: Bearer [管理员Token]" " https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms/stream_url -d '{"pc_pull":"[pc拉流地址]","pc_push":"[pc推流地址]","mobile_pull":"[手机拉流地址]","mobile_push":"[手机推流地址]"}'"成功返回格式:{
"action": "post",
"application": "e1a09de0-0e03-11e7-ad8e-a1d913615409",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"pc_pull": true,
"mobile_push": true,
"mobile_pull": true,
"pc_push": true
},
"timestamp": 1494084474885,
"duration": 1,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












2)创建主播
点击IM用户





点击注册IM用户





填写用户信息





创建用户的过程同样也可以通过REST API形式进行curl -X POST -i " https://a1.easemob.com/[应用OrgName]/[应用AppName]/users" -d '{"username":"[用户名]","password":"[密码]"}'
注:应用必须为开放注册





将注册的用户添加为主播curl -X POST -H "Authorization: [管理员Token]" https://a1.easemob.com/[应用OrgName]/[应用AppName]/super_admin -d'{"superadmin":"[IM用户名]"}'返回结果示例:{
"action": "post",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"result": "success"
},
"timestamp": 1496236798886,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












3)创建直播
点击直播





点击新建房间





填写房间信息




创建房间同时也可以使用REST API形式进行详情可以查看http://docs.easemob.com/im/live/server-integration环信官方文档。
4、 小程序demo集成使用
小程序直播购物demo集成官方WebIM SDK详情请查看https://github.com/easemob/webim-weixin-xcx
Demo具体配置如下
打开demo 下sdk配置文件





修改appkey为自己应用的appkey





打开pages/live/index.js修改房间默认拉流地址及直播间房间号





四、 扩展说明
Demo中房间为固定测试房间,实际使用中应获取环信直播的房间信息及房间列表。具体如下:
获取直播间列表:curl -X GET -H "Authorization: Bearer [用户Token]" https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms?ongoing=true&limit=[获取数量]&cursor=[游标地址(不填写为充开始查询)]
响应:{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"params": {
"cursor": [
"ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6MzE"
],
"ongoing": [
"true"
],
"limit": [
"2"
]
},
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": [
{
"id": "1924",
"chatroom_id": "17177265635330",
"title": "具体了",
"desc": "就咯",
"startTime": 1495779917352,
"endTime": 1495779917352,
"anchor": "wuls",
"gift_count": 0,
"praise_count": 0,
"current_user_count": 8,
"max_user_count": 9,
"status": "ongoing",
"cover_picture_url": "",
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1"
},
{
"id": "1922",
"chatroom_id": "17175003856897",
"title": "香山",
"desc": "随便",
"startTime": 1495777760957,
"endTime": 1495777760957,
"anchor": "sx001",
"gift_count": 0,
"praise_count": 8,
"current_user_count": 1,
"max_user_count": 3,
"status": "ongoing",
"cover_picture_url": "http://127.0.0.1:8080/easemob- ... ot%3B,
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1"
}
],
"timestamp": 1496303336669,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"cursor": "ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6NDk",
"count": 2
}












获取直播间详情:curl -X GET -H "Authorization: Bearer [用户Token]" " https://a1.easemob.com/[应用OrgName]/[应用AppName]/[房间id]/status"响应:{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"liveRoomID": "1946",
"status": "ongoing"
},
"timestamp": 1496234759930,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"count": 0
}














 
使用环信直播购物小程序遇到任何问题欢迎跟帖讨论。 查看全部
今天你看直播了吗?
拥有10亿微信生态用户的小程序已经成为了继移动互联后的又一个现象级风口,随着微信小程序对外开放实时音视频录制及播放等更多连接能力,小程序与直播强强联合,在各行各业找到了非常多的玩法,小程序直播相比微信直播和APP直播更加简洁、流畅、低延时、多入口等众多优势迅速向商业直播领域及泛娱乐直播领域蔓延。从小游戏、内容付费、工具、大数据、社交电商创业者到传统品牌商们,都在努力搭上小程序直播这辆快车,以免错过微信生态里新的流量洼地。
 
微信图片_20180725162426.jpg


作为一名环信生态圈资深开发者,本着对技术的热衷,对环信的眷恋和对党的忠诚,基于环信即时通讯云写了“直播购物小程序”,目前项目源码已全部免费开放,希望对有需求的企业和开发者提供一个思路和参考。
直播购物小程序源码github地址:https://github.com/YuTongNetworkTechnology/wechat_live/tree/master 
git打不开可直接点下面链接下载



预览图.jpg

直播购物小程序运行预览图 
 
小程序体验指南(仅需两步):
 
1、下载微信小程序开发工具,下载地址:https://developers.weixin.qq.c ... .html 
 
Catch9A07(07-20-17-38-30).jpg

2、导入源码:将附件的源码解压直接导入 


Catch1C69(07-20-17-38-30).jpg


环信小程序直播技术文档
一、 使用的技术
1、 环信IM直播室。
2、 微信小程序实时音视频播放组件live-player。
3、 推流软件(obs、易推流)等推流。
4、 视频流服务器(UCLOUD、七牛、腾讯)等视频流服务器。
二、 系统使用流程。
1、 视频推流软件将视频流推到流服务器。
2、 打开视频直播demo小程序注册环信账号。
3、 进入软件直播室进行测试。
三、 技术流程及使用的SDk
1、 注册环信账号
打开https://www.easemob.com/ 环信官网,点击右上角注册按钮,选择[注册即时通讯云]
1.png

填写对相关信息进行注册

2.png

注册成功后进行登录
3.png

注:新注册用户需进行账号的认证。
2、 直播应用创建
登录成功点击应用列表选择创建应用
4.png

输入应用名称等信息
 

5.png

创建成功后点击应用进入

6.png

需要注意的是应用的OrgName 和AppName这两个是以后都需要用到的两个参数变量
7.png

3、 直播创建
1)在创建直播之前需要对应用进行设置首先需要设置应用的直播流地址
第一步获取应用管理员的Token
curl -X POST "https://a1.easemob.com/[应用OrgName]/[应用AppName]/token" -d '{"grant_type":"client_credentials","client_id":"[应用client_id]","client_secret":"[应用] client_secret"}'
返回格式
{
"access_token":"YWMtWY779DgJEeS2h9OR7fw4QgAAAUmO4Qukwd9cfJSpkWHiOa7MCSk0MrkVIco",
"expires_in":5184000,
"application":"c03b3e30-046a-11e4-8ed1-5701cdaaa0e4"












第二步设置直播流地址
curl -X POST -H "Authorization: Bearer [管理员Token]"  " https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms/stream_url -d '{"pc_pull":"[pc拉流地址]","pc_push":"[pc推流地址]","mobile_pull":"[手机拉流地址]","mobile_push":"[手机推流地址]"}'"
成功返回格式:
{
"action": "post",
"application": "e1a09de0-0e03-11e7-ad8e-a1d913615409",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"pc_pull": true,
"mobile_push": true,
"mobile_pull": true,
"pc_push": true
},
"timestamp": 1494084474885,
"duration": 1,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












2)创建主播
点击IM用户

8.png

点击注册IM用户

9.png

填写用户信息

10.png

创建用户的过程同样也可以通过REST API形式进行
curl -X POST -i " https://a1.easemob.com/[应用OrgName]/[应用AppName]/users" -d '{"username":"[用户名]","password":"[密码]"}'

注:应用必须为开放注册

11.png

将注册的用户添加为主播
curl -X POST -H "Authorization: [管理员Token]"  https://a1.easemob.com/[应用OrgName]/[应用AppName]/super_admin -d'{"superadmin":"[IM用户名]"}'
返回结果示例:
{
"action": "post",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"result": "success"
},
"timestamp": 1496236798886,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












3)创建直播
点击直播

12.png

点击新建房间

13.png

填写房间信息
14.png

创建房间同时也可以使用REST API形式进行详情可以查看http://docs.easemob.com/im/live/server-integration环信官方文档。
4、 小程序demo集成使用
小程序直播购物demo集成官方WebIM SDK详情请查看https://github.com/easemob/webim-weixin-xcx
Demo具体配置如下
打开demo 下sdk配置文件

15.png

修改appkey为自己应用的appkey

16.png

打开pages/live/index.js修改房间默认拉流地址及直播间房间号

17.png

四、 扩展说明
Demo中房间为固定测试房间,实际使用中应获取环信直播的房间信息及房间列表。具体如下:
获取直播间列表:
curl -X GET -H "Authorization: Bearer  [用户Token]"  https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms?ongoing=true&limit=[获取数量]&cursor=[游标地址(不填写为充开始查询)]

响应:
{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"params": {
"cursor": [
"ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6MzE"
],
"ongoing": [
"true"
],
"limit": [
"2"
]
},
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": [
{
"id": "1924",
"chatroom_id": "17177265635330",
"title": "具体了",
"desc": "就咯",
"startTime": 1495779917352,
"endTime": 1495779917352,
"anchor": "wuls",
"gift_count": 0,
"praise_count": 0,
"current_user_count": 8,
"max_user_count": 9,
"status": "ongoing",
"cover_picture_url": "",
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1"
},
{
"id": "1922",
"chatroom_id": "17175003856897",
"title": "香山",
"desc": "随便",
"startTime": 1495777760957,
"endTime": 1495777760957,
"anchor": "sx001",
"gift_count": 0,
"praise_count": 8,
"current_user_count": 1,
"max_user_count": 3,
"status": "ongoing",
"cover_picture_url": "http://127.0.0.1:8080/easemob- ... ot%3B,
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1"
}
],
"timestamp": 1496303336669,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"cursor": "ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6NDk",
"count": 2
}












获取直播间详情:
curl -X GET -H "Authorization: Bearer [用户Token]" " https://a1.easemob.com/[应用OrgName]/[应用AppName]/[房间id]/status"
响应:
{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"liveRoomID": "1946",
"status": "ongoing"
},
"timestamp": 1496234759930,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"count": 0
}














 
使用环信直播购物小程序遇到任何问题欢迎跟帖讨论。
19
评论

【新手快速入门】集成环信常见问题+解决方案汇总 常见问题

dujiepeng 发表了文章 • 18374 次浏览 • 2017-05-22 15:51 • 来自相关话题

   这里整理了集成环信的常见问题和一些功能的实现思路,希望能帮助到大家。感谢热心的开发者贡献,大家在观看过程中有不明白的地方欢迎直接跟帖咨询。
 
ios篇
APNs证书创建和上传到环信后台头像昵称的简述和处理方案音视频离线推送Demo实现环信服务器聊天记录保存多久?离线收不到好友请求IOS中环信聊天窗口如何实现文件发送和预览的功能ios集成常见问题环信推送的一些常见问题实现名片|红包|话题聊天室等自定义cell
 
Android篇
Android sdk 的两种导入方式环信3.0SDK集成小米推送教程EaseUI库中V4、v7包冲突解决方案Android EaseUI里的百度地图替换为高德地图android扩展消息(名片集成)关于会话列表的置顶聊天java.lang.UnsatisfiedLinkError: 的问题android 端 app 后台被杀死收不到消息的解决方案
昵称头像篇
android中如何显示开发者服务器上的昵称和头像 Android中显示头像(接上一篇文章看)环信(Android)设置头像和昵称的方法(最简单暴力的基于环信demo的集成)IOS中如何显示开发者服务器上的昵称和头像【环信公开课第12期视频回放】-所有关于环信IM昵称头像的问题听这课就够了
 
直播篇
一言不合你就搞个直播APP
 
客服集成
IM-SDK和客服SDK并存开发指南—Android篇IM-SDK和客服SDK并存开发指南—iOS篇
 
开源项目
Android简版demoios简版demo凡信2.0:超仿微信的开源项目 凡信3.0:携直播和红包而来高仿微信:Github 3,515 Star方圆十里:环信编程大赛冠军项目泛聊:定一个小目标写一个QQSlack聊天机器人:一天时间做一个聊天机器人TV视频通话:在电视上视频通话视频通话:Android手机视频通话酷信:ios高仿微信公众号助手:与订阅用户聊天沟通
 
持续更新ing...小伙伴们还有什么想知道欢迎跟帖提出。
  查看全部
   这里整理了集成环信的常见问题和一些功能的实现思路,希望能帮助到大家。感谢热心的开发者贡献,大家在观看过程中有不明白的地方欢迎直接跟帖咨询。
 
ios篇

 
Android篇

昵称头像篇

 
直播篇
  1. 一言不合你就搞个直播APP

 
客服集成
  1. IM-SDK和客服SDK并存开发指南—Android篇
  2. IM-SDK和客服SDK并存开发指南—iOS篇

 
开源项目

 
持续更新ing...小伙伴们还有什么想知道欢迎跟帖提出。
 
11
回复

收集基于环信SDK开发的开源项目 开源项目

xiaoyan2015 回复了问题 • 13 人关注 • 11743 次浏览 • 2018-11-21 23:59 • 来自相关话题

19
回复

【有奖征集】环信集成文档建议收集,现金打赏! 环信

◇。 回复了问题 • 21 人关注 • 9137 次浏览 • 2016-09-06 16:09 • 来自相关话题

9
评论

【视频学习】环信视频教程 集成指南 视频 环信

fat1 发表了文章 • 24955 次浏览 • 2015-10-21 14:53 • 来自相关话题

Android_EaseUI 视频地址
 
Android_SDK 视频地址
 
OC_EaseUI 视频地址
 
OC_SDK 视频地址
 
Swift_EaseUI 视频地址
 
Swift_SDK 视频地址 查看全部
40bb20ca7b0921d79257f7bb786dd9bb.png

Android_EaseUI 视频地址
 
Android_SDK 视频地址
 
OC_EaseUI 视频地址
 
OC_SDK 视频地址
 
Swift_EaseUI 视频地址
 
Swift_SDK 视频地址
1
评论

环信CTO马晓宇:开源重燃移动IM大连接梦想 环信

oscar 发表了文章 • 3065 次浏览 • 2015-06-30 18:45 • 来自相关话题

    2014年,微信凭借着QQ得天独厚的优势牢牢把控着国内的市场,陌陌通过资本力量洗牌一骑绝尘奔赴美国纳斯达克上市,Facebook 拆资190亿美元收购WhatsApp,买下了一个未来。当人们都认为移动IM局面已经尘埃落定时,众多通过移动IM走向社交类的APP也相继拿到风投,加入了这场无法预知的战争。在2015年的今天,移动互联网将进入活跃度时代,随着人们对手机依赖感的提升,用户需求不断在变化,4G的迅速发展,移动IM又掀起一场入口争夺战。WhatsApp股东的知名风投机构红杉资本高管合伙人Aaref Hilaly曾表示,移动聊天正在重新定义社交网络,诸如Facebook等充斥陌生人关系的社交模式,已经显得没有价值。移动IM将迎来一个巨大的创新机会,无论是社交、电商、教育、甚至嵌入式领域,都可以创造一个大链接时代。

     "我们的方向是即时通信云,主要面向多端,除了现有的iOS、Android和Web端,我们实际还在做Linux嵌入式,会支持更多嵌入设备,加入IOT(物体组成的因特网)实现设备之间互联。"

    与记者谈起移动IM的发展以及环信未来的方向,作为环信CTO的马晓宇从移动通信领域的实践经验和感悟来表达了自己的看法。同时作为一个开源理想主义者,他和整个团队致力把环信逐步开源,也把开源运用在整个工作环境里面,让企业跟随着开源世界的脚步,坚定在技术路线上前进,让一切都变得美好起来。






     马晓宇,环信CTO,从事十七八年程序开发,从最早的IC设计,到后来电信短信网关程序以及网关软件的开发,先后入职Symbian和Nokia公司,从事中间件以及内核软件开发,在移动技术领域有深厚积累,可以说马晓宇伴随着中国移动互联网的成长一路走来。

    在环信项目的早期,马晓宇和其他项目的成员看到移动互联网这个大趋势,以及市场的需求,想基于BaaS平台上提供IM以及推送这样的服务,在Key-Value存储、用户体系、权限管理等方面做一套完整的BaaS平台,不过这个项目持续了半年就被终止。面对着这样的打击马晓宇和整个团队也并没有因此而停止整个项目的开发,从非理性的热烈追捧到泡沫破裂,这让他们更加认识到了整个市场用户的需求和开放性及整个生态圈的重要性。2013年底,马晓宇和他们的团队再次出发,他们把之前的项目全部回收,重新定位并聚焦一件事情,那就是即时通讯业务。

    在移动互联网依旧澎湃的今天,移动IM在整个市场的冲击下愈演愈烈。不过马晓宇认为移动IM领域仍然蕴藏着巨大的潜力,差异化的市场仍有很大的一部分用户需求。所以他们开始以平台化、入口化为重点,在满足用户的即时通讯需求外,还继续不断的纵向扩展。

    可以说2013年是马晓宇和整个团队最艰难的一年。微信、易信、飞信、来往、陌陌等等似乎已经占据了整个移动IM市场,但是移动端即时通讯应用的形式还远没有定型,用户也在不断适应和迭代,一切的确定都是充满不确定性。马晓宇和整个团队也是看到了这个市场,凭借着整个团队有着开源和移动技术背景,一步一步的把环信这个项目带入移动互联网的台面上,在成功的背后也隐藏着很多艰难的决定和方向的抉择。下面就同记者一起来了解马晓宇和环信。

    记者:您是基于什么考虑和整个团队一起研发环信这类移动IM产品?

    马晓宇:我们环信这个项目从2013年初开始,当时我们看到移动互联网这个大趋势和需求,最早想做一个BaaS平台(后端即服务:Backend as a Service),提供一部分的IM功能,当时也搭建了一个推送功能,加入Key-Value存储,用户体系,权限管理等功能,最终想做一套比较全的BaaS平台,大概有半年多的时间,发现这个项目有一个很大的难度。

     主要问题是BaaS对中小开发者很好,不需要有自己的后台,很容易跑起来。但是如果你的业务发展,很难满足个性化的需求定制。实际上在2013年底我们就讨论这个事情,BaaS这个平台基本解决不了用户的个性化需求,所以后来我们就回收了这个项目,然后聚焦做一件事情---也就是现在IM即时通讯。从2013年底我们就重新定位,开始专注即时通讯业务,产品真正上线是在2014年的年中,6月份正式上线。






环信后台架构图

    记者:在2012年大家开始提及到BaaS平台,2013年在移动互联网上就有越来越多的人在谈整合BaaS服务,您认为在BaaS服务上比较适合做些什么?

    马晓宇:它对中小开发团队特别有效。如果你做移动APP开发,首先要有你的用户系统,还有Key-Value数据存储。然后了解推送社交,甚至朋友圈模块,发现很容易地搭建一套这种APP。

    但是用户有什么需求就不好解决,Key-Value即使能存储不同数据,从用户权限管需求这一块就不好办。因为有些应用,比如说只能是领导的秘书可以有一个特定的权限。所以真正到企业级的移动应用,我觉得就比较难做进一步的扩展。我们做了一年这个BaaS平台。

    记者:后面有没有继续?

    马晓宇:没有,不过我们做BaaS平台的这个团队都有科研背景,我们选了Usergrid Apache这顶级的开源项目,同时我们的主要创始人也是Usergrid Committer,通过技术的演变,基于Usergrid开发环信的用户系统。

    记者:据了解你们团队很多高管都有着一些重要的开源项目背景,像Jboss和Hibernate这类顶级的开源项目中也有着丰富的经验,而环信这样的平台大部分的用户都是开发者,而您以及整个团队从某个角度来讲也算是自己产品的用户,也是直接最懂自己用户的。那么您认为最能够让开发者接受的产品最重要的是什么?

    马晓宇:对,首先我们用环信,同时我们也用其他的开发者工具,从统计到一些分析、监控、推送,我们自身觉得比较重要的还是服务。包括我们以前做开源社区,有时候也在一些兄弟公司QQ群里看看,基本上环信是唯一一个每天晚上两三点开发者能找到主要技术人员给你回复,我们在服务商还是获得了很好的评价,这也是我们现在能赢得开发者的认可。

    记者:从开源的角度看,环信把即时通信云的SDK代码开源了,这对于开发者来说是非常有利部署自己的应用,从这方面我们能够看出环信对开源的态度。请谈谈你们是如何看待开源?以及接下来的开源计划是怎样的?

    马晓宇:首先我们是逐步开源的,包括我们的后台。因为我们最终不是靠这个CODE本身,毕竟即时通讯现在都快做成免费市场了,所以我们最终还是要靠服务来赢得市场。

    还有一个,我们其实做开源的时间也比较长,利用这个机会做环信也是想做一些尝试,也一直在推动。我们是希望做环信能做到三个成功。

    第一个是商业成功,首先是产品有价值,我们做的是toD面向开发者和面向企业SAAS服务,最后我们是能有收入,能有一个合理的利润,能够商业成功。

    第二个是技术成功。我们本身的技术栈用到的不光是我们自己研发的技术,同时我们也用了大量的优秀开源软件,从中间件到数据库大多数都是来自国外的。我们在解决移动终端和服务器之间的这种消费程度,或者是跨平台部署。所以我们是希望我们的一个目标,技术成功的目标是说,我们找一个important的问题,然后做一个方案,作为我们商业产品的一部分,同时我们把它进行开源,吸引用户来使用,这也是整个团队需要长期要做的事情。

    第三个是团队成功。我们团队有一部分都是从事过开源项目背景,比较向往开源企业的文化和情怀。这个团队成功最好理解,就是说比如我们有同事家在海南,他就可以在海南工作,拿北京的工资,然后隔几个月来一起开会。

    我们也开始逐渐尝试,在过完年后有一个同事在泰国工作了一星期,然后回来跟我们分享。这样的结果我们认为还是比较靠谱的,在自己比较向往或者熟悉的地方工作效率完全不一样,思路特别清晰。所以我们是希望在商业公司也实现一些开源的企业文化。

    记者:目前市场上即时通信类的产品很多,我个人认为还都比较成熟,但是当技术发展到一定程度的时候,用户往往不会再关注到底技术哪家强,更多的是取决于产品体验以及服务态度。在这方面,您认为环信从哪些方面更能够体现出来?

    马晓宇:现在是三方面,一方面还是服务进一步深化,我觉得接入环信平台,提供IM只是第一步,我们现在专门有一个CSM(Cluster System Management 专门用于集群系统管理的中间件),帮助我们的客户成功。通过第一步的发消息到头像、位置、分级、互动、推送等等提高它的活跃度,让用户真正玩起来。所以我们专门有这么一个团队开始组建,帮助这些比较大的APP真正去分析用户指标,通过我们的数据怎么去帮助他们更多的互动,这是我们叫客户成功。

    第二步其实大家也在做了,就是做数据挖掘,挖掘用户的行为实际上对APP是非常有利的。比如,我们有一个用户是猎聘网,可以通过挖掘用户和露猎头在上面的一些行为关键词进行分析,根据这些数据去指导他的业务。

    第三步就是我们现在逐渐感到有一定用户量后,即时通讯需要保持一个长连接,所以这是有一定费用的。我认为成本优势也是一个优势,企业真正做到百万用户后,每月运维成本可能是几万。但是如果环信能经过优化,提供一半或者四分之一的价格,对企业来讲是挺大一笔费用。

    所以总结一下,第一个是我们的客户成功,第二个是数据挖掘,第三个是成本优势。目前客户成功和数据挖掘我们都启动,成本优势我们还在继续优化过程中,下一步主要是在技术上,我们要把成本给优化下来。

    记者:环信是基于PaaS平台去做的,而像这样的产品也很多,但是真正的提高核心竞争力我认为还是要加强自己的生态圈建设,在不断的收集用户的需求以及痛点并及时解决,完善和壮大自己的产品,在这方面你们是如何建设的呢?

    马晓宇:现在我们是分三层,第一层是我们所有的用户,就是环信的直接用户。

    第二层是我们有一个QQ群的形式,一个QQ群有2000人。我们有五个群,现在建了第六个群。然后在这个基础上,我们有一些基于环信的核心开发者,他们会给我们做demo,或者真正地提交了一个完全开源的APP,就是基于环信的。

    第三层是我们和一些合作伙伴做的一些探索,专门做个IM Geek开源社区,作为我们整个生态圈的核心部分。

    记者:从微信、飞信、易信这些即时通信软件到即时通信云平台,从只需要服务自己一家产品到要服务于成千上万家不同的APP产品,她们的需求也是不一样的,从系统设计和运维的角度,你们如何保证他们的稳定性以及安全性?
   
    马晓宇:不太一样,因为我们是做多租户APP平台,每个APP有不同的需求,所以我们现在是有一个基于APP一些参数可以动态的,这是一部分。

    还有一部分是因为多租户,所以我们对数据安全比较看重。我们参与运维项目主要是用户体系比较好,提供了最基本的用户隔离和安全,完全做好用户访问其他APP信息的隔离。

    另外从运维层面上,平台上运维用户数据比较关键,系统内部规定只有两人有权限,真正登陆以后是能够看到用户。

    还有一部分是大家做云端要解决的一个共享问题,也就是公有云。怎么能保证所有用户体验在操作上不影响其他的用户。最基本的接口有限流,服务器端提供调用接口,可以给你的客户发消息,可以创建群组,可以做用户管理,但这个是有限流的,不能无限制地发,超过限流就会反馈错误。

    最后是队列设计。避免有些APP大量给用户发消息,影响其他用户,所以在系统的这些队列设计上,我们也考虑到让APP尽量隔离。现在我们有高速、低速两条通道,如果发现有大量的信息时就会走到低速队列,我们尽量保持用户体验。

    记者:从近两年来看,我们都能够感觉到移动互联网都是呈现爆发式增长,还有从今年春节我们也看到了大家都比较倾向通过IM通信这种方式拜年,交流,IM通信功能也会被广泛应用在其他的APP当中,面对这种趋势,我们在这方面如何去保证高稳定性及高并发这种情况?还有应急措施有哪些?

    马晓宇:我们会有相应的措施,像您说春节期间的突发状况,我们主要技术人员和运维在春节期间都没怎么休息,就是为了保证整个系统正常运转。首先我们的架构比较好,在后面的数据库、服务器,如果有系统瓶颈的话,我们能够及时加机器。现在我们加机器用的是云,不需要到机房去搭建,基本我们现在做到在分钟级就能够配好整个架构集群。

    真正线上我们有标准的监控,通过购买第三方服务监控全国各地到我们服务器的访问情况。对比系统的指标,比如登陆整个集群时间,登陆每台服务器的时间,监控发消息的整个过程时间。然后监控数据库系统的主要的队列,当发现有队列堆积,我们会及时进一步处理。

    同时我们也监控DB,主要是DB负载,整个系统是自动化的,有问题会报警,防患于未然。然后如果是真出了紧急情况,在系统里有一些降级开关,如果有紧急情况,保证最小可用。所以现在我们的系统设计,在关键模块是有降级开关的,那么降级开关实际上是要运维,我们每个月有一次演习,比如说我们的缓存宕机,整个储存都宕机,如何做到进一步重新加载数据。还有一些没有出现过的情况,假如数据库宕机,如何切换成直接写到log文件,再把log重新导到数据库恢复。

    记者:我们都知道2月27日工信部正式向中国电信和中国联通发放了FDD制式4G牌照,这也意味着移动音频和视频的时代到来了,我认为提高这方面的技术支持给开发者更好的体验将是突破竞争门槛的重要突破点,你们将如何面对这个浪潮?

    马晓宇:我们今年上半年主要的开发方向就是将音视频产品化,现在iOS和安卓都支持实时语音,而且可以互通,但是实时视频只有Android支持,iOS系统在今年4月初我们也会出支持实时视频的release版本, 有开发者基于我们视频SDK,做一些视频交流,这也是4G带宽的优势,把之前的不可能变成为可能。

    另外除了我们基础功能之外,我们还深入研究,在一对一语音接通率进行优化。大家在Wifi下,中间要跨防火墙,所以有接通率,我们现在在改进这一块。还有在4G网络下,当网络不稳定或弱网络的情况下,我们也做了优化。通过优化对音视频掉包补偿算法,在标准算法的基础上再做进一步优化。

    现在看到了很多机会,很多APP开始集成视频功能。包括我们一个合作伙伴,基于我们多人语音开始做智能的导航设备。通过定位,基于4G加入频道通话。现在实验是在3G网,但在使用上设备绑定是4G卡,基于云端。

    记者:还是要看未来终端的发展,兼容性好的话可以往上发力。从即时通信产品的多样化来看,环信还是显得比较单一,是做“专”还是做“全”,环信在未来将有哪样的布局?

    马晓宇:首先我们的方向是即时通信云,主要面向多端,除了现有的iOS、Android和Web端,我们实际还在做Linux嵌入式,会支持更多嵌入设备,加入IOT(物体组成的因特网)实现设备之间互联。现在很多巨头都在定标准,我们目前只提供SDK,让设备之间互联。

    同时,我们从去年年底基于即时通讯提供SaaS服务,它能提供移动应用实时客服,这和以前的呼叫中心不太一样,我们围绕的客户是一些移动应用,进入APP后点击帮助就可以通过IM技术和后台的客服沟通,给你提供帮助。 查看全部
    2014年,微信凭借着QQ得天独厚的优势牢牢把控着国内的市场,陌陌通过资本力量洗牌一骑绝尘奔赴美国纳斯达克上市,Facebook 拆资190亿美元收购WhatsApp,买下了一个未来。当人们都认为移动IM局面已经尘埃落定时,众多通过移动IM走向社交类的APP也相继拿到风投,加入了这场无法预知的战争。在2015年的今天,移动互联网将进入活跃度时代,随着人们对手机依赖感的提升,用户需求不断在变化,4G的迅速发展,移动IM又掀起一场入口争夺战。WhatsApp股东的知名风投机构红杉资本高管合伙人Aaref Hilaly曾表示,移动聊天正在重新定义社交网络,诸如Facebook等充斥陌生人关系的社交模式,已经显得没有价值。移动IM将迎来一个巨大的创新机会,无论是社交、电商、教育、甚至嵌入式领域,都可以创造一个大链接时代。

     "我们的方向是即时通信云,主要面向多端,除了现有的iOS、Android和Web端,我们实际还在做Linux嵌入式,会支持更多嵌入设备,加入IOT(物体组成的因特网)实现设备之间互联。"

    与记者谈起移动IM的发展以及环信未来的方向,作为环信CTO的马晓宇从移动通信领域的实践经验和感悟来表达了自己的看法。同时作为一个开源理想主义者,他和整个团队致力把环信逐步开源,也把开源运用在整个工作环境里面,让企业跟随着开源世界的脚步,坚定在技术路线上前进,让一切都变得美好起来。

wKiom1UYNwDCJmxQAACwdgCMSuw087.jpg


     马晓宇,环信CTO,从事十七八年程序开发,从最早的IC设计,到后来电信短信网关程序以及网关软件的开发,先后入职Symbian和Nokia公司,从事中间件以及内核软件开发,在移动技术领域有深厚积累,可以说马晓宇伴随着中国移动互联网的成长一路走来。

    在环信项目的早期,马晓宇和其他项目的成员看到移动互联网这个大趋势,以及市场的需求,想基于BaaS平台上提供IM以及推送这样的服务,在Key-Value存储、用户体系、权限管理等方面做一套完整的BaaS平台,不过这个项目持续了半年就被终止。面对着这样的打击马晓宇和整个团队也并没有因此而停止整个项目的开发,从非理性的热烈追捧到泡沫破裂,这让他们更加认识到了整个市场用户的需求和开放性及整个生态圈的重要性。2013年底,马晓宇和他们的团队再次出发,他们把之前的项目全部回收,重新定位并聚焦一件事情,那就是即时通讯业务。

    在移动互联网依旧澎湃的今天,移动IM在整个市场的冲击下愈演愈烈。不过马晓宇认为移动IM领域仍然蕴藏着巨大的潜力,差异化的市场仍有很大的一部分用户需求。所以他们开始以平台化、入口化为重点,在满足用户的即时通讯需求外,还继续不断的纵向扩展。

    可以说2013年是马晓宇和整个团队最艰难的一年。微信、易信、飞信、来往、陌陌等等似乎已经占据了整个移动IM市场,但是移动端即时通讯应用的形式还远没有定型,用户也在不断适应和迭代,一切的确定都是充满不确定性。马晓宇和整个团队也是看到了这个市场,凭借着整个团队有着开源和移动技术背景,一步一步的把环信这个项目带入移动互联网的台面上,在成功的背后也隐藏着很多艰难的决定和方向的抉择。下面就同记者一起来了解马晓宇和环信。

    记者:您是基于什么考虑和整个团队一起研发环信这类移动IM产品?

    马晓宇:我们环信这个项目从2013年初开始,当时我们看到移动互联网这个大趋势和需求,最早想做一个BaaS平台(后端即服务:Backend as a Service),提供一部分的IM功能,当时也搭建了一个推送功能,加入Key-Value存储,用户体系,权限管理等功能,最终想做一套比较全的BaaS平台,大概有半年多的时间,发现这个项目有一个很大的难度。

     主要问题是BaaS对中小开发者很好,不需要有自己的后台,很容易跑起来。但是如果你的业务发展,很难满足个性化的需求定制。实际上在2013年底我们就讨论这个事情,BaaS这个平台基本解决不了用户的个性化需求,所以后来我们就回收了这个项目,然后聚焦做一件事情---也就是现在IM即时通讯。从2013年底我们就重新定位,开始专注即时通讯业务,产品真正上线是在2014年的年中,6月份正式上线。

wKioL1UYOGPjYE2ZAADuoQziNd0748.jpg


环信后台架构图

    记者:在2012年大家开始提及到BaaS平台,2013年在移动互联网上就有越来越多的人在谈整合BaaS服务,您认为在BaaS服务上比较适合做些什么?

    马晓宇:它对中小开发团队特别有效。如果你做移动APP开发,首先要有你的用户系统,还有Key-Value数据存储。然后了解推送社交,甚至朋友圈模块,发现很容易地搭建一套这种APP。

    但是用户有什么需求就不好解决,Key-Value即使能存储不同数据,从用户权限管需求这一块就不好办。因为有些应用,比如说只能是领导的秘书可以有一个特定的权限。所以真正到企业级的移动应用,我觉得就比较难做进一步的扩展。我们做了一年这个BaaS平台。

    记者:后面有没有继续?

    马晓宇:没有,不过我们做BaaS平台的这个团队都有科研背景,我们选了Usergrid Apache这顶级的开源项目,同时我们的主要创始人也是Usergrid Committer,通过技术的演变,基于Usergrid开发环信的用户系统。

    记者:据了解你们团队很多高管都有着一些重要的开源项目背景,像Jboss和Hibernate这类顶级的开源项目中也有着丰富的经验,而环信这样的平台大部分的用户都是开发者,而您以及整个团队从某个角度来讲也算是自己产品的用户,也是直接最懂自己用户的。那么您认为最能够让开发者接受的产品最重要的是什么?

    马晓宇:对,首先我们用环信,同时我们也用其他的开发者工具,从统计到一些分析、监控、推送,我们自身觉得比较重要的还是服务。包括我们以前做开源社区,有时候也在一些兄弟公司QQ群里看看,基本上环信是唯一一个每天晚上两三点开发者能找到主要技术人员给你回复,我们在服务商还是获得了很好的评价,这也是我们现在能赢得开发者的认可。

    记者:从开源的角度看,环信把即时通信云的SDK代码开源了,这对于开发者来说是非常有利部署自己的应用,从这方面我们能够看出环信对开源的态度。请谈谈你们是如何看待开源?以及接下来的开源计划是怎样的?

    马晓宇:首先我们是逐步开源的,包括我们的后台。因为我们最终不是靠这个CODE本身,毕竟即时通讯现在都快做成免费市场了,所以我们最终还是要靠服务来赢得市场。

    还有一个,我们其实做开源的时间也比较长,利用这个机会做环信也是想做一些尝试,也一直在推动。我们是希望做环信能做到三个成功。

    第一个是商业成功,首先是产品有价值,我们做的是toD面向开发者和面向企业SAAS服务,最后我们是能有收入,能有一个合理的利润,能够商业成功。

    第二个是技术成功。我们本身的技术栈用到的不光是我们自己研发的技术,同时我们也用了大量的优秀开源软件,从中间件到数据库大多数都是来自国外的。我们在解决移动终端和服务器之间的这种消费程度,或者是跨平台部署。所以我们是希望我们的一个目标,技术成功的目标是说,我们找一个important的问题,然后做一个方案,作为我们商业产品的一部分,同时我们把它进行开源,吸引用户来使用,这也是整个团队需要长期要做的事情。

    第三个是团队成功。我们团队有一部分都是从事过开源项目背景,比较向往开源企业的文化和情怀。这个团队成功最好理解,就是说比如我们有同事家在海南,他就可以在海南工作,拿北京的工资,然后隔几个月来一起开会。

    我们也开始逐渐尝试,在过完年后有一个同事在泰国工作了一星期,然后回来跟我们分享。这样的结果我们认为还是比较靠谱的,在自己比较向往或者熟悉的地方工作效率完全不一样,思路特别清晰。所以我们是希望在商业公司也实现一些开源的企业文化。

    记者:目前市场上即时通信类的产品很多,我个人认为还都比较成熟,但是当技术发展到一定程度的时候,用户往往不会再关注到底技术哪家强,更多的是取决于产品体验以及服务态度。在这方面,您认为环信从哪些方面更能够体现出来?

    马晓宇:现在是三方面,一方面还是服务进一步深化,我觉得接入环信平台,提供IM只是第一步,我们现在专门有一个CSM(Cluster System Management 专门用于集群系统管理的中间件),帮助我们的客户成功。通过第一步的发消息到头像、位置、分级、互动、推送等等提高它的活跃度,让用户真正玩起来。所以我们专门有这么一个团队开始组建,帮助这些比较大的APP真正去分析用户指标,通过我们的数据怎么去帮助他们更多的互动,这是我们叫客户成功。

    第二步其实大家也在做了,就是做数据挖掘,挖掘用户的行为实际上对APP是非常有利的。比如,我们有一个用户是猎聘网,可以通过挖掘用户和露猎头在上面的一些行为关键词进行分析,根据这些数据去指导他的业务。

    第三步就是我们现在逐渐感到有一定用户量后,即时通讯需要保持一个长连接,所以这是有一定费用的。我认为成本优势也是一个优势,企业真正做到百万用户后,每月运维成本可能是几万。但是如果环信能经过优化,提供一半或者四分之一的价格,对企业来讲是挺大一笔费用。

    所以总结一下,第一个是我们的客户成功,第二个是数据挖掘,第三个是成本优势。目前客户成功和数据挖掘我们都启动,成本优势我们还在继续优化过程中,下一步主要是在技术上,我们要把成本给优化下来。

    记者:环信是基于PaaS平台去做的,而像这样的产品也很多,但是真正的提高核心竞争力我认为还是要加强自己的生态圈建设,在不断的收集用户的需求以及痛点并及时解决,完善和壮大自己的产品,在这方面你们是如何建设的呢?

    马晓宇:现在我们是分三层,第一层是我们所有的用户,就是环信的直接用户。

    第二层是我们有一个QQ群的形式,一个QQ群有2000人。我们有五个群,现在建了第六个群。然后在这个基础上,我们有一些基于环信的核心开发者,他们会给我们做demo,或者真正地提交了一个完全开源的APP,就是基于环信的。

    第三层是我们和一些合作伙伴做的一些探索,专门做个IM Geek开源社区,作为我们整个生态圈的核心部分。

    记者:从微信、飞信、易信这些即时通信软件到即时通信云平台,从只需要服务自己一家产品到要服务于成千上万家不同的APP产品,她们的需求也是不一样的,从系统设计和运维的角度,你们如何保证他们的稳定性以及安全性?
   
    马晓宇:不太一样,因为我们是做多租户APP平台,每个APP有不同的需求,所以我们现在是有一个基于APP一些参数可以动态的,这是一部分。

    还有一部分是因为多租户,所以我们对数据安全比较看重。我们参与运维项目主要是用户体系比较好,提供了最基本的用户隔离和安全,完全做好用户访问其他APP信息的隔离。

    另外从运维层面上,平台上运维用户数据比较关键,系统内部规定只有两人有权限,真正登陆以后是能够看到用户。

    还有一部分是大家做云端要解决的一个共享问题,也就是公有云。怎么能保证所有用户体验在操作上不影响其他的用户。最基本的接口有限流,服务器端提供调用接口,可以给你的客户发消息,可以创建群组,可以做用户管理,但这个是有限流的,不能无限制地发,超过限流就会反馈错误。

    最后是队列设计。避免有些APP大量给用户发消息,影响其他用户,所以在系统的这些队列设计上,我们也考虑到让APP尽量隔离。现在我们有高速、低速两条通道,如果发现有大量的信息时就会走到低速队列,我们尽量保持用户体验。

    记者:从近两年来看,我们都能够感觉到移动互联网都是呈现爆发式增长,还有从今年春节我们也看到了大家都比较倾向通过IM通信这种方式拜年,交流,IM通信功能也会被广泛应用在其他的APP当中,面对这种趋势,我们在这方面如何去保证高稳定性及高并发这种情况?还有应急措施有哪些?

    马晓宇:我们会有相应的措施,像您说春节期间的突发状况,我们主要技术人员和运维在春节期间都没怎么休息,就是为了保证整个系统正常运转。首先我们的架构比较好,在后面的数据库、服务器,如果有系统瓶颈的话,我们能够及时加机器。现在我们加机器用的是云,不需要到机房去搭建,基本我们现在做到在分钟级就能够配好整个架构集群。

    真正线上我们有标准的监控,通过购买第三方服务监控全国各地到我们服务器的访问情况。对比系统的指标,比如登陆整个集群时间,登陆每台服务器的时间,监控发消息的整个过程时间。然后监控数据库系统的主要的队列,当发现有队列堆积,我们会及时进一步处理。

    同时我们也监控DB,主要是DB负载,整个系统是自动化的,有问题会报警,防患于未然。然后如果是真出了紧急情况,在系统里有一些降级开关,如果有紧急情况,保证最小可用。所以现在我们的系统设计,在关键模块是有降级开关的,那么降级开关实际上是要运维,我们每个月有一次演习,比如说我们的缓存宕机,整个储存都宕机,如何做到进一步重新加载数据。还有一些没有出现过的情况,假如数据库宕机,如何切换成直接写到log文件,再把log重新导到数据库恢复。

    记者:我们都知道2月27日工信部正式向中国电信和中国联通发放了FDD制式4G牌照,这也意味着移动音频和视频的时代到来了,我认为提高这方面的技术支持给开发者更好的体验将是突破竞争门槛的重要突破点,你们将如何面对这个浪潮?

    马晓宇:我们今年上半年主要的开发方向就是将音视频产品化,现在iOS和安卓都支持实时语音,而且可以互通,但是实时视频只有Android支持,iOS系统在今年4月初我们也会出支持实时视频的release版本, 有开发者基于我们视频SDK,做一些视频交流,这也是4G带宽的优势,把之前的不可能变成为可能。

    另外除了我们基础功能之外,我们还深入研究,在一对一语音接通率进行优化。大家在Wifi下,中间要跨防火墙,所以有接通率,我们现在在改进这一块。还有在4G网络下,当网络不稳定或弱网络的情况下,我们也做了优化。通过优化对音视频掉包补偿算法,在标准算法的基础上再做进一步优化。

    现在看到了很多机会,很多APP开始集成视频功能。包括我们一个合作伙伴,基于我们多人语音开始做智能的导航设备。通过定位,基于4G加入频道通话。现在实验是在3G网,但在使用上设备绑定是4G卡,基于云端。

    记者:还是要看未来终端的发展,兼容性好的话可以往上发力。从即时通信产品的多样化来看,环信还是显得比较单一,是做“专”还是做“全”,环信在未来将有哪样的布局?

    马晓宇:首先我们的方向是即时通信云,主要面向多端,除了现有的iOS、Android和Web端,我们实际还在做Linux嵌入式,会支持更多嵌入设备,加入IOT(物体组成的因特网)实现设备之间互联。现在很多巨头都在定标准,我们目前只提供SDK,让设备之间互联。

    同时,我们从去年年底基于即时通讯提供SaaS服务,它能提供移动应用实时客服,这和以前的呼叫中心不太一样,我们围绕的客户是一些移动应用,进入APP后点击帮助就可以通过IM技术和后台的客服沟通,给你提供帮助。
0
评论

【活动推荐】ECUG Con 2018 拥抱下一个十年 ECUG Con 2018 许式伟 ECUG 七牛云

beyond 发表了文章 • 91 次浏览 • 2018-12-03 15:47 • 来自相关话题

国内云计算领域大咖 许式伟
倾情发起的技术盛宴
引领国内云领域风向的高端峰会
ECUG Con 2018
2018 年 12 月 22-23 日 深圳
全新启程!ECUG Con 2018

七牛云 CEO 许式伟

PingCAP CEO 刘奇

七牛云产品副总裁戴文军

Gopher 社区创始人 Asta Xie

阿里巴巴技术专家孙宏亮

《Kubernetes IN ACTION》作者 Marko Lukša

华为云 AI 推理平台&云搜索技术总监胡斐然

七牛云技术总监陈超

阿里云高级开发工程师严明明

京东云区块链实验室与数据库部负责人郭里靖

网易研究院云计算资深架构师朱剑峰

腾讯云高级工程师刘兆瑞

货拉拉数据分析负责人高遥

......
超豪华讲师阵容!

超有料精彩分享!

ECUG 历经十年蜕变

邀您共同开启下个十年

让我们坚持技术情怀,秉承技术精神

开启新的云计算布道篇章!
 
时  间

2018 年 12 月 22-23 日

地  点

深圳市南山区软件产业基地 

更多详情请见下方海报~




扫描上方二维码 ,立即购买早鸟票

与大咖讲师共同探索云计算的下一个十年!
活动详情:了解更多 查看全部
国内云计算领域大咖  许式伟 
倾情发起的技术盛宴
引领国内云领域风向的高端峰会
ECUG Con 2018
2018 年 12 月 22-23 日 深圳
全新启程!
ECUG Con 2018

七牛云 CEO 许式伟

PingCAP CEO 刘奇

七牛云产品副总裁戴文军

Gopher 社区创始人 Asta Xie

阿里巴巴技术专家孙宏亮

《Kubernetes IN ACTION》作者 Marko Lukša

华为云 AI 推理平台&云搜索技术总监胡斐然

七牛云技术总监陈超

阿里云高级开发工程师严明明

京东云区块链实验室与数据库部负责人郭里靖

网易研究院云计算资深架构师朱剑峰

腾讯云高级工程师刘兆瑞

货拉拉数据分析负责人高遥

......
超豪华讲师阵容!

超有料精彩分享!

ECUG 历经十年蜕变

邀您共同开启下个十年

让我们坚持技术情怀,秉承技术精神

开启新的云计算布道篇章!
 
时  间

2018 年 12 月 22-23 日

地  点

深圳市南山区软件产业基地 

更多详情请见下方海报~
30943258454939062.jpg

扫描上方二维码 ,立即购买早鸟票

与大咖讲师共同探索云计算的下一个十年!
活动详情:了解更多
0
评论

【我最喜爱的 Cloud Studio 插件评选大赛】终于开始了! Cloud Studio Cloud Studio 插件评选大赛 腾讯云开发者平台 coding 编程大赛

beyond 发表了文章 • 146 次浏览 • 2018-11-26 15:37 • 来自相关话题

由 环信、腾讯云和 CODING 共同举办的 我最喜爱的 Cloud Studio 插件评选大赛正式开始了!在这场比赛里,将会有技术上的碰撞,大牛评委的专业点评,愉快的技术交流,好玩的插件尝试。





参赛者可以围绕 Git、实用小工具、腾讯云产品对接、UI 强化、语言支持等 14 个主题提交插件,再加上最具娱乐奖,代码最简单奖,设置功能最复杂奖等;近 30 种奖项,超高中奖率;插件只要提交上架,就有 50 元的话费相赠;只要关注 CODING 公众号并转发活动讯息到朋友圈,即可获得手机充值小礼!

参与方式

注册并登陆腾讯云开发者平台(https://dev.tencent.com) -> 点击进入活动页面 -> 点击进行插件的编写与提交(需要选择参与评选的类别)-> 审核无误后即可上架自动参与评选。

赛程时间




 
环信特别奖




基于环信开发一款聊天插件,即有机会获得特别奖,根据作品还将获得环信提供的神秘奖品
更多活动信息,请浏览我们的活动页面。

进入活动页面> 查看全部

2.jpg


由 环信、腾讯云和 CODING 共同举办的 我最喜爱的 Cloud Studio 插件评选大赛正式开始了!在这场比赛里,将会有技术上的碰撞,大牛评委的专业点评,愉快的技术交流,好玩的插件尝试。

6ccda21fgy1fxeim29mncj20ik0e6dn4.jpg

  • 参赛者可以围绕 Git、实用小工具、腾讯云产品对接、UI 强化、语言支持等 14 个主题提交插件,再加上最具娱乐奖,代码最简单奖,设置功能最复杂奖等;
  • 近 30 种奖项,超高中奖率;
  • 插件只要提交上架,就有 50 元的话费相赠;
  • 只要关注 CODING 公众号并转发活动讯息到朋友圈,即可获得手机充值小礼!


参与方式

注册并登陆腾讯云开发者平台https://dev.tencent.com) -> 点击进入活动页面 -> 点击进行插件的编写与提交(需要选择参与评选的类别)-> 审核无误后即可上架自动参与评选。

赛程时间
6ccda21fly1fxejmnr8oej20ow03odfy.jpg

 
环信特别奖
tb16@2x.png

基于环信开发一款聊天插件,即有机会获得特别奖,根据作品还将获得环信提供的神秘奖品
更多活动信息,请浏览我们的活动页面。

进入活动页面>
11
回复

收集基于环信SDK开发的开源项目 开源项目

回复

xiaoyan2015 回复了问题 • 13 人关注 • 11743 次浏览 • 2018-11-21 23:59 • 来自相关话题

4
评论

【开源项目】全国首个开源直播小程序源码 环信公开课 小程序 直播

beyond 发表了文章 • 4077 次浏览 • 2018-07-20 17:30 • 来自相关话题

今天你看直播了吗?拥有10亿微信生态用户的小程序已经成为了继移动互联后的又一个现象级风口,随着微信小程序对外开放实时音视频录制及播放等更多连接能力,小程序与直播强强联合,在各行各业找到了非常多的玩法,小程序直播相比微信直播和APP直播更加简洁、流畅、低延时、多入口等众多优势迅速向商业直播领域及泛娱乐直播领域蔓延。从小游戏、内容付费、工具、大数据、社交电商创业者到传统品牌商们,都在努力搭上小程序直播这辆快车,以免错过微信生态里新的流量洼地。
 





作为一名环信生态圈资深开发者,本着对技术的热衷,对环信的眷恋和对党的忠诚,基于环信即时通讯云写了“直播购物小程序”,目前项目源码已全部免费开放,希望对有需求的企业和开发者提供一个思路和参考。
直播购物小程序源码github地址:https://github.com/YuTongNetworkTechnology/wechat_live/tree/master 
git打不开可直接点下面链接下载


小程序直播demo_2018-06-21.zip







直播购物小程序运行预览图 
 
小程序体验指南(仅需两步):
 
1、下载微信小程序开发工具,下载地址:https://developers.weixin.qq.c ... .html 
 




2、导入源码:将附件的源码解压直接导入 







环信小程序直播技术文档
一、 使用的技术
1、 环信IM直播室。
2、 微信小程序实时音视频播放组件live-player。
3、 推流软件(obs、易推流)等推流。
4、 视频流服务器(UCLOUD、七牛、腾讯)等视频流服务器。
二、 系统使用流程。
1、 视频推流软件将视频流推到流服务器。
2、 打开视频直播demo小程序注册环信账号。
3、 进入软件直播室进行测试。
三、 技术流程及使用的SDk
1、 注册环信账号
打开https://www.easemob.com/ 环信官网,点击右上角注册按钮,选择[注册即时通讯云]




填写对相关信息进行注册





注册成功后进行登录




注:新注册用户需进行账号的认证。
2、 直播应用创建
登录成功点击应用列表选择创建应用




输入应用名称等信息
 





创建成功后点击应用进入





需要注意的是应用的OrgName 和AppName这两个是以后都需要用到的两个参数变量




3、 直播创建
1)在创建直播之前需要对应用进行设置首先需要设置应用的直播流地址
第一步获取应用管理员的Tokencurl -X POST "https://a1.easemob.com/[应用OrgName]/[应用AppName]/token" -d '{"grant_type":"client_credentials","client_id":"[应用client_id]","client_secret":"[应用] client_secret"}'返回格式{
"access_token":"YWMtWY779DgJEeS2h9OR7fw4QgAAAUmO4Qukwd9cfJSpkWHiOa7MCSk0MrkVIco",
"expires_in":5184000,
"application":"c03b3e30-046a-11e4-8ed1-5701cdaaa0e4"












第二步设置直播流地址curl -X POST -H "Authorization: Bearer [管理员Token]" " https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms/stream_url -d '{"pc_pull":"[pc拉流地址]","pc_push":"[pc推流地址]","mobile_pull":"[手机拉流地址]","mobile_push":"[手机推流地址]"}'"成功返回格式:{
"action": "post",
"application": "e1a09de0-0e03-11e7-ad8e-a1d913615409",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"pc_pull": true,
"mobile_push": true,
"mobile_pull": true,
"pc_push": true
},
"timestamp": 1494084474885,
"duration": 1,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












2)创建主播
点击IM用户





点击注册IM用户





填写用户信息





创建用户的过程同样也可以通过REST API形式进行curl -X POST -i " https://a1.easemob.com/[应用OrgName]/[应用AppName]/users" -d '{"username":"[用户名]","password":"[密码]"}'
注:应用必须为开放注册





将注册的用户添加为主播curl -X POST -H "Authorization: [管理员Token]" https://a1.easemob.com/[应用OrgName]/[应用AppName]/super_admin -d'{"superadmin":"[IM用户名]"}'返回结果示例:{
"action": "post",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"result": "success"
},
"timestamp": 1496236798886,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












3)创建直播
点击直播





点击新建房间





填写房间信息




创建房间同时也可以使用REST API形式进行详情可以查看http://docs.easemob.com/im/live/server-integration环信官方文档。
4、 小程序demo集成使用
小程序直播购物demo集成官方WebIM SDK详情请查看https://github.com/easemob/webim-weixin-xcx
Demo具体配置如下
打开demo 下sdk配置文件





修改appkey为自己应用的appkey





打开pages/live/index.js修改房间默认拉流地址及直播间房间号





四、 扩展说明
Demo中房间为固定测试房间,实际使用中应获取环信直播的房间信息及房间列表。具体如下:
获取直播间列表:curl -X GET -H "Authorization: Bearer [用户Token]" https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms?ongoing=true&limit=[获取数量]&cursor=[游标地址(不填写为充开始查询)]
响应:{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"params": {
"cursor": [
"ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6MzE"
],
"ongoing": [
"true"
],
"limit": [
"2"
]
},
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": [
{
"id": "1924",
"chatroom_id": "17177265635330",
"title": "具体了",
"desc": "就咯",
"startTime": 1495779917352,
"endTime": 1495779917352,
"anchor": "wuls",
"gift_count": 0,
"praise_count": 0,
"current_user_count": 8,
"max_user_count": 9,
"status": "ongoing",
"cover_picture_url": "",
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1"
},
{
"id": "1922",
"chatroom_id": "17175003856897",
"title": "香山",
"desc": "随便",
"startTime": 1495777760957,
"endTime": 1495777760957,
"anchor": "sx001",
"gift_count": 0,
"praise_count": 8,
"current_user_count": 1,
"max_user_count": 3,
"status": "ongoing",
"cover_picture_url": "http://127.0.0.1:8080/easemob- ... ot%3B,
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1"
}
],
"timestamp": 1496303336669,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"cursor": "ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6NDk",
"count": 2
}












获取直播间详情:curl -X GET -H "Authorization: Bearer [用户Token]" " https://a1.easemob.com/[应用OrgName]/[应用AppName]/[房间id]/status"响应:{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"liveRoomID": "1946",
"status": "ongoing"
},
"timestamp": 1496234759930,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"count": 0
}














 
使用环信直播购物小程序遇到任何问题欢迎跟帖讨论。 查看全部
今天你看直播了吗?
拥有10亿微信生态用户的小程序已经成为了继移动互联后的又一个现象级风口,随着微信小程序对外开放实时音视频录制及播放等更多连接能力,小程序与直播强强联合,在各行各业找到了非常多的玩法,小程序直播相比微信直播和APP直播更加简洁、流畅、低延时、多入口等众多优势迅速向商业直播领域及泛娱乐直播领域蔓延。从小游戏、内容付费、工具、大数据、社交电商创业者到传统品牌商们,都在努力搭上小程序直播这辆快车,以免错过微信生态里新的流量洼地。
 
微信图片_20180725162426.jpg


作为一名环信生态圈资深开发者,本着对技术的热衷,对环信的眷恋和对党的忠诚,基于环信即时通讯云写了“直播购物小程序”,目前项目源码已全部免费开放,希望对有需求的企业和开发者提供一个思路和参考。
直播购物小程序源码github地址:https://github.com/YuTongNetworkTechnology/wechat_live/tree/master 
git打不开可直接点下面链接下载



预览图.jpg

直播购物小程序运行预览图 
 
小程序体验指南(仅需两步):
 
1、下载微信小程序开发工具,下载地址:https://developers.weixin.qq.c ... .html 
 
Catch9A07(07-20-17-38-30).jpg

2、导入源码:将附件的源码解压直接导入 


Catch1C69(07-20-17-38-30).jpg


环信小程序直播技术文档
一、 使用的技术
1、 环信IM直播室。
2、 微信小程序实时音视频播放组件live-player。
3、 推流软件(obs、易推流)等推流。
4、 视频流服务器(UCLOUD、七牛、腾讯)等视频流服务器。
二、 系统使用流程。
1、 视频推流软件将视频流推到流服务器。
2、 打开视频直播demo小程序注册环信账号。
3、 进入软件直播室进行测试。
三、 技术流程及使用的SDk
1、 注册环信账号
打开https://www.easemob.com/ 环信官网,点击右上角注册按钮,选择[注册即时通讯云]
1.png

填写对相关信息进行注册

2.png

注册成功后进行登录
3.png

注:新注册用户需进行账号的认证。
2、 直播应用创建
登录成功点击应用列表选择创建应用
4.png

输入应用名称等信息
 

5.png

创建成功后点击应用进入

6.png

需要注意的是应用的OrgName 和AppName这两个是以后都需要用到的两个参数变量
7.png

3、 直播创建
1)在创建直播之前需要对应用进行设置首先需要设置应用的直播流地址
第一步获取应用管理员的Token
curl -X POST "https://a1.easemob.com/[应用OrgName]/[应用AppName]/token" -d '{"grant_type":"client_credentials","client_id":"[应用client_id]","client_secret":"[应用] client_secret"}'
返回格式
{
"access_token":"YWMtWY779DgJEeS2h9OR7fw4QgAAAUmO4Qukwd9cfJSpkWHiOa7MCSk0MrkVIco",
"expires_in":5184000,
"application":"c03b3e30-046a-11e4-8ed1-5701cdaaa0e4"












第二步设置直播流地址
curl -X POST -H "Authorization: Bearer [管理员Token]"  " https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms/stream_url -d '{"pc_pull":"[pc拉流地址]","pc_push":"[pc推流地址]","mobile_pull":"[手机拉流地址]","mobile_push":"[手机推流地址]"}'"
成功返回格式:
{
"action": "post",
"application": "e1a09de0-0e03-11e7-ad8e-a1d913615409",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"pc_pull": true,
"mobile_push": true,
"mobile_pull": true,
"pc_push": true
},
"timestamp": 1494084474885,
"duration": 1,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












2)创建主播
点击IM用户

8.png

点击注册IM用户

9.png

填写用户信息

10.png

创建用户的过程同样也可以通过REST API形式进行
curl -X POST -i " https://a1.easemob.com/[应用OrgName]/[应用AppName]/users" -d '{"username":"[用户名]","password":"[密码]"}'

注:应用必须为开放注册

11.png

将注册的用户添加为主播
curl -X POST -H "Authorization: [管理员Token]"  https://a1.easemob.com/[应用OrgName]/[应用AppName]/super_admin -d'{"superadmin":"[IM用户名]"}'
返回结果示例:
{
"action": "post",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"result": "success"
},
"timestamp": 1496236798886,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












3)创建直播
点击直播

12.png

点击新建房间

13.png

填写房间信息
14.png

创建房间同时也可以使用REST API形式进行详情可以查看http://docs.easemob.com/im/live/server-integration环信官方文档。
4、 小程序demo集成使用
小程序直播购物demo集成官方WebIM SDK详情请查看https://github.com/easemob/webim-weixin-xcx
Demo具体配置如下
打开demo 下sdk配置文件

15.png

修改appkey为自己应用的appkey

16.png

打开pages/live/index.js修改房间默认拉流地址及直播间房间号

17.png

四、 扩展说明
Demo中房间为固定测试房间,实际使用中应获取环信直播的房间信息及房间列表。具体如下:
获取直播间列表:
curl -X GET -H "Authorization: Bearer  [用户Token]"  https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms?ongoing=true&limit=[获取数量]&cursor=[游标地址(不填写为充开始查询)]

响应:
{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"params": {
"cursor": [
"ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6MzE"
],
"ongoing": [
"true"
],
"limit": [
"2"
]
},
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": [
{
"id": "1924",
"chatroom_id": "17177265635330",
"title": "具体了",
"desc": "就咯",
"startTime": 1495779917352,
"endTime": 1495779917352,
"anchor": "wuls",
"gift_count": 0,
"praise_count": 0,
"current_user_count": 8,
"max_user_count": 9,
"status": "ongoing",
"cover_picture_url": "",
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1"
},
{
"id": "1922",
"chatroom_id": "17175003856897",
"title": "香山",
"desc": "随便",
"startTime": 1495777760957,
"endTime": 1495777760957,
"anchor": "sx001",
"gift_count": 0,
"praise_count": 8,
"current_user_count": 1,
"max_user_count": 3,
"status": "ongoing",
"cover_picture_url": "http://127.0.0.1:8080/easemob- ... ot%3B,
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1"
}
],
"timestamp": 1496303336669,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"cursor": "ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6NDk",
"count": 2
}












获取直播间详情:
curl -X GET -H "Authorization: Bearer [用户Token]" " https://a1.easemob.com/[应用OrgName]/[应用AppName]/[房间id]/status"
响应:
{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"liveRoomID": "1946",
"status": "ongoing"
},
"timestamp": 1496234759930,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"count": 0
}














 
使用环信直播购物小程序遇到任何问题欢迎跟帖讨论。
19
评论

【新手快速入门】集成环信常见问题+解决方案汇总 常见问题

dujiepeng 发表了文章 • 18374 次浏览 • 2017-05-22 15:51 • 来自相关话题

   这里整理了集成环信的常见问题和一些功能的实现思路,希望能帮助到大家。感谢热心的开发者贡献,大家在观看过程中有不明白的地方欢迎直接跟帖咨询。
 
ios篇
APNs证书创建和上传到环信后台头像昵称的简述和处理方案音视频离线推送Demo实现环信服务器聊天记录保存多久?离线收不到好友请求IOS中环信聊天窗口如何实现文件发送和预览的功能ios集成常见问题环信推送的一些常见问题实现名片|红包|话题聊天室等自定义cell
 
Android篇
Android sdk 的两种导入方式环信3.0SDK集成小米推送教程EaseUI库中V4、v7包冲突解决方案Android EaseUI里的百度地图替换为高德地图android扩展消息(名片集成)关于会话列表的置顶聊天java.lang.UnsatisfiedLinkError: 的问题android 端 app 后台被杀死收不到消息的解决方案
昵称头像篇
android中如何显示开发者服务器上的昵称和头像 Android中显示头像(接上一篇文章看)环信(Android)设置头像和昵称的方法(最简单暴力的基于环信demo的集成)IOS中如何显示开发者服务器上的昵称和头像【环信公开课第12期视频回放】-所有关于环信IM昵称头像的问题听这课就够了
 
直播篇
一言不合你就搞个直播APP
 
客服集成
IM-SDK和客服SDK并存开发指南—Android篇IM-SDK和客服SDK并存开发指南—iOS篇
 
开源项目
Android简版demoios简版demo凡信2.0:超仿微信的开源项目 凡信3.0:携直播和红包而来高仿微信:Github 3,515 Star方圆十里:环信编程大赛冠军项目泛聊:定一个小目标写一个QQSlack聊天机器人:一天时间做一个聊天机器人TV视频通话:在电视上视频通话视频通话:Android手机视频通话酷信:ios高仿微信公众号助手:与订阅用户聊天沟通
 
持续更新ing...小伙伴们还有什么想知道欢迎跟帖提出。
  查看全部
   这里整理了集成环信的常见问题和一些功能的实现思路,希望能帮助到大家。感谢热心的开发者贡献,大家在观看过程中有不明白的地方欢迎直接跟帖咨询。
 
ios篇

 
Android篇

昵称头像篇

 
直播篇
  1. 一言不合你就搞个直播APP

 
客服集成
  1. IM-SDK和客服SDK并存开发指南—Android篇
  2. IM-SDK和客服SDK并存开发指南—iOS篇

 
开源项目

 
持续更新ing...小伙伴们还有什么想知道欢迎跟帖提出。
 
0
回复

Android studio导入easeui运行编译报错 Android 环信

回复

₁₉₉₃₀₄₀₇の陳小垚 发起了问题 • 1 人关注 • 453 次浏览 • 2018-09-27 22:07 • 来自相关话题

1
回复

导出聊天记录报错:Array ( [error] => apiname is invalid ) 环信集成 环信

回复

kaibisikai 回复了问题 • 2 人关注 • 1083 次浏览 • 2018-09-25 10:37 • 来自相关话题

2
回复

群成员主动退出,但是群里面获取所有成员还是能获取到已经退出的成员 环信

回复

孩子气 Rc 回复了问题 • 3 人关注 • 2091 次浏览 • 2018-08-09 15:09 • 来自相关话题

4
回复

牛逼啊,这么大个环信连做到头像和昵称保存的方法都没有 环信

回复

陈日明 回复了问题 • 2 人关注 • 577 次浏览 • 2018-08-08 10:49 • 来自相关话题

1
回复

OC_SDK集成参考视频 建议 环信 iOS

回复

beyond 回复了问题 • 2 人关注 • 418 次浏览 • 2018-07-26 10:48 • 来自相关话题

2
回复
1
回复

都添加哪些库,视频里看不清啊? 环信 iOS

回复

KevinGong 回复了问题 • 2 人关注 • 467 次浏览 • 2018-06-05 11:52 • 来自相关话题

1
回复

Could not successfully update network info during initialization这是什么原因啊? 环信 iOS

回复

驱马历长洲 回复了问题 • 2 人关注 • 5211 次浏览 • 2018-04-29 15:05 • 来自相关话题

0
回复

你们用的环信ios 稳定吗? 环信 环信_iOS

回复

tianwaifeixian 发起了问题 • 1 人关注 • 637 次浏览 • 2018-04-25 15:56 • 来自相关话题

0
回复

加载EaseUI封装的聊天页面的添加id找不到 Android 环信

回复

gorky_19 发起了问题 • 1 人关注 • 860 次浏览 • 2018-02-08 14:46 • 来自相关话题

0
回复

java.lang.IllegalArgumentException: No view found for id 0x7f07003a for fragment EaseChatFragment Android 环信

回复

gorky_19 发起了问题 • 1 人关注 • 1078 次浏览 • 2018-02-08 11:27 • 来自相关话题

2
最佳

看视频如果出现问题可以看这里 dyld: Library not loaded: @rpath/Hyphenate.framework/Hyphenate iOS 环信

回复

Rickie_Lambert 回复了问题 • 3 人关注 • 5714 次浏览 • 2017-11-27 15:51 • 来自相关话题

7
回复

【环信官方外包一个项目】利用环信IM实现一个在线白板 环信

回复

g711ab 回复了问题 • 8 人关注 • 3070 次浏览 • 2017-11-23 15:52 • 来自相关话题

1
回复

.a文件没找到 iOS 环信

回复

dujiepeng 回复了问题 • 2 人关注 • 879 次浏览 • 2017-11-06 18:24 • 来自相关话题

0
回复

环信即时通讯 Unity,为什么只有用户的name,没有对应的id呢 环信

回复

叶孤城的橙 发起了问题 • 1 人关注 • 876 次浏览 • 2017-10-24 12:11 • 来自相关话题

3
回复

环信离线推送消息自定义 离线 推送 环信 通知

回复

╰☆╮末↘ 回复了问题 • 2 人关注 • 1829 次浏览 • 2017-09-14 11:42 • 来自相关话题

0
回复

收到消息的代理回调不会执行 环信 iOS

回复

Aries 发起了问题 • 1 人关注 • 1073 次浏览 • 2017-09-12 10:28 • 来自相关话题

3
回复

环信v3,聊天室解除禁言在回调前崩溃的问题 环信 禁言

回复

XiaoMai 回复了问题 • 2 人关注 • 1455 次浏览 • 2017-08-23 14:32 • 来自相关话题

1
回复

'EMSDKFull.h' file not found iOS 环信

回复

wangyuzhang 回复了问题 • 2 人关注 • 1231 次浏览 • 2017-08-08 19:46 • 来自相关话题

1
回复

关于回话列表 怎么弄啊 环信 Android

回复

geri_yang 回复了问题 • 2 人关注 • 894 次浏览 • 2017-07-20 18:46 • 来自相关话题

1
回复

Android 会话列表只展示群组 Android 环信

回复

geri_yang 回复了问题 • 2 人关注 • 1035 次浏览 • 2017-06-21 12:49 • 来自相关话题

0
回复

android 3.0以后怎么获取自定义消息中Ext消息 环信 ext 接收消息 3.0 Android

回复

╰☆╮末↘ 发起了问题 • 1 人关注 • 857 次浏览 • 2017-06-16 10:30 • 来自相关话题

1
回复

在pct中导入EMSDKFull.h时报错 iOS 环信

回复

木云落 回复了问题 • 2 人关注 • 893 次浏览 • 2017-05-26 11:06 • 来自相关话题

3
回复

请问环信聊天室新用户进入回调怎么获取头像啊? 环信 聊天 聊天室 头像

回复

lyc110104 回复了问题 • 2 人关注 • 806 次浏览 • 2017-05-02 16:51 • 来自相关话题

1
回复

照视频添加的EaseUI库,但是运行不了 Android 环信

回复

zhoumin 回复了问题 • 2 人关注 • 930 次浏览 • 2017-04-20 10:26 • 来自相关话题

0
评论

【活动推荐】ECUG Con 2018 拥抱下一个十年 ECUG Con 2018 许式伟 ECUG 七牛云

beyond 发表了文章 • 91 次浏览 • 2018-12-03 15:47 • 来自相关话题

国内云计算领域大咖 许式伟
倾情发起的技术盛宴
引领国内云领域风向的高端峰会
ECUG Con 2018
2018 年 12 月 22-23 日 深圳
全新启程!ECUG Con 2018

七牛云 CEO 许式伟

PingCAP CEO 刘奇

七牛云产品副总裁戴文军

Gopher 社区创始人 Asta Xie

阿里巴巴技术专家孙宏亮

《Kubernetes IN ACTION》作者 Marko Lukša

华为云 AI 推理平台&云搜索技术总监胡斐然

七牛云技术总监陈超

阿里云高级开发工程师严明明

京东云区块链实验室与数据库部负责人郭里靖

网易研究院云计算资深架构师朱剑峰

腾讯云高级工程师刘兆瑞

货拉拉数据分析负责人高遥

......
超豪华讲师阵容!

超有料精彩分享!

ECUG 历经十年蜕变

邀您共同开启下个十年

让我们坚持技术情怀,秉承技术精神

开启新的云计算布道篇章!
 
时  间

2018 年 12 月 22-23 日

地  点

深圳市南山区软件产业基地 

更多详情请见下方海报~




扫描上方二维码 ,立即购买早鸟票

与大咖讲师共同探索云计算的下一个十年!
活动详情:了解更多 查看全部
国内云计算领域大咖  许式伟 
倾情发起的技术盛宴
引领国内云领域风向的高端峰会
ECUG Con 2018
2018 年 12 月 22-23 日 深圳
全新启程!
ECUG Con 2018

七牛云 CEO 许式伟

PingCAP CEO 刘奇

七牛云产品副总裁戴文军

Gopher 社区创始人 Asta Xie

阿里巴巴技术专家孙宏亮

《Kubernetes IN ACTION》作者 Marko Lukša

华为云 AI 推理平台&云搜索技术总监胡斐然

七牛云技术总监陈超

阿里云高级开发工程师严明明

京东云区块链实验室与数据库部负责人郭里靖

网易研究院云计算资深架构师朱剑峰

腾讯云高级工程师刘兆瑞

货拉拉数据分析负责人高遥

......
超豪华讲师阵容!

超有料精彩分享!

ECUG 历经十年蜕变

邀您共同开启下个十年

让我们坚持技术情怀,秉承技术精神

开启新的云计算布道篇章!
 
时  间

2018 年 12 月 22-23 日

地  点

深圳市南山区软件产业基地 

更多详情请见下方海报~
30943258454939062.jpg

扫描上方二维码 ,立即购买早鸟票

与大咖讲师共同探索云计算的下一个十年!
活动详情:了解更多
0
评论

【我最喜爱的 Cloud Studio 插件评选大赛】终于开始了! Cloud Studio Cloud Studio 插件评选大赛 腾讯云开发者平台 coding 编程大赛

beyond 发表了文章 • 146 次浏览 • 2018-11-26 15:37 • 来自相关话题

由 环信、腾讯云和 CODING 共同举办的 我最喜爱的 Cloud Studio 插件评选大赛正式开始了!在这场比赛里,将会有技术上的碰撞,大牛评委的专业点评,愉快的技术交流,好玩的插件尝试。





参赛者可以围绕 Git、实用小工具、腾讯云产品对接、UI 强化、语言支持等 14 个主题提交插件,再加上最具娱乐奖,代码最简单奖,设置功能最复杂奖等;近 30 种奖项,超高中奖率;插件只要提交上架,就有 50 元的话费相赠;只要关注 CODING 公众号并转发活动讯息到朋友圈,即可获得手机充值小礼!

参与方式

注册并登陆腾讯云开发者平台(https://dev.tencent.com) -> 点击进入活动页面 -> 点击进行插件的编写与提交(需要选择参与评选的类别)-> 审核无误后即可上架自动参与评选。

赛程时间




 
环信特别奖




基于环信开发一款聊天插件,即有机会获得特别奖,根据作品还将获得环信提供的神秘奖品
更多活动信息,请浏览我们的活动页面。

进入活动页面> 查看全部

2.jpg


由 环信、腾讯云和 CODING 共同举办的 我最喜爱的 Cloud Studio 插件评选大赛正式开始了!在这场比赛里,将会有技术上的碰撞,大牛评委的专业点评,愉快的技术交流,好玩的插件尝试。

6ccda21fgy1fxeim29mncj20ik0e6dn4.jpg

  • 参赛者可以围绕 Git、实用小工具、腾讯云产品对接、UI 强化、语言支持等 14 个主题提交插件,再加上最具娱乐奖,代码最简单奖,设置功能最复杂奖等;
  • 近 30 种奖项,超高中奖率;
  • 插件只要提交上架,就有 50 元的话费相赠;
  • 只要关注 CODING 公众号并转发活动讯息到朋友圈,即可获得手机充值小礼!


参与方式

注册并登陆腾讯云开发者平台https://dev.tencent.com) -> 点击进入活动页面 -> 点击进行插件的编写与提交(需要选择参与评选的类别)-> 审核无误后即可上架自动参与评选。

赛程时间
6ccda21fly1fxejmnr8oej20ow03odfy.jpg

 
环信特别奖
tb16@2x.png

基于环信开发一款聊天插件,即有机会获得特别奖,根据作品还将获得环信提供的神秘奖品
更多活动信息,请浏览我们的活动页面。

进入活动页面>
11
回复

收集基于环信SDK开发的开源项目 开源项目

回复

xiaoyan2015 回复了问题 • 13 人关注 • 11743 次浏览 • 2018-11-21 23:59 • 来自相关话题

4
评论

【开源项目】全国首个开源直播小程序源码 环信公开课 小程序 直播

beyond 发表了文章 • 4077 次浏览 • 2018-07-20 17:30 • 来自相关话题

今天你看直播了吗?拥有10亿微信生态用户的小程序已经成为了继移动互联后的又一个现象级风口,随着微信小程序对外开放实时音视频录制及播放等更多连接能力,小程序与直播强强联合,在各行各业找到了非常多的玩法,小程序直播相比微信直播和APP直播更加简洁、流畅、低延时、多入口等众多优势迅速向商业直播领域及泛娱乐直播领域蔓延。从小游戏、内容付费、工具、大数据、社交电商创业者到传统品牌商们,都在努力搭上小程序直播这辆快车,以免错过微信生态里新的流量洼地。
 





作为一名环信生态圈资深开发者,本着对技术的热衷,对环信的眷恋和对党的忠诚,基于环信即时通讯云写了“直播购物小程序”,目前项目源码已全部免费开放,希望对有需求的企业和开发者提供一个思路和参考。
直播购物小程序源码github地址:https://github.com/YuTongNetworkTechnology/wechat_live/tree/master 
git打不开可直接点下面链接下载


小程序直播demo_2018-06-21.zip







直播购物小程序运行预览图 
 
小程序体验指南(仅需两步):
 
1、下载微信小程序开发工具,下载地址:https://developers.weixin.qq.c ... .html 
 




2、导入源码:将附件的源码解压直接导入 







环信小程序直播技术文档
一、 使用的技术
1、 环信IM直播室。
2、 微信小程序实时音视频播放组件live-player。
3、 推流软件(obs、易推流)等推流。
4、 视频流服务器(UCLOUD、七牛、腾讯)等视频流服务器。
二、 系统使用流程。
1、 视频推流软件将视频流推到流服务器。
2、 打开视频直播demo小程序注册环信账号。
3、 进入软件直播室进行测试。
三、 技术流程及使用的SDk
1、 注册环信账号
打开https://www.easemob.com/ 环信官网,点击右上角注册按钮,选择[注册即时通讯云]




填写对相关信息进行注册





注册成功后进行登录




注:新注册用户需进行账号的认证。
2、 直播应用创建
登录成功点击应用列表选择创建应用




输入应用名称等信息
 





创建成功后点击应用进入





需要注意的是应用的OrgName 和AppName这两个是以后都需要用到的两个参数变量




3、 直播创建
1)在创建直播之前需要对应用进行设置首先需要设置应用的直播流地址
第一步获取应用管理员的Tokencurl -X POST "https://a1.easemob.com/[应用OrgName]/[应用AppName]/token" -d '{"grant_type":"client_credentials","client_id":"[应用client_id]","client_secret":"[应用] client_secret"}'返回格式{
"access_token":"YWMtWY779DgJEeS2h9OR7fw4QgAAAUmO4Qukwd9cfJSpkWHiOa7MCSk0MrkVIco",
"expires_in":5184000,
"application":"c03b3e30-046a-11e4-8ed1-5701cdaaa0e4"












第二步设置直播流地址curl -X POST -H "Authorization: Bearer [管理员Token]" " https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms/stream_url -d '{"pc_pull":"[pc拉流地址]","pc_push":"[pc推流地址]","mobile_pull":"[手机拉流地址]","mobile_push":"[手机推流地址]"}'"成功返回格式:{
"action": "post",
"application": "e1a09de0-0e03-11e7-ad8e-a1d913615409",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"pc_pull": true,
"mobile_push": true,
"mobile_pull": true,
"pc_push": true
},
"timestamp": 1494084474885,
"duration": 1,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












2)创建主播
点击IM用户





点击注册IM用户





填写用户信息





创建用户的过程同样也可以通过REST API形式进行curl -X POST -i " https://a1.easemob.com/[应用OrgName]/[应用AppName]/users" -d '{"username":"[用户名]","password":"[密码]"}'
注:应用必须为开放注册





将注册的用户添加为主播curl -X POST -H "Authorization: [管理员Token]" https://a1.easemob.com/[应用OrgName]/[应用AppName]/super_admin -d'{"superadmin":"[IM用户名]"}'返回结果示例:{
"action": "post",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"result": "success"
},
"timestamp": 1496236798886,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












3)创建直播
点击直播





点击新建房间





填写房间信息




创建房间同时也可以使用REST API形式进行详情可以查看http://docs.easemob.com/im/live/server-integration环信官方文档。
4、 小程序demo集成使用
小程序直播购物demo集成官方WebIM SDK详情请查看https://github.com/easemob/webim-weixin-xcx
Demo具体配置如下
打开demo 下sdk配置文件





修改appkey为自己应用的appkey





打开pages/live/index.js修改房间默认拉流地址及直播间房间号





四、 扩展说明
Demo中房间为固定测试房间,实际使用中应获取环信直播的房间信息及房间列表。具体如下:
获取直播间列表:curl -X GET -H "Authorization: Bearer [用户Token]" https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms?ongoing=true&limit=[获取数量]&cursor=[游标地址(不填写为充开始查询)]
响应:{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"params": {
"cursor": [
"ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6MzE"
],
"ongoing": [
"true"
],
"limit": [
"2"
]
},
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": [
{
"id": "1924",
"chatroom_id": "17177265635330",
"title": "具体了",
"desc": "就咯",
"startTime": 1495779917352,
"endTime": 1495779917352,
"anchor": "wuls",
"gift_count": 0,
"praise_count": 0,
"current_user_count": 8,
"max_user_count": 9,
"status": "ongoing",
"cover_picture_url": "",
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1"
},
{
"id": "1922",
"chatroom_id": "17175003856897",
"title": "香山",
"desc": "随便",
"startTime": 1495777760957,
"endTime": 1495777760957,
"anchor": "sx001",
"gift_count": 0,
"praise_count": 8,
"current_user_count": 1,
"max_user_count": 3,
"status": "ongoing",
"cover_picture_url": "http://127.0.0.1:8080/easemob- ... ot%3B,
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1"
}
],
"timestamp": 1496303336669,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"cursor": "ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6NDk",
"count": 2
}












获取直播间详情:curl -X GET -H "Authorization: Bearer [用户Token]" " https://a1.easemob.com/[应用OrgName]/[应用AppName]/[房间id]/status"响应:{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"liveRoomID": "1946",
"status": "ongoing"
},
"timestamp": 1496234759930,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"count": 0
}














 
使用环信直播购物小程序遇到任何问题欢迎跟帖讨论。 查看全部
今天你看直播了吗?
拥有10亿微信生态用户的小程序已经成为了继移动互联后的又一个现象级风口,随着微信小程序对外开放实时音视频录制及播放等更多连接能力,小程序与直播强强联合,在各行各业找到了非常多的玩法,小程序直播相比微信直播和APP直播更加简洁、流畅、低延时、多入口等众多优势迅速向商业直播领域及泛娱乐直播领域蔓延。从小游戏、内容付费、工具、大数据、社交电商创业者到传统品牌商们,都在努力搭上小程序直播这辆快车,以免错过微信生态里新的流量洼地。
 
微信图片_20180725162426.jpg


作为一名环信生态圈资深开发者,本着对技术的热衷,对环信的眷恋和对党的忠诚,基于环信即时通讯云写了“直播购物小程序”,目前项目源码已全部免费开放,希望对有需求的企业和开发者提供一个思路和参考。
直播购物小程序源码github地址:https://github.com/YuTongNetworkTechnology/wechat_live/tree/master 
git打不开可直接点下面链接下载



预览图.jpg

直播购物小程序运行预览图 
 
小程序体验指南(仅需两步):
 
1、下载微信小程序开发工具,下载地址:https://developers.weixin.qq.c ... .html 
 
Catch9A07(07-20-17-38-30).jpg

2、导入源码:将附件的源码解压直接导入 


Catch1C69(07-20-17-38-30).jpg


环信小程序直播技术文档
一、 使用的技术
1、 环信IM直播室。
2、 微信小程序实时音视频播放组件live-player。
3、 推流软件(obs、易推流)等推流。
4、 视频流服务器(UCLOUD、七牛、腾讯)等视频流服务器。
二、 系统使用流程。
1、 视频推流软件将视频流推到流服务器。
2、 打开视频直播demo小程序注册环信账号。
3、 进入软件直播室进行测试。
三、 技术流程及使用的SDk
1、 注册环信账号
打开https://www.easemob.com/ 环信官网,点击右上角注册按钮,选择[注册即时通讯云]
1.png

填写对相关信息进行注册

2.png

注册成功后进行登录
3.png

注:新注册用户需进行账号的认证。
2、 直播应用创建
登录成功点击应用列表选择创建应用
4.png

输入应用名称等信息
 

5.png

创建成功后点击应用进入

6.png

需要注意的是应用的OrgName 和AppName这两个是以后都需要用到的两个参数变量
7.png

3、 直播创建
1)在创建直播之前需要对应用进行设置首先需要设置应用的直播流地址
第一步获取应用管理员的Token
curl -X POST "https://a1.easemob.com/[应用OrgName]/[应用AppName]/token" -d '{"grant_type":"client_credentials","client_id":"[应用client_id]","client_secret":"[应用] client_secret"}'
返回格式
{
"access_token":"YWMtWY779DgJEeS2h9OR7fw4QgAAAUmO4Qukwd9cfJSpkWHiOa7MCSk0MrkVIco",
"expires_in":5184000,
"application":"c03b3e30-046a-11e4-8ed1-5701cdaaa0e4"












第二步设置直播流地址
curl -X POST -H "Authorization: Bearer [管理员Token]"  " https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms/stream_url -d '{"pc_pull":"[pc拉流地址]","pc_push":"[pc推流地址]","mobile_pull":"[手机拉流地址]","mobile_push":"[手机推流地址]"}'"
成功返回格式:
{
"action": "post",
"application": "e1a09de0-0e03-11e7-ad8e-a1d913615409",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"pc_pull": true,
"mobile_push": true,
"mobile_pull": true,
"pc_push": true
},
"timestamp": 1494084474885,
"duration": 1,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












2)创建主播
点击IM用户

8.png

点击注册IM用户

9.png

填写用户信息

10.png

创建用户的过程同样也可以通过REST API形式进行
curl -X POST -i " https://a1.easemob.com/[应用OrgName]/[应用AppName]/users" -d '{"username":"[用户名]","password":"[密码]"}'

注:应用必须为开放注册

11.png

将注册的用户添加为主播
curl -X POST -H "Authorization: [管理员Token]"  https://a1.easemob.com/[应用OrgName]/[应用AppName]/super_admin -d'{"superadmin":"[IM用户名]"}'
返回结果示例:
{
"action": "post",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"result": "success"
},
"timestamp": 1496236798886,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui"
}












3)创建直播
点击直播

12.png

点击新建房间

13.png

填写房间信息
14.png

创建房间同时也可以使用REST API形式进行详情可以查看http://docs.easemob.com/im/live/server-integration环信官方文档。
4、 小程序demo集成使用
小程序直播购物demo集成官方WebIM SDK详情请查看https://github.com/easemob/webim-weixin-xcx
Demo具体配置如下
打开demo 下sdk配置文件

15.png

修改appkey为自己应用的appkey

16.png

打开pages/live/index.js修改房间默认拉流地址及直播间房间号

17.png

四、 扩展说明
Demo中房间为固定测试房间,实际使用中应获取环信直播的房间信息及房间列表。具体如下:
获取直播间列表:
curl -X GET -H "Authorization: Bearer  [用户Token]"  https://a1.easemob.com/[应用OrgName]/[应用AppName]/liverooms?ongoing=true&limit=[获取数量]&cursor=[游标地址(不填写为充开始查询)]

响应:
{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"params": {
"cursor": [
"ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6MzE"
],
"ongoing": [
"true"
],
"limit": [
"2"
]
},
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": [
{
"id": "1924",
"chatroom_id": "17177265635330",
"title": "具体了",
"desc": "就咯",
"startTime": 1495779917352,
"endTime": 1495779917352,
"anchor": "wuls",
"gift_count": 0,
"praise_count": 0,
"current_user_count": 8,
"max_user_count": 9,
"status": "ongoing",
"cover_picture_url": "",
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1924_1"
},
{
"id": "1922",
"chatroom_id": "17175003856897",
"title": "香山",
"desc": "随便",
"startTime": 1495777760957,
"endTime": 1495777760957,
"anchor": "sx001",
"gift_count": 0,
"praise_count": 8,
"current_user_count": 1,
"max_user_count": 3,
"status": "ongoing",
"cover_picture_url": "http://127.0.0.1:8080/easemob- ... ot%3B,
"pc_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"pc_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_pull_url": "rtmp://vlive3.rtmp.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1",
"mobile_push_url": "rtmp://publish3.cdn.ucloud.com.cn/ucloud/easemob-demo_chatdemoui_1922_1"
}
],
"timestamp": 1496303336669,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"cursor": "ZGNiMjRmNGY1YjczYjlhYTNkYjk1MDY2YmEyNzFmODQ6aW06Y2hhdHJvb206ZWFzZW1vYi1kZW1vI2NoYXRkZW1vdWk6NDk",
"count": 2
}












获取直播间详情:
curl -X GET -H "Authorization: Bearer [用户Token]" " https://a1.easemob.com/[应用OrgName]/[应用AppName]/[房间id]/status"
响应:
{
"action": "get",
"application": "4d7e4ba0-dc4a-11e3-90d5-e1ffbaacdaf5",
"uri": "http://127.0.0.1:8080/easemob- ... ot%3B,
"entities": [ ],
"data": {
"liveRoomID": "1946",
"status": "ongoing"
},
"timestamp": 1496234759930,
"duration": 0,
"organization": "easemob-demo",
"applicationName": "chatdemoui",
"count": 0
}














 
使用环信直播购物小程序遇到任何问题欢迎跟帖讨论。
19
评论

【新手快速入门】集成环信常见问题+解决方案汇总 常见问题

dujiepeng 发表了文章 • 18374 次浏览 • 2017-05-22 15:51 • 来自相关话题

   这里整理了集成环信的常见问题和一些功能的实现思路,希望能帮助到大家。感谢热心的开发者贡献,大家在观看过程中有不明白的地方欢迎直接跟帖咨询。
 
ios篇
APNs证书创建和上传到环信后台头像昵称的简述和处理方案音视频离线推送Demo实现环信服务器聊天记录保存多久?离线收不到好友请求IOS中环信聊天窗口如何实现文件发送和预览的功能ios集成常见问题环信推送的一些常见问题实现名片|红包|话题聊天室等自定义cell
 
Android篇
Android sdk 的两种导入方式环信3.0SDK集成小米推送教程EaseUI库中V4、v7包冲突解决方案Android EaseUI里的百度地图替换为高德地图android扩展消息(名片集成)关于会话列表的置顶聊天java.lang.UnsatisfiedLinkError: 的问题android 端 app 后台被杀死收不到消息的解决方案
昵称头像篇
android中如何显示开发者服务器上的昵称和头像 Android中显示头像(接上一篇文章看)环信(Android)设置头像和昵称的方法(最简单暴力的基于环信demo的集成)IOS中如何显示开发者服务器上的昵称和头像【环信公开课第12期视频回放】-所有关于环信IM昵称头像的问题听这课就够了
 
直播篇
一言不合你就搞个直播APP
 
客服集成
IM-SDK和客服SDK并存开发指南—Android篇IM-SDK和客服SDK并存开发指南—iOS篇
 
开源项目
Android简版demoios简版demo凡信2.0:超仿微信的开源项目 凡信3.0:携直播和红包而来高仿微信:Github 3,515 Star方圆十里:环信编程大赛冠军项目泛聊:定一个小目标写一个QQSlack聊天机器人:一天时间做一个聊天机器人TV视频通话:在电视上视频通话视频通话:Android手机视频通话酷信:ios高仿微信公众号助手:与订阅用户聊天沟通
 
持续更新ing...小伙伴们还有什么想知道欢迎跟帖提出。
  查看全部
   这里整理了集成环信的常见问题和一些功能的实现思路,希望能帮助到大家。感谢热心的开发者贡献,大家在观看过程中有不明白的地方欢迎直接跟帖咨询。
 
ios篇

 
Android篇

昵称头像篇

 
直播篇
  1. 一言不合你就搞个直播APP

 
客服集成
  1. IM-SDK和客服SDK并存开发指南—Android篇
  2. IM-SDK和客服SDK并存开发指南—iOS篇

 
开源项目

 
持续更新ing...小伙伴们还有什么想知道欢迎跟帖提出。
 
0
评论

0 元福利手慢无 | 年尾盛会——2018 · 支付学院年会环信用户免费报名 活动推荐 环信 ping++

beyond 发表了文章 • 97 次浏览 • 2018-11-27 15:13 • 来自相关话题

文能提笔抒骚情
武能切图画交互





 作为一个产品经理

学习不是忙里偷闲的充电

而是写进岗位职责里的日日功

公司一步步发展,业务一步步扩张
 
 支付 

一个熟悉又陌生的词映入眼帘
从 2014 年起,Ping++ 用 4 年的沉淀积累,化繁为简,实现「 7 行代码接入支付」的聚合支付、会员账户系统、多级商户系统等产品,首次提出「聚合支付」,在聚合支付领域树立标杆、建立规则。曾经踩过的无数坑,都成为了支付这一领域内宝贵的经验。所以说,不如为所有的产品经理们办一个「支付学院」吧!就这样,支付学院第一期款款而来。





「你们应该继续办下去啊!支持你们!」
「这次真的收获满满,老师讲得我还要再捋捋,太多了一下吸收不了。」
「可以私底下给秋秋老师打 Call 吗?请替我表白!」
「PPT 我打印出来学习,你们下次别用黑底白字了,打印起来反白很麻烦。」
「……」




受宠若惊,十分惶恐。因此,领域即便如此狭窄,架构即便大同小异,也要像宰相的女儿山鲁佐德一样,奉上个个迥异的故事,直到第一千零一夜。















于是就又举办了第二期、第三期,以及现在如约而至的 2018 年会。




❤ 作为一名严肃活泼认真可爱的支付从业者,你一定知道支付的前提是合规,监管即是这开头的 1 ;而后作为一个产品商业化的核心,支付系统与交易系统应为业务敞开怀抱,随着需求的变化而迭代以支撑业务十倍百倍的增长,0 是谦虚也是包容;在当今经济下行的处境下,很多企业为了寻求进一步的发展,纷纷选择了出海,去海外寻求新的增长点,因此跨境就像尾部的 1,代表了新的起点和开始。

❤ 1001 个支付故事,其实也是 4 个支付故事。2018 支付学院年会来为大家讲解关于交易系统、支付系统、监管和跨境支付的故事。
 
年会不同以往的是,大家热热闹闹开开心心相聚才是最重要的,因此这次人数应该远超以往,如果想要 0 元听老师讲课,那你就需要手快一些了。

0 元票兑换码
feqylt1
 
有道是,相逢即是有缘,有缘自会相逢。

我觉得我们已经很有缘了,故事也有了,来年会一起聊聊吧。
 
活动详情:免费报名 查看全部
文能提笔抒骚情
武能切图画交互


微信图片_20181127145045.jpg

 作为一个产品经理

学习不是忙里偷闲的充电

而是写进岗位职责里的日日功

公司一步步发展,业务一步步扩张
 
 支付 

一个熟悉又陌生的词映入眼帘
从 2014 年起,Ping++ 用 4 年的沉淀积累,化繁为简,实现「 7 行代码接入支付」的聚合支付、会员账户系统、多级商户系统等产品,首次提出「聚合支付」,在聚合支付领域树立标杆、建立规则。曾经踩过的无数坑,都成为了支付这一领域内宝贵的经验。所以说,不如为所有的产品经理们办一个「支付学院」吧!就这样,支付学院第一期款款而来。

微信图片_20181127151035.jpg

「你们应该继续办下去啊!支持你们!」
「这次真的收获满满,老师讲得我还要再捋捋,太多了一下吸收不了。」
「可以私底下给秋秋老师打 Call 吗?请替我表白!」
「PPT 我打印出来学习,你们下次别用黑底白字了,打印起来反白很麻烦。」
「……」
微信图片_20181127151054.jpg

受宠若惊,十分惶恐。因此,领域即便如此狭窄,架构即便大同小异,也要像宰相的女儿山鲁佐德一样,奉上个个迥异的故事,直到第一千零一夜。

微信图片_20181127151125.jpg


微信图片_20181127151137.jpg


微信图片_20181127151148.jpg

于是就又举办了第二期、第三期,以及现在如约而至的 2018 年会。
微信图片_20181127151202.jpg

❤ 作为一名严肃活泼认真可爱的支付从业者,你一定知道支付的前提是合规,监管即是这开头的 1 ;而后作为一个产品商业化的核心,支付系统与交易系统应为业务敞开怀抱,随着需求的变化而迭代以支撑业务十倍百倍的增长,0 是谦虚也是包容;在当今经济下行的处境下,很多企业为了寻求进一步的发展,纷纷选择了出海,去海外寻求新的增长点,因此跨境就像尾部的 1,代表了新的起点和开始。

❤ 1001 个支付故事,其实也是 4 个支付故事。2018 支付学院年会来为大家讲解关于交易系统、支付系统、监管和跨境支付的故事。
 
年会不同以往的是,大家热热闹闹开开心心相聚才是最重要的,因此这次人数应该远超以往,如果想要 0 元听老师讲课,那你就需要手快一些了。

0 元票兑换码
feqylt1

 
有道是,相逢即是有缘,有缘自会相逢。

我觉得我们已经很有缘了,故事也有了,来年会一起聊聊吧。
 
活动详情:免费报名
2
评论

NIUDAY 11.23 北京站 |环信CEO刘俊彦现场讲述人工智能赋能客户互动之现状与未来 刘俊彦 人工智能 环信 七牛云

beyond 发表了文章 • 145 次浏览 • 2018-11-15 16:36 • 来自相关话题

2018 年是见证「奇迹」的一年。AI 从多年的热门话题中开始走下神坛,逐渐深入到了各个行业,加速经济结构优化及行业智慧化升级,AI 已不再是难以企及的神话而是可触摸的美好未来。 政策支持加上资本推动,无论是从新兴行业还是传统行业都出现了人工智能方面的布局者和佼佼者,智慧教育、移动社交、智能语音、智慧客服、传统媒体等行业都在突破技术上和流程上的难点和困惑。

11 月 23 日,一场由七牛云主办主题为「AI 产业技术的渗透与融合」的 NIUDAY 小牛汇共享日将在北京举行。会上,将邀请众多行业内知名企业及技术专家,针对当前 AI 在技术上以及行业中遇到的一些壁垒问题,进行深入探讨和分享。

智慧教育、移动未来,体验指尖上的 AI

在此次活动中,除行业专家的视点剖析之外,对于 AI 与行业的渗透与融合度是理论大于实践亦或是理论与实践已完美结合,已经应用的行业代表案例有哪些?对于这些问题,大家可以在此次活动中得以解惑。




刘俊彦
手机电商、手机软件系统的快速更迭让在线客服、移动客服有了更大的发展空间,成了市场中的一片蓝海,究竟现状如何、客户体验的真实反馈是什么?环信 CEO 刘俊彦先生带来的《人工智能赋能客户互动之现状与未来》让你更贴近生活,更能体会 AI 的无处不在。




谢华亮

科技发展教育先行,技术与教育的结合又将碰撞出怎样的火花,会上,将有好未来 SEG 智慧教育事业部技术总监谢华亮带来主题为《AI 在教育行业中的应用》的精彩演讲。




佘超杰

移动互联网的发展已影响到我们身边的每一个人,游戏、娱乐、社交等手机平台的火爆更是带来了巨大的信息流量。但如何应对这些突然爆发的信息流,如何让产品与技术更好地去结合以吸引更多的受众人群,成为人们关注的话题。以作为专注于移动互联网社交的知名企业 Blued 为例,实践与技术并重的技术专家佘超杰将分享给我们《AI 在 Blued 上的应用》。
                
连线行业专家,洞悉专业视点

人工智能技术在飞速发展过程中得到了国家以及政府的极大关注与大力支持,中国人工智能产业发展联盟作为国家发展改革委、科学技术部、工业和信息化部、中央网信办四部委共同指导下的人工智能产业权威联盟机构,也将加入到此次 NIUDAY 小牛汇共享日活动中来。





孙明俊

中国信息通信研究院人工智能部副主任,中国人工智能产业发展联盟总体组组长、数据中心联盟秘书长孙明俊女士将出席本次活动,并将从行业专家的角度带来主题为《人工智能产业发展水平分析》的演讲,向大家解析产业发展水平、分享行业利好政策等。

战略签约中国网 传统与创新的再突破





杨新华

值得一提的是,本次 NIUDAY 小牛汇共享日活动上七牛云将与中国互联网新闻中心举行战略合作签约仪式。届时,中国互联网新闻中心·中国网副总编辑杨新华先生将带来《AI 如何讲好中国故事》的演讲,介绍七牛云在未来媒体平台构建中发挥的作用,以及正处于变革中的媒体行业对 AI 的思考。

当然作为本次 NIUDAY 小牛汇活动的主办方,七牛云也准备了满满的干货带给大家。七牛云技术总监陈超《数据智能时代的智慧工厂实践》、七牛云人工智能实验室资深产品经理杨叶青《一站式审核助力无忧运营》带你体会七牛云两大重要产品线的技术与发展。

更多大咖嘉宾,请往下看~ 





关于环信机器人:

环信机器人已经在中通快递、新东方、天津农商行、宜家、环球捕手等头部企业的“双十一”中发挥着中流砥柱的作用,机器人可以帮助解决80%以上的常见问题,在售后环节能替代超90%的人工,轻松实现7*24无间断客户服务,AI从此让我们的客服人员告别苦逼,云淡风轻,笑对各种节假日促销、狂欢节。

目前,环信机器人已经广泛服务于包括保险、证券、银行、教育、物流、商旅、电商、汽车等行业的数万客户,日机器人会话超千万条。
活动报名地址:http://www.huodongxing.com/event/2464773427600 查看全部

2018 年是见证「奇迹」的一年。AI 从多年的热门话题中开始走下神坛,逐渐深入到了各个行业,加速经济结构优化及行业智慧化升级,AI 已不再是难以企及的神话而是可触摸的美好未来。 政策支持加上资本推动,无论是从新兴行业还是传统行业都出现了人工智能方面的布局者和佼佼者,智慧教育、移动社交、智能语音、智慧客服、传统媒体等行业都在突破技术上和流程上的难点和困惑。



11 月 23 日,一场由七牛云主办主题为「AI 产业技术的渗透与融合」的 NIUDAY 小牛汇共享日将在北京举行。会上,将邀请众多行业内知名企业及技术专家,针对当前 AI 在技术上以及行业中遇到的一些壁垒问题,进行深入探讨和分享。

智慧教育、移动未来,体验指尖上的 AI

在此次活动中,除行业专家的视点剖析之外,对于 AI 与行业的渗透与融合度是理论大于实践亦或是理论与实践已完美结合,已经应用的行业代表案例有哪些?对于这些问题,大家可以在此次活动中得以解惑。

微信图片_20181115162453.jpg

刘俊彦


手机电商、手机软件系统的快速更迭让在线客服、移动客服有了更大的发展空间,成了市场中的一片蓝海,究竟现状如何、客户体验的真实反馈是什么?环信 CEO 刘俊彦先生带来的《人工智能赋能客户互动之现状与未来》让你更贴近生活,更能体会 AI 的无处不在。

微信图片_20181115162531.jpg

谢华亮



科技发展教育先行,技术与教育的结合又将碰撞出怎样的火花,会上,将有好未来 SEG 智慧教育事业部技术总监谢华亮带来主题为《AI 在教育行业中的应用》的精彩演讲。

微信图片_20181115162544.jpg

佘超杰



移动互联网的发展已影响到我们身边的每一个人,游戏、娱乐、社交等手机平台的火爆更是带来了巨大的信息流量。但如何应对这些突然爆发的信息流,如何让产品与技术更好地去结合以吸引更多的受众人群,成为人们关注的话题。以作为专注于移动互联网社交的知名企业 Blued 为例,实践与技术并重的技术专家佘超杰将分享给我们《AI 在 Blued 上的应用》。
                
连线行业专家,洞悉专业视点

人工智能技术在飞速发展过程中得到了国家以及政府的极大关注与大力支持,中国人工智能产业发展联盟作为国家发展改革委、科学技术部、工业和信息化部、中央网信办四部委共同指导下的人工智能产业权威联盟机构,也将加入到此次 NIUDAY 小牛汇共享日活动中来。

微信图片_20181115162600.jpg


孙明俊



中国信息通信研究院人工智能部副主任,中国人工智能产业发展联盟总体组组长、数据中心联盟秘书长孙明俊女士将出席本次活动,并将从行业专家的角度带来主题为《人工智能产业发展水平分析》的演讲,向大家解析产业发展水平、分享行业利好政策等。

战略签约中国网 传统与创新的再突破

微信图片_20181115162615.jpg


杨新华



值得一提的是,本次 NIUDAY 小牛汇共享日活动上七牛云将与中国互联网新闻中心举行战略合作签约仪式。届时,中国互联网新闻中心·中国网副总编辑杨新华先生将带来《AI 如何讲好中国故事》的演讲,介绍七牛云在未来媒体平台构建中发挥的作用,以及正处于变革中的媒体行业对 AI 的思考。

当然作为本次 NIUDAY 小牛汇活动的主办方,七牛云也准备了满满的干货带给大家。七牛云技术总监陈超《数据智能时代的智慧工厂实践》、七牛云人工智能实验室资深产品经理杨叶青《一站式审核助力无忧运营》带你体会七牛云两大重要产品线的技术与发展。

更多大咖嘉宾,请往下看~ 

5bed2dcd27fe6.jpg

关于环信机器人:

环信机器人已经在中通快递、新东方、天津农商行、宜家、环球捕手等头部企业的“双十一”中发挥着中流砥柱的作用,机器人可以帮助解决80%以上的常见问题,在售后环节能替代超90%的人工,轻松实现7*24无间断客户服务,AI从此让我们的客服人员告别苦逼,云淡风轻,笑对各种节假日促销、狂欢节。

目前,环信机器人已经广泛服务于包括保险、证券、银行、教育、物流、商旅、电商、汽车等行业的数万客户,日机器人会话超千万条。
活动报名地址:http://www.huodongxing.com/event/2464773427600
0
评论

环信Rest java sdk吐槽+你想怎么写? 环信

环信沈冲 发表了文章 • 546 次浏览 • 2018-05-22 00:50 • 来自相关话题

先附上java sdk以及示例代码的GitHub地址:
https://github.com/easemob/emchat-server-examples/tree/master/emchat-server-java
 
相信各位服务端的朋友都已经瞅过了,最后是否使用了这个sdk呢?如果没有使用,为什么不使用呢?你..你...你能不能告诉我为什么??尽情的喷我吧,告诉我该怎么写,我改还不行吗..
 
先行感谢各位诚恳的意见和建议,期望得到您的回复。 查看全部
先附上java sdk以及示例代码的GitHub地址:
https://github.com/easemob/emchat-server-examples/tree/master/emchat-server-java
 
相信各位服务端的朋友都已经瞅过了,最后是否使用了这个sdk呢?如果没有使用,为什么不使用呢?你..你...你能不能告诉我为什么??尽情的喷我吧,告诉我该怎么写,我改还不行吗..
 
先行感谢各位诚恳的意见和建议,期望得到您的回复。
0
评论

基于环信的仿QQ即时通讯的简单实现 QQ 环信

beyond 发表了文章 • 837 次浏览 • 2018-03-08 16:01 • 来自相关话题

概述
 
今天看了环信的API,就利用下午的时间动手试了试,然后做了一个小Demo。详细

我的博客地址

之前一直想实现聊天的功能,但是感觉有点困难,今天看了环信的API,就利用下午的时间动手试了试,然后做了一个小Demo。
因为没有刻意去做聊天软件,花的时间也不多,然后界面就很简单,都是一些基本知识,如果觉得功能简单,可以自行添加,我这就不多介绍了。

照例先来一波动态演示:




 
功能很简单,注册用户 —> 用户登录 —> 选择聊天对象 —> 开始聊天

使用到的知识点:
RecyclerViewCardView环信的API的简单使用

依赖的库
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.android.support:cardview-v7:24.1.1'
compile 'com.android.support:recyclerview-v7:24.0.0' 1、聊天页面

首先是看了郭神的《第二行代码》做了聊天界面,用的是RecyclerView

a. 消息类的封装
public class MSG {
public static final int TYPE_RECEIVED = 0;//消息的类型:接收
public static final int TYPE_SEND = 1; //消息的类型:发送
private String content;//消息的内容
private int type; //消息的类型
public MSG(String content, int type) {
this.content = content;
this.type = type;
}
public String getContent() {
return content;
}
public int getType() {
return type;
}
}b. RecyclerView子项的布局​
<LinearLayout
android:id="@+id/ll_msg_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
<!-- 设置点击效果为水波纹(5.0以上) -->
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
android:padding="2dp">
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="20dp"
app:cardPreventCornerOverlap="false"
app:cardUseCompatPadding="true">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:scaleType="centerCrop"
android:src="@mipmap/man" />
</android.support.v7.widget.CardView>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/message_left"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_msg_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:textColor="#fff" />
</LinearLayout>
</LinearLayout>这是左边的部分,至于右边应该也就简单了。我用CardView把ImageView包裹起来,这样比较好看。效果如下:




c. RecyclerView适配器​
public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.MyViewHolder> {
private List<MSG> mMsgList;
public MsgAdapter(List<MSG> mMsgList) {
this.mMsgList = mMsgList;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(parent.getContext(), R.layout.item_msg, null);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MSG msg = mMsgList.get(position);
if (msg.getType() == MSG.TYPE_RECEIVED){
//如果是收到的消息,显示左边布局,隐藏右边布局
holder.llLeft.setVisibility(View.VISIBLE);
holder.llRight.setVisibility(View.GONE);
holder.tv_Left.setText(msg.getContent());
} else if (msg.getType() == MSG.TYPE_SEND){
//如果是发送的消息,显示右边布局,隐藏左边布局
holder.llLeft.setVisibility(View.GONE);
holder.llRight.setVisibility(View.VISIBLE);
holder.tv_Right.setText(msg.getContent());
}
}
@Override
public int getItemCount() {
return mMsgList.size();
}
static class MyViewHolder extends RecyclerView.ViewHolder{
LinearLayout llLeft;
LinearLayout llRight;
TextView tv_Left;
TextView tv_Right;
public MyViewHolder(View itemView) {
super(itemView);
llLeft = (LinearLayout) itemView.findViewById(R.id.ll_msg_left);
llRight = (LinearLayout) itemView.findViewById(R.id.ll_msg_right);
tv_Left = (TextView) itemView.findViewById(R.id.tv_msg_left);
tv_Right = (TextView) itemView.findViewById(R.id.tv_msg_right);
}
}
}这部分应该也没什么问题,就是适配器的创建,我之前的文章也讲过 传送门:简单粗暴——RecyclerView

d. RecyclerView初始化

就是一些基本的初始化,我就不赘述了,讲一下添加数据的细节处理
 
btSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String content = etInput.getText().toString().trim();
if (!TextUtils.isEmpty(content)){
...//环信部分的发送消息
MSG msg = new MSG(content, MSG.TYPE_SEND);
mList.add(msg);
//当有新消息时,刷新RecyclerView中的显示
mAdapter.notifyItemInserted(mList.size() - 1);
//将RecyclerView定位到最后一行
mRecyclerView.scrollToPosition(mList.size() - 1);
etInput.setText("");
}
}
});至此界面已经结束了,接下来就是数据的读取

2. 环信API的简单应用

官网有详细的API介绍 环信及时通讯V3.0,我这里就简单介绍如何简单集成

a. 环信开发账号的注册

环信官网

创建应用得到Appkey后面要用




b. SDK导入

你可以直接下载然后拷贝工程的libs目录下

Android Studio可以直接添加依赖
 
将以下代码放到项目根目录的build.gradle文件里
repositories {
maven { url "https://raw.githubusercontent. ... ot%3B }
}在你的module的build.gradle里加入以下代码
android {
//use legacy for android 6.0
useLibrary 'org.apache.http.legacy'
}
dependencies {
compile 'com.android.support:appcompat-v7:23.4.0'
//Optional compile for GCM (Google Cloud Messaging).
compile 'com.google.android.gms:play-services-gcm:9.4.0'
compile 'com.hyphenate:hyphenate-sdk:3.2.3'
}如果想使用不包含音视频通话的sdk,用compile 'com.hyphenate [:hyphenate-sdk-lite:] 3.2.3'
 
c. 清单文件配置
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="Your Package"
android:versionCode="100"
android:versionName="1.0.0">
<!-- Required -->
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:name="Your Application">
<!-- 设置环信应用的AppKey -->
<meta-data android:name="EASEMOB_APPKEY" android:value="Your AppKey" />
<!-- 声明SDK所需的service SDK核心功能-->
<service android:name="com.hyphenate.chat.EMChatService" android:exported="true"/>
<service android:name="com.hyphenate.chat.EMJobService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true"
/>
<!-- 声明SDK所需的receiver -->
<receiver android:name="com.hyphenate.chat.EMMonitorReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<data android:scheme="package"/>
</intent-filter>
<!-- 可选filter -->
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.USER_PRESENT" />
</intent-filter>
</receiver>
</application>
</manifest>APP打包混淆
-keep class com.hyphenate.** {*;}
-dontwarn com.hyphenate.**d. 初始化SDK
在自定义Application的onCreate中初始化
public class MyApplication extends Application {
private Context appContext;
@Override
public void onCreate() {
super.onCreate();
EMOptions options = new EMOptions();
options.setAcceptInvitationAlways(false);
appContext = this;
int pid = android.os.Process.myPid();
String processAppName = getAppName(pid);
// 如果APP启用了远程的service,此application:onCreate会被调用2次
// 为了防止环信SDK被初始化2次,加此判断会保证SDK被初始化1次
// 默认的APP会在以包名为默认的process name下运行,如果查到的process name不是APP的process name就立即返回
if (processAppName == null || !processAppName.equalsIgnoreCase(appContext.getPackageName())) {
Log.e("--->", "enter the service process!");
// 则此application::onCreate 是被service 调用的,直接返回
return;
}
//初始化
EMClient.getInstance().init(getApplicationContext(), options);
//在做打包混淆时,关闭debug模式,避免消耗不必要的资源
EMClient.getInstance().setDebugMode(true);
}
private String getAppName(int pID) {
String processName = null;
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
List l = am.getRunningAppProcesses();
Iterator i = l.iterator();
PackageManager pm = this.getPackageManager();
while (i.hasNext()) {
ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) (i.next());
try {
if (info.pid == pID) {
processName = info.processName;
return processName;
}
} catch (Exception e) {
// Log.d("Process", "Error>> :"+ e.toString());
}
}
return processName;
}
}e. 注册和登陆

注册要在子线程中执行
//注册失败会抛出HyphenateException
EMClient.getInstance().createAccount(username, pwd);//同步方法
EMClient.getInstance().login(userName,password,new EMCallBack() {//回调
@Override
public void onSuccess() {
EMClient.getInstance().groupManager().loadAllGroups();
EMClient.getInstance().chatManager().loadAllConversations();
Log.d("main", "登录聊天服务器成功!");
}
@Override
public void onProgress(int progress, String status) {
}
@Override
public void onError(int code, String message) {
Log.d("main", "登录聊天服务器失败!");
}
});f. 发送消息
//创建一条文本消息,content为消息文字内容,toChatUsername为对方用户或者群聊的id,后文皆是如此
EMMessage message = EMMessage.createTxtSendMessage(content, toChatUsername);
//发送消息
EMClient.getInstance().chatManager().sendMessage(message);g. 接收消息
msgListener = new EMMessageListener() {
@Override
public void onMessageReceived(List<EMMessage> messages) {
//收到消息
String result = messages.get(0).getBody().toString();
String msgReceived = result.substring(5, result.length() - 1);
Log.i(TAG, "onMessageReceived: " + msgReceived);
final MSG msg = new MSG(msgReceived, MSG.TYPE_RECEIVED);
runOnUiThread(new Runnable() {
@Override
public void run() {
mList.add(msg);
mAdapter.notifyDataSetChanged();
mRecyclerView.scrollToPosition(mList.size() - 1);
}
});
}
@Override
public void onCmdMessageReceived(List<EMMessage> messages) {
//收到透传消息
}
@Override
public void onMessageRead(List<EMMessage> list) {
}
@Override
public void onMessageDelivered(List<EMMessage> list) {
}
@Override
public void onMessageChanged(EMMessage message, Object change) {
//消息状态变动
}
};接收消息的监听器分别需要在OnResume()和OnDestory()方法中注册和取消注册
EMClient.getInstance().chatManager().addMessageListener(msgListener);//注册
EMClient.getInstance().chatManager().removeMessageListener(msgListener);//取消注册需要注意的是,当接收到消息,需要在主线程中更新适配器,否则会不能及时刷新出来

项目文件截图:





到此,一个简单的及时聊天Demo已经完成,功能很简单,如果需要添加额外功能的话,可以自行参考官网,官网给出的教程还是很不错的!

最后希望大家能多多支持我,需要你们的支持喜欢!! 查看全部
概述
 
今天看了环信的API,就利用下午的时间动手试了试,然后做了一个小Demo。详细

我的博客地址

之前一直想实现聊天的功能,但是感觉有点困难,今天看了环信的API,就利用下午的时间动手试了试,然后做了一个小Demo。
因为没有刻意去做聊天软件,花的时间也不多,然后界面就很简单,都是一些基本知识,如果觉得功能简单,可以自行添加,我这就不多介绍了。

照例先来一波动态演示:
4043475-d16a88926805236a.gif

 
功能很简单,注册用户 —> 用户登录 —> 选择聊天对象 —> 开始聊天

使用到的知识点:
  1. RecyclerView
  2. CardView
  3. 环信的API的简单使用


依赖的库
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.android.support:cardview-v7:24.1.1'
compile 'com.android.support:recyclerview-v7:24.0.0'
1、聊天页面

首先是看了郭神的《第二行代码》做了聊天界面,用的是RecyclerView

a. 消息类的封装
public class MSG {
public static final int TYPE_RECEIVED = 0;//消息的类型:接收
public static final int TYPE_SEND = 1; //消息的类型:发送
private String content;//消息的内容
private int type; //消息的类型
public MSG(String content, int type) {
this.content = content;
this.type = type;
}
public String getContent() {
return content;
}
public int getType() {
return type;
}
}
b. RecyclerView子项的布局​
<LinearLayout
android:id="@+id/ll_msg_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
<!-- 设置点击效果为水波纹(5.0以上) -->
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
android:padding="2dp">
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="20dp"
app:cardPreventCornerOverlap="false"
app:cardUseCompatPadding="true">
<ImageView
android:layout_width="50dp"
android:layout_height="50dp"
android:scaleType="centerCrop"
android:src="@mipmap/man" />
</android.support.v7.widget.CardView>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/message_left"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_msg_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:textColor="#fff" />
</LinearLayout>
</LinearLayout>
这是左边的部分,至于右边应该也就简单了。我用CardView把ImageView包裹起来,这样比较好看。效果如下:
4043475-76ea5370b4d09d89.png

c. RecyclerView适配器​
 public class MsgAdapter extends RecyclerView.Adapter<MsgAdapter.MyViewHolder> {
private List<MSG> mMsgList;
public MsgAdapter(List<MSG> mMsgList) {
this.mMsgList = mMsgList;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(parent.getContext(), R.layout.item_msg, null);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
MSG msg = mMsgList.get(position);
if (msg.getType() == MSG.TYPE_RECEIVED){
//如果是收到的消息,显示左边布局,隐藏右边布局
holder.llLeft.setVisibility(View.VISIBLE);
holder.llRight.setVisibility(View.GONE);
holder.tv_Left.setText(msg.getContent());
} else if (msg.getType() == MSG.TYPE_SEND){
//如果是发送的消息,显示右边布局,隐藏左边布局
holder.llLeft.setVisibility(View.GONE);
holder.llRight.setVisibility(View.VISIBLE);
holder.tv_Right.setText(msg.getContent());
}
}
@Override
public int getItemCount() {
return mMsgList.size();
}
static class MyViewHolder extends RecyclerView.ViewHolder{
LinearLayout llLeft;
LinearLayout llRight;
TextView tv_Left;
TextView tv_Right;
public MyViewHolder(View itemView) {
super(itemView);
llLeft = (LinearLayout) itemView.findViewById(R.id.ll_msg_left);
llRight = (LinearLayout) itemView.findViewById(R.id.ll_msg_right);
tv_Left = (TextView) itemView.findViewById(R.id.tv_msg_left);
tv_Right = (TextView) itemView.findViewById(R.id.tv_msg_right);
}
}
}
这部分应该也没什么问题,就是适配器的创建,我之前的文章也讲过 传送门:简单粗暴——RecyclerView

d. RecyclerView初始化

就是一些基本的初始化,我就不赘述了,讲一下添加数据的细节处理
 
  btSend.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String content = etInput.getText().toString().trim();
if (!TextUtils.isEmpty(content)){
...//环信部分的发送消息
MSG msg = new MSG(content, MSG.TYPE_SEND);
mList.add(msg);
//当有新消息时,刷新RecyclerView中的显示
mAdapter.notifyItemInserted(mList.size() - 1);
//将RecyclerView定位到最后一行
mRecyclerView.scrollToPosition(mList.size() - 1);
etInput.setText("");
}
}
});
至此界面已经结束了,接下来就是数据的读取

2. 环信API的简单应用

官网有详细的API介绍 环信及时通讯V3.0,我这里就简单介绍如何简单集成

a. 环信开发账号的注册

环信官网


创建应用得到Appkey后面要用

4043475-e4dd45e05060467f.png


b. SDK导入

你可以直接下载然后拷贝工程的libs目录下

Android Studio可以直接添加依赖
 
将以下代码放到项目根目录的build.gradle文件里
repositories {
maven { url "https://raw.githubusercontent. ... ot%3B }
}
在你的module的build.gradle里加入以下代码
android {
//use legacy for android 6.0
useLibrary 'org.apache.http.legacy'
}
dependencies {
compile 'com.android.support:appcompat-v7:23.4.0'
//Optional compile for GCM (Google Cloud Messaging).
compile 'com.google.android.gms:play-services-gcm:9.4.0'
compile 'com.hyphenate:hyphenate-sdk:3.2.3'
}
如果想使用不包含音视频通话的sdk,用compile 'com.hyphenate [:hyphenate-sdk-lite:] 3.2.3'
 
c. 清单文件配置
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="Your Package"
android:versionCode="100"
android:versionName="1.0.0">
<!-- Required -->
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:name="Your Application">
<!-- 设置环信应用的AppKey -->
<meta-data android:name="EASEMOB_APPKEY" android:value="Your AppKey" />
<!-- 声明SDK所需的service SDK核心功能-->
<service android:name="com.hyphenate.chat.EMChatService" android:exported="true"/>
<service android:name="com.hyphenate.chat.EMJobService"
android:permission="android.permission.BIND_JOB_SERVICE"
android:exported="true"
/>
<!-- 声明SDK所需的receiver -->
<receiver android:name="com.hyphenate.chat.EMMonitorReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
<data android:scheme="package"/>
</intent-filter>
<!-- 可选filter -->
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.USER_PRESENT" />
</intent-filter>
</receiver>
</application>
</manifest>
APP打包混淆
-keep class com.hyphenate.** {*;}
-dontwarn com.hyphenate.**
d. 初始化SDK
在自定义Application的onCreate中初始化
public class MyApplication extends Application {
private Context appContext;
@Override
public void onCreate() {
super.onCreate();
EMOptions options = new EMOptions();
options.setAcceptInvitationAlways(false);
appContext = this;
int pid = android.os.Process.myPid();
String processAppName = getAppName(pid);
// 如果APP启用了远程的service,此application:onCreate会被调用2次
// 为了防止环信SDK被初始化2次,加此判断会保证SDK被初始化1次
// 默认的APP会在以包名为默认的process name下运行,如果查到的process name不是APP的process name就立即返回
if (processAppName == null || !processAppName.equalsIgnoreCase(appContext.getPackageName())) {
Log.e("--->", "enter the service process!");
// 则此application::onCreate 是被service 调用的,直接返回
return;
}
//初始化
EMClient.getInstance().init(getApplicationContext(), options);
//在做打包混淆时,关闭debug模式,避免消耗不必要的资源
EMClient.getInstance().setDebugMode(true);
}
private String getAppName(int pID) {
String processName = null;
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
List l = am.getRunningAppProcesses();
Iterator i = l.iterator();
PackageManager pm = this.getPackageManager();
while (i.hasNext()) {
ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo) (i.next());
try {
if (info.pid == pID) {
processName = info.processName;
return processName;
}
} catch (Exception e) {
// Log.d("Process", "Error>> :"+ e.toString());
}
}
return processName;
}
}
e. 注册和登陆

注册要在子线程中执行
//注册失败会抛出HyphenateException
EMClient.getInstance().createAccount(username, pwd);//同步方法
EMClient.getInstance().login(userName,password,new EMCallBack() {//回调
@Override
public void onSuccess() {
EMClient.getInstance().groupManager().loadAllGroups();
EMClient.getInstance().chatManager().loadAllConversations();
Log.d("main", "登录聊天服务器成功!");
}
@Override
public void onProgress(int progress, String status) {
}
@Override
public void onError(int code, String message) {
Log.d("main", "登录聊天服务器失败!");
}
});
f. 发送消息
//创建一条文本消息,content为消息文字内容,toChatUsername为对方用户或者群聊的id,后文皆是如此
EMMessage message = EMMessage.createTxtSendMessage(content, toChatUsername);
//发送消息
EMClient.getInstance().chatManager().sendMessage(message);
g. 接收消息
msgListener = new EMMessageListener() {
@Override
public void onMessageReceived(List<EMMessage> messages) {
//收到消息
String result = messages.get(0).getBody().toString();
String msgReceived = result.substring(5, result.length() - 1);
Log.i(TAG, "onMessageReceived: " + msgReceived);
final MSG msg = new MSG(msgReceived, MSG.TYPE_RECEIVED);
runOnUiThread(new Runnable() {
@Override
public void run() {
mList.add(msg);
mAdapter.notifyDataSetChanged();
mRecyclerView.scrollToPosition(mList.size() - 1);
}
});
}
@Override
public void onCmdMessageReceived(List<EMMessage> messages) {
//收到透传消息
}
@Override
public void onMessageRead(List<EMMessage> list) {
}
@Override
public void onMessageDelivered(List<EMMessage> list) {
}
@Override
public void onMessageChanged(EMMessage message, Object change) {
//消息状态变动
}
};
接收消息的监听器分别需要在OnResume()和OnDestory()方法中注册和取消注册
EMClient.getInstance().chatManager().addMessageListener(msgListener);//注册
EMClient.getInstance().chatManager().removeMessageListener(msgListener);//取消注册
需要注意的是,当接收到消息,需要在主线程中更新适配器,否则会不能及时刷新出来

项目文件截图:

HyTYCEDIj4uugpEvJ59.jpg

到此,一个简单的及时聊天Demo已经完成,功能很简单,如果需要添加额外功能的话,可以自行参考官网,官网给出的教程还是很不错的!

最后希望大家能多多支持我,需要你们的支持喜欢!!
0
评论

【环信征文】集成环信,并实现消息免打扰 即时通讯 环信 消息免打扰 IM iOS

cokeyer 发表了文章 • 640 次浏览 • 2017-09-14 11:27 • 来自相关话题

现在大多数社交app都有消息免打扰功能,因为环信SDK主要是对即时通讯模块进行封装,因此如果要实现消息免打扰功能则需要开发者自己对此功能逻辑进行处理。
先解释一下,本人项目中对消息免打扰功能的定义:正常情况下,我们收到的每一条聊天消息都会收到小红点、声音、震动的提示。如果对某个好友设置消息免打扰功能,则只提示小红点,声音和震动则不再提示。

下面简述结合环信SDK时,此功能的实现方法。
环信将即时聊天的所有功能分为四大模块进行管理://聊天模块:
[EMClient sharedClient].chatManager
//好友模块 :
[EMClient sharedClient].contactManager
//群组模块 :
[EMClient sharedClient].groupManager
//聊天室模块:
[EMClient sharedClient].roomManager消息免打扰的功能借助聊天模块[EMClient sharedClient].chatManager的API就能实现。
一般来说,在app内不管当前在哪个界面,只要收到消息都需要被判断是否需要免打扰,因此可以在appdelegate里写如下代码,app通常都有tabBarController,那么也可以让tabBarController来实现如下代码。
首先让控制器tabBarController遵守代理EMChatManagerDelegate
然后成为代理
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];

EMChatManagerDelegate中有一个代理方法- (void)didReceiveMessages:(NSArray *)aMessages;实现此代理方法- (void)didReceiveMessages:(NSArray *)aMessages{
[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;
}
}方法中有一个aMessages参数。这个参数是一个消息组,每一个元素都是EMMessage类型的实例。
因为通常都只有一条信息。因此只需要取出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,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂 查看全部
现在大多数社交app都有消息免打扰功能,因为环信SDK主要是对即时通讯模块进行封装,因此如果要实现消息免打扰功能则需要开发者自己对此功能逻辑进行处理。
先解释一下,本人项目中对消息免打扰功能的定义:正常情况下,我们收到的每一条聊天消息都会收到小红点、声音、震动的提示。如果对某个好友设置消息免打扰功能,则只提示小红点,声音和震动则不再提示。

下面简述结合环信SDK时,此功能的实现方法。
环信将即时聊天的所有功能分为四大模块进行管理:
//聊天模块:
[EMClient sharedClient].chatManager
//好友模块 :
[EMClient sharedClient].contactManager
//群组模块 :
[EMClient sharedClient].groupManager
//聊天室模块:
[EMClient sharedClient].roomManager
消息免打扰的功能借助聊天模块[EMClient sharedClient].chatManager的API就能实现。
一般来说,在app内不管当前在哪个界面,只要收到消息都需要被判断是否需要免打扰,因此可以在appdelegate里写如下代码,app通常都有tabBarController,那么也可以让tabBarController来实现如下代码。
首先让控制器tabBarController遵守代理EMChatManagerDelegate
然后成为代理
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];

EMChatManagerDelegate中有一个代理方法
- (void)didReceiveMessages:(NSArray *)aMessages;
实现此代理方法
- (void)didReceiveMessages:(NSArray *)aMessages{
[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;
}
}
方法中有一个aMessages参数。这个参数是一个消息组,每一个元素都是EMMessage类型的实例。
因为通常都只有一条信息。因此只需要取出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,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂

qrcode_for_gh_bc92a063b4a2_430.jpg
0
评论

【环信征文】基于环信开发一个医疗APP-Ⅰ iOS 环信 即时通讯 IM

cokeyer 发表了文章 • 545 次浏览 • 2017-09-12 17:56 • 来自相关话题

公司又有了新项目,依然是含有即时通讯功能模块的项目。在经历了上个项目对环信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
{
//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;
}




本人github:https://github.com/BHAreslee
本人简书:http://www.jianshu.com/u/bb53043aaa00
以上就是集成环信时暂时发现的问题,欢迎大家分享你们遇到的问题,也欢迎加入QQ群:372251359,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂





 
项目完整源码 查看全部
公司又有了新项目,依然是含有即时通讯功能模块的项目。在经历了上个项目对环信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的如下方法

环信2.png

然而这个方法,环信并没有放在EaseMessageViewController.h成为公开方法。我们只需手动粘贴方法到.h,然后在自己的子类重写就可以了。

还有一个关于更多下图更多功能区域的问题

EaseChatBarMoreView.png

如上图所示,相册、拍照、视频等附加功能按钮,环信用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
{
//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;
}




本人github:https://github.com/BHAreslee
本人简书:http://www.jianshu.com/u/bb53043aaa00
以上就是集成环信时暂时发现的问题,欢迎大家分享你们遇到的问题,也欢迎加入QQ群:372251359,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂

qrcode_for_gh_bc92a063b4a2_430.jpg

 
项目完整源码
0
评论

环信公开课16期回放|环信智能鉴黄:用深度学习实现99%精准度的鉴黄服务 环信 环信公开课 环信智能鉴黄 鉴黄

beyond 发表了文章 • 1024 次浏览 • 2017-09-04 17:01 • 来自相关话题

   8月31日,环信公开课以“智能鉴黄”为主题,为大家普及了内容审查工作的前世今生,以及环信智能鉴黄算法、技术实现和行业解决方案。
 
关于环信智能鉴黄:
   随着移动互联网的飞速发展和信息量的猛增,大量的色情、赌博、暴力等不良信息图片夹杂在信息流中,严重影响着整个互联网的体验和健康发展。各大互联网公司为了保持自己所提供的服务不触犯国家法律和法规,使得鉴黄工作变得尤为重要。环信智能鉴黄服务基于深度学习的智能鉴黄算法,识别精准度高达99%,可以帮助企业完成95%的图片内容审查工作,节省90%的时间及人工成本。
环信公开课第16期分享内容:


















































环信公开课第16期视频回放:





参加环信公开课还有大礼相送:
恭喜手机尾号8985的leoNN同学成为本期公开课幸运观众,获得环信定制版瑞士军团双肩背包。

环信智能鉴黄免费体验请联系环信小助手,微信huanxin-hh 查看全部
   8月31日,环信公开课以“智能鉴黄”为主题,为大家普及了内容审查工作的前世今生,以及环信智能鉴黄算法、技术实现和行业解决方案。
 
关于环信智能鉴黄:

   随着移动互联网的飞速发展和信息量的猛增,大量的色情、赌博、暴力等不良信息图片夹杂在信息流中,严重影响着整个互联网的体验和健康发展。各大互联网公司为了保持自己所提供的服务不触犯国家法律和法规,使得鉴黄工作变得尤为重要。环信智能鉴黄服务基于深度学习的智能鉴黄算法,识别精准度高达99%,可以帮助企业完成95%的图片内容审查工作,节省90%的时间及人工成本。


环信公开课第16期分享内容:
001.png


002.png


003.png


004.png


005.png


006.png


007.png


008.png


009.png


010.png


环信公开课第16期视频回放:






参加环信公开课还有大礼相送:
恭喜手机尾号8985的leoNN同学成为本期公开课幸运观众,获得环信定制版瑞士军团双肩背包。

环信智能鉴黄免费体验请联系环信小助手,微信huanxin-hh
3a36009c9eb571b9a3a2797f17c4ae25.gif
1
评论

精通环信开发已成程序员招聘刚需?看别人家的招聘要求 环信 招聘

beyond 发表了文章 • 550 次浏览 • 2017-08-25 15:46 • 来自相关话题

今天在一个2000人技术交流群里看到一家互联网公司招聘Android/ios开发











一段不到200字的招聘要求,竟然出现了两次“环信”。眉头一紧,感觉这事不简单了!






去年在环信社区看到《今天面试一个自称两年经验的Android》《我又做了一次面试官》两篇面试经历还不以为然,没想到一年内作者预言成真,精通环信开发等第三方API开发已然成为程序员招聘刚需!

作为一个与时俱进的好司机赶紧打开X度搜索“如何精通环信开发”,还真让我找到了环信Alpha全国开发者培训计划,



环信alpha计划将对所有报名的ISV厂商和开发者提供技术、审核认证及发行等方面的支持。环信“Alpha计划”旨在为ISV和开发者们提供更加全面且专业的支持,帮助其在包括企业IM、协同OA、APP内社交、直播互动、IOT、智能硬件等领域挖掘产生更多落地有商业前景的优质项目,一起建设整个即时通讯云服务生态。

文末有小伙伴愿意去这家福建公司的发送简历到duc@easemob.com邮箱,暗号“我精通环信开发”,我们等的就是你! 查看全部
今天在一个2000人技术交流群里看到一家互联网公司招聘Android/ios开发

TIM截图20170825163121.png


timg.jpg


一段不到200字的招聘要求,竟然出现了两次“环信”。眉头一紧,感觉这事不简单了!

TIM图片20170825160503.jpg


去年在环信社区看到《今天面试一个自称两年经验的Android》《我又做了一次面试官》两篇面试经历还不以为然,没想到一年内作者预言成真,精通环信开发等第三方API开发已然成为程序员招聘刚需!

作为一个与时俱进的好司机赶紧打开X度搜索“如何精通环信开发”,还真让我找到了环信Alpha全国开发者培训计划
TIM截图20170825160913.png
环信alpha计划将对所有报名的ISV厂商和开发者提供技术、审核认证及发行等方面的支持。环信“Alpha计划”旨在为ISV和开发者们提供更加全面且专业的支持,帮助其在包括企业IM、协同OA、APP内社交、直播互动、IOT、智能硬件等领域挖掘产生更多落地有商业前景的优质项目,一起建设整个即时通讯云服务生态。

文末有小伙伴愿意去这家福建公司的发送简历到duc@easemob.com邮箱,暗号“我精通环信开发”,我们等的就是你!
0
评论

【移动战略说 · 第一期】智能硬件产品开发从0到1 环信 行业活动

beyond 发表了文章 • 413 次浏览 • 2017-08-14 19:09 • 来自相关话题

   据GSMA预期,到2020年,全球互联设备将突破270亿,移动互联设备有望达到105亿,新的市场机遇将进一步增多。自动上报家中燃气数据、远程开关气阀、精准透明计费、自动调节远程定时控制路灯等,基于新一代物联网的新型智慧产品正在走入我们的生产生活。

   开发一款智能硬件产品涉及的环节很多。本次活动,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-】幸运抽奖&自由交流分享嘉宾
















报名地址活动报名 查看全部
   据GSMA预期,到2020年,全球互联设备将突破270亿,移动互联设备有望达到105亿,新的市场机遇将进一步增多。自动上报家中燃气数据、远程开关气阀、精准透明计费、自动调节远程定时控制路灯等,基于新一代物联网的新型智慧产品正在走入我们的生产生活。

   开发一款智能硬件产品涉及的环节很多。本次活动,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-】幸运抽奖&自由交流
分享嘉宾

30972779689807524.jpeg


30242778644313753.jpg


30852779689957552.jpeg


报名地址活动报名
0
评论

月薪五千和五万销售的区别:一只丑桔引发的大单子(环信真实案例改编) 丑橘 环信

beyond 发表了文章 • 595 次浏览 • 2017-08-04 17:27 • 来自相关话题

​​ 




 这是一个初冬的早晨。王向东迈着轻快的步伐,走进了“黄桃园”集团大楼,直奔物业管理公司CEO陶福成办公室。与陶总交换名片后,陶总看着名片,抬头说:“你就是那个什么环信公司的销售经理?你在电话上说有一笔大生意要谈?简单说说吧,我只有十分钟时间。”陶总抬手看了眼手表。

王向东从包里拿出一只丑桔,放到大班台上,说:“这是丑桔,想必陶总吃过。”陶总微微点了下头。“我要和陶总谈的生意与丑桔有关。”陶总好奇地问:“我一个物业公司,怎么会和丑桔生意有关呢?”

“我先问陶总一个经营上的问题。现在由于人工费用上涨很快,物业公司从业主收来的物业费却多年没有做相应的调整,物业公司的利润逐年下滑,甚至出现亏损,不知是不是属实?”陶总点了下头,心里却想你个毛头小子还和我说盈亏,真不知天高地厚。

“所以物业公司不得不想别的办法,拓展收入来源来弥补物业费的亏空。”陶总一笑:“所以你想推荐丑桔生意?”王向东指着台上的丑桔说:“是的!咱们算笔账。陶总物业公司管理着三个高档小区,一共有3万2千住户。”陶总眼睛从半眯状到睁大状。“丑桔是新开发的一个水果品种,口味独特,很受欢迎,超市里卖到24块每公斤。如果能以18块每公斤卖给您的住户,想必一定卖的很好。如果直接和原产地进货,进货价格是10块每公斤,这样的话毛利是8块每公斤。假设有1万5千住户每户购买一箱20公斤,总共30万公斤,毛利240万。”陶总深深点了下头:“240万不少,但对于我这样的物业公司来说,还真不是什么了不起的收入。”

“如果我说丑桔贡献240万,精品东北大米贡献300万,陕西红富士苹果贡献300万。。。。。。这些收入合起来贡献2000万毛利,够不够大?”“够大!但是我要把这个生意做成,需要店面,仓库,运输,配送,押款。。。。。。费用支出多大,你知道吗?”

“知道。但如果我有办法把这些费用降到零呢?”陶总瞪大了眼睛:“什么办法?”“就是利用移动互联技术,构建客服平台,起到一石三鸟作用。”“哪三鸟?”“一是解决咱们物业管理老本行与住户的交流和住户服务请求和相应;二是形成电子商务平台,网上推广产品;三是网上缴费,既交物业费,又是电子商务资金流通道。”

陶总站起来,拉住王向东的手:“快说说,你能帮我建设这个什么客服平台吗?”“可以,环信就是这方面的专家。”

陶总快步走到门口,对秘书说:“马上通知总裁办主任,客服部主管,IT部主管,财务部主管到我这里开会!”

几分钟后,主管们到齐。陶总说:“来,跟大家介绍一下这位小兄弟,王向东,他可是给我们带来了好东西,先听听他的介绍。”王向东站起来谦逊地个跟每个主管打了招呼,才坐下简要地介绍了刚才跟陶总交流的内容。陶总站起来说:“王兄弟带来的方案,揭开了困扰我们好长时间的难题,有了这个客服平台,可以大幅度提高我们的物业服务质量,同时开辟了扩大收入的渠道,是个非常有价值的建议。我要求你们和小王兄弟一起尽快拿出方案,做出预算,在2个月内上线!”

所有主管都响亮地答应下来,同时心里在猜测这位“小王兄弟”后台有多硬,是陶总的什么关系?

没过几天,方案出来了,预算也出来了。一期先建设即时通讯软件平台和客户交互平台,建设费用320万;二期建设智能客服机器人系统,建设费用180万;采用vpc形式,每年支付环信托管费用50万;环信提供战略和业务咨询,每年咨询费40万。

一个由丑桔引起的“大单子”就这么发生了!(由环信真实销售案例改编,文中均为化名) 查看全部
​​ 
timg.jpg

 这是一个初冬的早晨。王向东迈着轻快的步伐,走进了“黄桃园”集团大楼,直奔物业管理公司CEO陶福成办公室。与陶总交换名片后,陶总看着名片,抬头说:“你就是那个什么环信公司的销售经理?你在电话上说有一笔大生意要谈?简单说说吧,我只有十分钟时间。”陶总抬手看了眼手表。

王向东从包里拿出一只丑桔,放到大班台上,说:“这是丑桔,想必陶总吃过。”陶总微微点了下头。“我要和陶总谈的生意与丑桔有关。”陶总好奇地问:“我一个物业公司,怎么会和丑桔生意有关呢?”

“我先问陶总一个经营上的问题。现在由于人工费用上涨很快,物业公司从业主收来的物业费却多年没有做相应的调整,物业公司的利润逐年下滑,甚至出现亏损,不知是不是属实?”陶总点了下头,心里却想你个毛头小子还和我说盈亏,真不知天高地厚。

“所以物业公司不得不想别的办法,拓展收入来源来弥补物业费的亏空。”陶总一笑:“所以你想推荐丑桔生意?”王向东指着台上的丑桔说:“是的!咱们算笔账。陶总物业公司管理着三个高档小区,一共有3万2千住户。”陶总眼睛从半眯状到睁大状。“丑桔是新开发的一个水果品种,口味独特,很受欢迎,超市里卖到24块每公斤。如果能以18块每公斤卖给您的住户,想必一定卖的很好。如果直接和原产地进货,进货价格是10块每公斤,这样的话毛利是8块每公斤。假设有1万5千住户每户购买一箱20公斤,总共30万公斤,毛利240万。”陶总深深点了下头:“240万不少,但对于我这样的物业公司来说,还真不是什么了不起的收入。”

“如果我说丑桔贡献240万,精品东北大米贡献300万,陕西红富士苹果贡献300万。。。。。。这些收入合起来贡献2000万毛利,够不够大?”“够大!但是我要把这个生意做成,需要店面,仓库,运输,配送,押款。。。。。。费用支出多大,你知道吗?”

“知道。但如果我有办法把这些费用降到零呢?”陶总瞪大了眼睛:“什么办法?”“就是利用移动互联技术,构建客服平台,起到一石三鸟作用。”“哪三鸟?”“一是解决咱们物业管理老本行与住户的交流和住户服务请求和相应;二是形成电子商务平台,网上推广产品;三是网上缴费,既交物业费,又是电子商务资金流通道。”

陶总站起来,拉住王向东的手:“快说说,你能帮我建设这个什么客服平台吗?”“可以,环信就是这方面的专家。”

陶总快步走到门口,对秘书说:“马上通知总裁办主任,客服部主管,IT部主管,财务部主管到我这里开会!”

几分钟后,主管们到齐。陶总说:“来,跟大家介绍一下这位小兄弟,王向东,他可是给我们带来了好东西,先听听他的介绍。”王向东站起来谦逊地个跟每个主管打了招呼,才坐下简要地介绍了刚才跟陶总交流的内容。陶总站起来说:“王兄弟带来的方案,揭开了困扰我们好长时间的难题,有了这个客服平台,可以大幅度提高我们的物业服务质量,同时开辟了扩大收入的渠道,是个非常有价值的建议。我要求你们和小王兄弟一起尽快拿出方案,做出预算,在2个月内上线!”

所有主管都响亮地答应下来,同时心里在猜测这位“小王兄弟”后台有多硬,是陶总的什么关系?

没过几天,方案出来了,预算也出来了。一期先建设即时通讯软件平台和客户交互平台,建设费用320万;二期建设智能客服机器人系统,建设费用180万;采用vpc形式,每年支付环信托管费用50万;环信提供战略和业务咨询,每年咨询费40万。

一个由丑桔引起的“大单子”就这么发生了!(由环信真实销售案例改编,文中均为化名)
0
评论

【环信征文】|两处小改动,解决环信V3.0官方版本关于转发的bug 转发 即时通讯 环信 IM

cokeyer 发表了文章 • 516 次浏览 • 2017-08-02 00:57 • 来自相关话题

    (本人github:https://github.com/BHAreslee)(若转载,请告知本人并附上原文链接,谢谢)
    
    最近接手了一个集成即时通讯功能的项目,用的是环信的SDK。用环信的接口可以快速实现即时通讯的很多功能。并且对官方demo稍加改动基本能够满足项目需求。真机测试时,发现图片的转发,每次都是转发失败。我开始以为是我集成时有疏漏,逐行检查代码。发现并不是我的问题。从app store下载的官方demo同样是转发失败!!坑我啊!!原因是ContactListSelectViewController这个控制器里无法正确获取到想转发的图片的缓存地址。
修改如下图:





ContactListSelectViewController.m
代码拷走直接用- (BOOL)messageViewController:(EaseMessageViewController *)viewController
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;
}ContactListSelectViewController是取数据,那么存数据要在ChatViewController控制器做存数据的操作。消息类型写死为EMChatTypeChat,是因为,不论是从单聊界面转发,还是从群聊界面转发,都只能转发给个人,所以这里写死,目前没有问题。
如下图:





ChatViewController.m
代码拷走直接用#pragma mark - EMUserListViewControllerDelegate
- (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);
}
}
}上面一定要判断一下消息体类型,只有消息体为图片类型(EMMessageBodyTypeImage)才需要保存图片本地。如果不做判断的话,点击气泡马上崩掉。
个人感觉虽然能解决图片转发的问题,但并不是最好的解决办法,虽然对环信demo的代码改动最少。有更好的办法,欢迎在评论区交流。
(本人github:https://github.com/BHAreslee)(若转载,请告知本人并附上原文链接,谢谢) 查看全部
    (本人github:https://github.com/BHAreslee)(若转载,请告知本人并附上原文链接,谢谢)
    
    最近接手了一个集成即时通讯功能的项目,用的是环信的SDK。用环信的接口可以快速实现即时通讯的很多功能。并且对官方demo稍加改动基本能够满足项目需求。真机测试时,发现图片的转发,每次都是转发失败。我开始以为是我集成时有疏漏,逐行检查代码。发现并不是我的问题。从app store下载的官方demo同样是转发失败!!坑我啊!!原因是ContactListSelectViewController这个控制器里无法正确获取到想转发的图片的缓存地址。
修改如下图:

2893691-7bfd41d8c42b5f3d.png

ContactListSelectViewController.m
代码拷走直接用
- (BOOL)messageViewController:(EaseMessageViewController *)viewController
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;
}
ContactListSelectViewController是取数据,那么存数据要在ChatViewController控制器做存数据的操作。消息类型写死为EMChatTypeChat,是因为,不论是从单聊界面转发,还是从群聊界面转发,都只能转发给个人,所以这里写死,目前没有问题。
如下图:

2893691-7beb949a62e8035f.png

ChatViewController.m
代码拷走直接用
#pragma mark - EMUserListViewControllerDelegate
- (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);
}
}
}
上面一定要判断一下消息体类型,只有消息体为图片类型(EMMessageBodyTypeImage)才需要保存图片本地。如果不做判断的话,点击气泡马上崩掉。
个人感觉虽然能解决图片转发的问题,但并不是最好的解决办法,虽然对环信demo的代码改动最少。有更好的办法,欢迎在评论区交流。
(本人github:https://github.com/BHAreslee)(若转载,请告知本人并附上原文链接,谢谢)
0
评论

环信荣膺“2017未来独角兽企业”,做商业的连接器 独角兽 新闻资讯 环信

新闻资讯 发表了文章 • 794 次浏览 • 2017-07-25 11:29 • 来自相关话题

 独角兽企业往往聚集了行业里大多的资源,随着技术、人才、资金的积累,其在行业里的地位与机会将逐步放大,前进愈发顺利,发展迎风而起。近日,由中国科学院《互联网周刊》杂志评选的“2017未来独角兽企业TOP150”榜单正式揭晓,有着国际领先的企业级软件服务提供商愿景的环信凭借在即时通讯云和SaaS客服领域的行业深耕和迅猛发展,以全国榜单第130名位居垂直行业第一。




“连接人与人”,“连接人与商业”的愿景支撑垂直行业第一

   企业服务市场是一块大蛋糕,练就的是技术内功,靠的是对市场趋势的准确把握,环信以用户需求为出发点近期推出客户互动云(CEC),环信CEC基于全球领先的即时通讯云技术,通过人工智能和大数据赋能,依托多渠道接入管理、精准用户画像、智能客服机器人、客户之声、智能质检、视频客服等SaaS客服体系为包括保险、证券、金融、教育、电商等行业提供了从客户互动渠道、到客户服务、再到精准营销的全流程客户互动解决方案。

   环信的起家产品“即时通讯云”,承担环信“连接人与人”的商业愿景,为开发者提供基于移动互联网的即时通讯能力,作为全球最大的即时通讯云厂商已经广泛应用服务13万余APP客户,环信全面支持Android、iOS、Web等多种平台,在流量、电量、长连接、语音、位置、安全等能力做了极致的优化,让移动开发者摆脱繁重的移动IM通讯底层开发,极大限度地缩短产品开发周期,二十四时间内即可让App拥有移动IM能力。目前环信即时通讯云已经拓展推出了包括直播、社交大数据、红包、鉴黄、视频人脸特效、短信验证码等增值服务。

   而“环信移动客服”是即时通讯云“连接人与人”场景的一个延伸到“连接人与商业”,包括网页在线客服、社交媒体客服(微博、微信)、APP内置客服、工单和呼叫中心等多种渠道均可一键接入。基于环信业界领先的IM长连接技术保证消息必达,并通过智能客服机器人技术降低人工客服工作量。同时,基于人工智能和大数据挖掘的客户旅程透析产品”环信客户声音”能够帮助企业优化运营,提高跨渠道客服体验。

   2016年,基于开发即时通讯云和移动客服的基础上,环信对已有产品进行了再次的研发和升级,针对已有在包括电商、保险、证券、金融、教育等优势行业的积累基础上,着手开发人工智能 —— “环信智能客服机器人”。他们希望在不降低用户体验的情况下,尽可能地解决商家日益增长的客服成本和海量客服请求之间的天然矛盾。

   比如,我们在移动端通过国美在线下单后,产品遇到的任何问题,通过IM窗口和客服咨询,这个沟通通道就是环信即时通讯云在提供底层通信服务。环信移动客服依托智能客服机器人很大程度上为企业节约了人力成本,众多保险公司已经通过部署环信智能客服机器人来提高客服效率。环信客户声音提高了跨渠道的客户服务体验,帮助企业优化运营,实现了客户中心完成从成本中心向价值中心的转化,国内某标杆教育机构已经在部署完环信客服声音以后尝到了客户转化率、客单价双升的甜头。

   与此同时,环信还一直利用自己的大数据平台产品给客户提供增值服务,让客户通过即时通讯云和移动客服等产品的后台数据,分析得出自己产品的适用人群、产品体验和活跃度等。让客户能更好地改善自己的产品,更好地服务消费者。

   环信的所有更新、改变与尝试,都是在围绕着一个行业,或者说是一个目标在努力。走上行业的顶峰之后,面临坦途时就会懈怠很多,但他们似乎仍然没有放弃向更高峰的攀登。

   2016年环信作为国内唯一的SaaS厂商荣膺Gartner 2016 Cool Vendor,2017年3月环信刚获得由经纬中国领投、银泰嘉禾跟投的1.03亿元C轮融资,显示出包括国际顶级研究机构和资本市场对于环信商业模式和发展前景的认可。正是得益于包括红杉资本、经纬中国、SIG和银泰嘉禾的鼎力支持,保障了环信持续巨额的研发投入,形成了公司业务发展的正向循环。

志存高远方能有所大成

   独角兽企业往往聚集了行业里大多的资源,随着技术、人才、资金的积累,其在行业里的地位与机会将逐步放大,前进愈发顺利,发展迎风而起。优势会被放大,引领、变革行业发展的责任则愈发凸显。换句话说,独角兽企业不仅仅是行业的佼佼者,更重要的,它是行业的领跑者、推动者。

   身为未来独角兽企业,要以行业推动者自居,以创新破迷局,以诚信守正心,以担当为己任。只有致力于市场需求的满足,行业发展瓶颈的突破,才会在纷乱的市场竞争中把握准方向,守得住初心,冲出迷雾,把握未来。

独角兽是一种荣耀的名片,更意味着一种担当与责任。 查看全部
 独角兽企业往往聚集了行业里大多的资源,随着技术、人才、资金的积累,其在行业里的地位与机会将逐步放大,前进愈发顺利,发展迎风而起。近日,由中国科学院《互联网周刊》杂志评选的“2017未来独角兽企业TOP150”榜单正式揭晓,有着国际领先的企业级软件服务提供商愿景的环信凭借在即时通讯云和SaaS客服领域的行业深耕和迅猛发展,以全国榜单第130名位居垂直行业第一。
ea790d9dly1fhv495ni8gj211j0pyn6b.jpg

“连接人与人”,“连接人与商业”的愿景支撑垂直行业第一

   企业服务市场是一块大蛋糕,练就的是技术内功,靠的是对市场趋势的准确把握,环信以用户需求为出发点近期推出客户互动云(CEC),环信CEC基于全球领先的即时通讯云技术,通过人工智能和大数据赋能,依托多渠道接入管理、精准用户画像、智能客服机器人、客户之声、智能质检、视频客服等SaaS客服体系为包括保险、证券、金融、教育、电商等行业提供了从客户互动渠道、到客户服务、再到精准营销的全流程客户互动解决方案。

   环信的起家产品“即时通讯云”,承担环信“连接人与人”的商业愿景,为开发者提供基于移动互联网的即时通讯能力,作为全球最大的即时通讯云厂商已经广泛应用服务13万余APP客户,环信全面支持Android、iOS、Web等多种平台,在流量、电量、长连接、语音、位置、安全等能力做了极致的优化,让移动开发者摆脱繁重的移动IM通讯底层开发,极大限度地缩短产品开发周期,二十四时间内即可让App拥有移动IM能力。目前环信即时通讯云已经拓展推出了包括直播、社交大数据、红包、鉴黄、视频人脸特效、短信验证码等增值服务。

   而“环信移动客服”是即时通讯云“连接人与人”场景的一个延伸到“连接人与商业”,包括网页在线客服、社交媒体客服(微博、微信)、APP内置客服、工单和呼叫中心等多种渠道均可一键接入。基于环信业界领先的IM长连接技术保证消息必达,并通过智能客服机器人技术降低人工客服工作量。同时,基于人工智能和大数据挖掘的客户旅程透析产品”环信客户声音”能够帮助企业优化运营,提高跨渠道客服体验。

   2016年,基于开发即时通讯云和移动客服的基础上,环信对已有产品进行了再次的研发和升级,针对已有在包括电商、保险、证券、金融、教育等优势行业的积累基础上,着手开发人工智能 —— “环信智能客服机器人”。他们希望在不降低用户体验的情况下,尽可能地解决商家日益增长的客服成本和海量客服请求之间的天然矛盾。

   比如,我们在移动端通过国美在线下单后,产品遇到的任何问题,通过IM窗口和客服咨询,这个沟通通道就是环信即时通讯云在提供底层通信服务。环信移动客服依托智能客服机器人很大程度上为企业节约了人力成本,众多保险公司已经通过部署环信智能客服机器人来提高客服效率。环信客户声音提高了跨渠道的客户服务体验,帮助企业优化运营,实现了客户中心完成从成本中心向价值中心的转化,国内某标杆教育机构已经在部署完环信客服声音以后尝到了客户转化率、客单价双升的甜头。

   与此同时,环信还一直利用自己的大数据平台产品给客户提供增值服务,让客户通过即时通讯云和移动客服等产品的后台数据,分析得出自己产品的适用人群、产品体验和活跃度等。让客户能更好地改善自己的产品,更好地服务消费者。

   环信的所有更新、改变与尝试,都是在围绕着一个行业,或者说是一个目标在努力。走上行业的顶峰之后,面临坦途时就会懈怠很多,但他们似乎仍然没有放弃向更高峰的攀登。

   2016年环信作为国内唯一的SaaS厂商荣膺Gartner 2016 Cool Vendor,2017年3月环信刚获得由经纬中国领投、银泰嘉禾跟投的1.03亿元C轮融资,显示出包括国际顶级研究机构和资本市场对于环信商业模式和发展前景的认可。正是得益于包括红杉资本、经纬中国、SIG和银泰嘉禾的鼎力支持,保障了环信持续巨额的研发投入,形成了公司业务发展的正向循环。

志存高远方能有所大成

   独角兽企业往往聚集了行业里大多的资源,随着技术、人才、资金的积累,其在行业里的地位与机会将逐步放大,前进愈发顺利,发展迎风而起。优势会被放大,引领、变革行业发展的责任则愈发凸显。换句话说,独角兽企业不仅仅是行业的佼佼者,更重要的,它是行业的领跑者、推动者。

   身为未来独角兽企业,要以行业推动者自居,以创新破迷局,以诚信守正心,以担当为己任。只有致力于市场需求的满足,行业发展瓶颈的突破,才会在纷乱的市场竞争中把握准方向,守得住初心,冲出迷雾,把握未来。

独角兽是一种荣耀的名片,更意味着一种担当与责任。
0
评论

在线教育+直播,千亿市场的新入口 环信 APICloud 行业活动

新闻资讯 发表了文章 • 340 次浏览 • 2017-07-20 11:13 • 来自相关话题

百度报告显示,互联网教育市场在2016年的增长率位居全行业第三,预计2017年的市场规模将突破2800亿元。AI、VR、AR等新技术的日趋成熟也给产品创新带来了新的可能。在激烈的竞争中,如何提高开发效率,快速将产品推向市场;如何借助前沿技术,给用户带来创新的体验,赢得市场成为企业关注的重点。本次活动,APICloud将联合合作伙伴从在线教育类App的开发及创新技术应用等方向,跟大家聊聊直播给在线教育带来的新机会。




【活动时间】2017年7月29日(周六),13:30-16:30

【活动地点】创业邦Demo Space(北京市海淀区中关村创业大街11号海置创投大厦7层)

【面向人群】在线教育企业管理层、产品负责人、技术负责人,其他在线教育从业者

【活动咨询/合作】请加微信:appdev1,备注729





【13:30-14:00】签到

【14:00-14:40】在线教育App开发面临的挑战

内容概要:如何冲破在线教育的技术壁垒;在线教育业务落地平台选型对比;在线教育类App实例分析

【14:40-15:20】视频内容版权保护技术在在线教育中的应用

内容概要:视频盗版的发现、防范及证据保存,以及如何保护视频内容的版权

【15:20-16:00】直播和在线教育结合的实践经验

内容概要:直播和在线教育相结合的特点与好处;直播与线下培训、图文、音频分享的区别与特点;线上直播分享的运营和推广经验;IT 在线教育的未来发展趋势

【16:00-】幸运抽奖&自由交流
























活动报名:报名地址 查看全部
百度报告显示,互联网教育市场在2016年的增长率位居全行业第三,预计2017年的市场规模将突破2800亿元。AI、VR、AR等新技术的日趋成熟也给产品创新带来了新的可能。在激烈的竞争中,如何提高开发效率,快速将产品推向市场;如何借助前沿技术,给用户带来创新的体验,赢得市场成为企业关注的重点。
本次活动,APICloud将联合合作伙伴从在线教育类App的开发及创新技术应用等方向,跟大家聊聊直播给在线教育带来的新机会。
30102748471066586.png

【活动时间】2017年7月29日(周六),13:30-16:30

【活动地点】创业邦Demo Space(北京市海淀区中关村创业大街11号海置创投大厦7层)

【面向人群】在线教育企业管理层、产品负责人、技术负责人,其他在线教育从业者

【活动咨询/合作】请加微信:appdev1,备注729



01.png

【13:30-14:00】签到

【14:00-14:40】在线教育App开发面临的挑战

内容概要:如何冲破在线教育的技术壁垒;在线教育业务落地平台选型对比;在线教育类App实例分析

【14:40-15:20】视频内容版权保护技术在在线教育中的应用

内容概要:视频盗版的发现、防范及证据保存,以及如何保护视频内容的版权

【15:20-16:00】直播和在线教育结合的实践经验

内容概要:直播和在线教育相结合的特点与好处;直播与线下培训、图文、音频分享的区别与特点;线上直播分享的运营和推广经验;IT 在线教育的未来发展趋势

【16:00-】幸运抽奖&自由交流



02.png

03.jpg


04.png


05.jpeg


06.jpeg

活动报名:报名地址
0
评论

经纬熊飞:企业服务行业如何先赢而后战 环信 新闻资讯

新闻资讯 发表了文章 • 747 次浏览 • 2017-07-04 16:01 • 来自相关话题

   




   企业服务并非科技新兴领域,早在上世纪70年代,美国已出现SAP、微软、Oracle这样的ToB公司,成长为巨头。在国内,由于经济快速增长及人力成本低廉,一直以来,企业服务市场属于少为人知的领域。2012年起,国内GDP增速放缓,人力成本增长问题凸显,同时2013年棱镜门事件后,国内加大去IOE力度,也为企业级服务创业提供了较好的发展土壤。

   经纬创投是最早布局企业服务领域的机构。从2012年开始,经过5 年的探索与沉淀,目前在经纬系布局的近50家企业服务创业项目中,有北森、销售易、七牛、永洪BI、OneAPM、环信、GrowingIO、亿方云、上上签、佳格数据、盖雅工场、Pingcap等已初露锋芒。

   今天的文章来自我们与经纬董事总经理熊飞的一次交流,希望对你有所启发。以下,Enjoy:“企业服务项目到底怎么投?两个核心关键点。

Q:在我看来,做VC有个能力:当有经验积累后,挑项目的时候,是能够预判出项目发展路径的。但问题在于,当一个项目到了一定的标准,投与不投,是多维度进行判断的。比如Saas,中国Saas目前看来还比较难做,如果满足了基本条件KPI达标,那么超越KPI的标准是什么?在此之上经纬看重什么?

熊飞:第一点,是个大市场。比如CRM,再比如人力资源,也有很多细分项目,比如做核心人力、做招聘,但肯定不只是做一个报表工具。企业服务公司所处的市场足够大,这是核心。企业服务本身是让企业为该职能相关痛点去付费。而销售、HR、客服、财务等职能,是企业最核心职能,痛点的商业价值最大。所以大市场的基础,是该产品关注的是企业核心职能,以及解决的是核心职能中的核心痛点。

第二点,要考虑这个项目是不是处在浪尖位置。我们经常说投浪尖。三五年前投Saas,那个时候对于早期项目来说是一个浪尖。过去一两年投infrastructure(IT底层架构),也是个浪尖,比如说marketing automation(营销自动化)、iot等等。所以如果你现在做客服Saas创业就不是浪尖了,因为已有环信这些头部项目。浪尖的优势在于你是最早做的,所有资源都给你。

总结一下:它应该是这个领域最早的探路者,且速度一直高速增长。如果市场够大,并处于浪尖的位置,是先人半步与先人一步的机会,这个我们是非常看重的。“企业服务,产品技术导向的创始人更有优势。

Q:在这两点满足的前提下,关于团队层面,有什么体会?你们看重创始人的哪些特质?

熊飞:我觉得没有完美决策,我们常说VC是一个判断+运气的连续体,但投ToB靠判断会更多一些。做的每一个判断都希望结果是大概率事件,但所谓大概率也只能证明这个项目七八成应该投,但没有百分之百。

我个人倾向产品技术导向的创始人。在我看来,投产品技术导向的团队没什么下行风险,但上行收益巨大;因为产品技术好,最差情况就是没销售,但优势在于产品壁垒高,一旦市场找到感觉,找到销售合伙人,业务可能就会以5 倍、10倍增速发展。但纯销售导向创始人,早期业务起来比较快,但如果竞争对手是产品技术导向,对手一旦找到市场感觉和销售合伙人,下行风险就很大。

宏观来看,企业服务公司产品技术的护城河宽不宽,有没有留下足够多的安全边际,是我们很关注的点。这也是经纬系企业服务公司,为什么普遍发展很扎实、高速健康增长的原因。我们在投的时候,是希望跟产品技术导向、着重于打磨自己产品的创始人去沟通。

Q:说到产品和技术,其实相对难判断,ToC可能是看KPI;ToB的话,特别是一些早期公司除了看创始人过去的背景,怎么去判断呢?

熊飞:我觉得有几点,第一,做reference track,团队的能力,是可以通过reference相当程度判断。

第二,团队投每个领域都会投入很多的时间,要了解趋势,知道有哪些领先的公司。形成初步投资假设。再去和公司聊发展、聊产品,就能够比较快的判断出这个团队的视野、产品意识。

第三,就是一些标杆客户的反馈,这个是实打实的。做到这三点就很快能做出不赖的判断。“先赢而后战。

Q:经纬五年前就开始布局ToB,坚持到现在。在我看来,五年前的时候应该非常寂寞。直到2015年大家才普遍觉得 ToB是风口,这期间你是怎么去判断的?

熊飞:投ToB其实投的创始人的特质,往往都是比较踏实、稳重、重逻辑、重积累,团队专注某一个方向;ToC则不然,可能需要创始人是愿意快速变化的人——这两类人是完全不一样的。

另外,我个人觉得在中国投ToB的长期回报会比美国投ToB好很多。原因在于:

在美国,因为Salesforce、Workday等已有领先者产品的市场占有度很高,导致创业公司长不动、长不大,很多都是10亿美金、12亿美金被并购。在中国,ToB领域竞争并不激烈,因为没有产品供给,很多公司创业两年,就可以做中国500强的生意,这在美国不可想象。所以从长期来看,国内 ToB创业公司的天花板显著的高。

另外,从运营效率来看国内Saas创业公司也有不小优势。美国很多Saas公司大概做到1 个亿美金收入还在不停亏损,还要不停地往前赶,很难实现现金流打平。但在国内,至少我们投的很多Saas公司做到亿元人民币量级的时候,或者之后一年,就有机会做到单月盈亏平衡。

最后,从经纬角度来说,最核心是投产品高壁垒和护城河足够宽的项目,比如像HR领域的北森现在发展很好,五年后还会发展很好、再比如销售易、环信、GrowingIO……这些公司现在很好,我们也能看到它们五年后都会很好。

大核心、大前提还是投到最优秀的公司。我很喜欢《孙子兵法》里面的一句话——先胜而后战,你要先确保你大概率能赢的再去打。张颖有一句话,叫自强则万强,只要把产品、技术做到行业内非常领先,我觉得融资的问题都是业务问题。“企业服务这么火,创业到底是该切入大客户还是小客户?

熊飞:经纬投企业服务五年时间,这个行业的发展是超出预期的。几点原因:

中国人力成本的提高到了一个转折点。我经常举例子,六年前一个人工资大概3000元 / 月,一台电脑5000元。现在反过来了,一个人工资5000元,笔记本电脑的价格只有2000元。企业主是很理性的,以前2:1,现在变1:2了,他希望更大投入提高效率。而且,最近中国经济增长放缓,三年前企业主都在谈拉贷款、扩产能,但是现在想的是如何高效地去提高利润,也落在软件上。

我有个观察,ToB市场爆发,不是留给海外巨头,而是给国内创业企业的巨大机会。很像七八年前智能手机的市场,当时移动手机市场刚起来,大家知道苹果、三星非常好,可是一台手机要六七千块。所以需求起来的时候,性价比更高的国产手机,小米、OPPO、华为、中兴爆发式增长。ToB领域也类似,软件从最初大型和超大型企业的刚需,过渡到中型以上企业的刚需,而这个爆发的市场更关注性价比和产品体验,使得国内创业公司成为最大受益方。

Q:那么现在如果再做企业服务创业的话,是否理想的客户反而不是中海油、中石油,而应该是中型企业?

熊飞:我们投的大部分成功企业服务公司,不是一上来就瞄准中海油等超大型企业,无法一击即中,因为超大型企业的功能需求太多了。它们往往是先瞄准100人到300人的中型企业,或者是中型偏小型企业,要先快速上手,再逐年向上走,今年可能是服务100人到300人的企业,明年可能是300人到800人,后年可能是1000人到2000人。随着功能不断地添加,这是一个“逆流而上”的策略。

Q:有个现象非常有趣——很多企业服务创业者会在两头摇摆,以前做大客户出身的会非常痛恨做大企业,过去诸如催款、服务等等小事,CEO、工程师动不动就被叫过去处理问题。 经历过做大客户的,现在就愿意做小企业或者中小企业,他觉得我是产品说话,不会像以前那样被牵着鼻子走;但又会发现一个新问题:收费有点困难。小企业消失得快,或者是需求率不高。他们就像一个钟摆在不断摇摆。你怎么看?

熊飞:我觉得一定要做中大企业。一点一点往上。全球IT投入90% 来自于财富两千强,再90% 来自于两万强,你做不到两万强的生意,你就只有1% 的市场,自然这个公司能够成为一个很大的、很牛的公司的概率也变得很小。“投资的魅力所在:不断地去证伪。

Q:经纬企业服务团队做的最快的一次决策多长时间?为什么?

熊飞:最快决策是当天见完觉得可以投,就签下TS。能这么快的原因是,团队在该领域已做了足够多思考,见了足够多公司,当遇到这家公司时,其实是捅破了这层“窗户纸”。

另外,我认为投资的魅力所在,是一个不断证伪的过程。VC这个行业是一个idea business,所有的回报取决于你的idea质量,本质在于两点:

第一,generate idea的能力,就是说你的视野够广,经常在一线跑,有很多的思考。

第二,证伪idea的能力。如果你没有证伪idea的能力,那就变成了自己做空中楼阁的假设。

经纬企业服务团队每天都在不断地拼命去证伪——比如17年初定了三四个ToB的主方向,现在看有两个觉得不错;但是已有一个觉得机会不大,还有一个待判断。所以每个季度都在推翻自己投资的思路和假设。

Q:Peter Thiel的书《Zero to One》里说过创投要有一个非常规的想法。如果说你提一个跟ToB相关的观点,比如“我觉得我这么认为,但是其他的投资人未必是这么认为的”。如果有,是什么?

熊飞:我觉得是中国企业服务创业公司机会规模,10倍于目前美国企业服务创业机会。原因在于,美国在enterprise是三波的创业浪潮,第一波是上世纪70年代到80年代,像SAP、微软、Oracle,他们现在都是1000亿到3000亿美金的公司。第二波是云计算,从上世纪90年代末到2000下半叶,这时崛起了Salesforce、workday、NetSuite、ServiceNow这一系列公司,从几十亿美金到六百亿美金。第三波就是现在,现在有一些AI企业服务创业公司开始起来。

在中国,这三波发展是融合在一起爆发的,三、四年前没有人谈企业服务,现在所有人都在谈企业服务,所有人都在谈企业服务直接上云计算,所有人都在谈企业服务和AI的结合。所以三波浪潮的合并,使得目前中国企业服务创业公司的天花板显著的高。

Q:会不会有这样一个趋势,SAP这些公司等于是压在中国公司头上的石头,首先会有一批企业服务本土企业。未来中国公司出海,反过来最后会不会变成中国公司把SAP干掉?

熊飞:第一,我不知道会不会干掉,但我相信未来的5 到10年中国的企业服务公司会在全球企业服务市场将占据重要地位,原因有两点:一是随着中国企业的出海而出海;二是价格优势,SAP、Oracle现在是一个85分到90分的产品,但我们中国的企业服务产品现在很努力地在赶上,虽然可能还是一个75分的产品,但是价格是其1 /3。三是,未来中国企业的最佳实践,会成为第三世界国家(企业服务下一波机会所在地)的最佳实践。 查看全部
   
201707039141499064337064.jpg

   企业服务并非科技新兴领域,早在上世纪70年代,美国已出现SAP、微软、Oracle这样的ToB公司,成长为巨头。在国内,由于经济快速增长及人力成本低廉,一直以来,企业服务市场属于少为人知的领域。2012年起,国内GDP增速放缓,人力成本增长问题凸显,同时2013年棱镜门事件后,国内加大去IOE力度,也为企业级服务创业提供了较好的发展土壤。

   经纬创投是最早布局企业服务领域的机构。从2012年开始,经过5 年的探索与沉淀,目前在经纬系布局的近50家企业服务创业项目中,有北森、销售易、七牛、永洪BI、OneAPM、环信、GrowingIO、亿方云、上上签、佳格数据、盖雅工场、Pingcap等已初露锋芒。

   今天的文章来自我们与经纬董事总经理熊飞的一次交流,希望对你有所启发。以下,Enjoy:“企业服务项目到底怎么投?两个核心关键点。

Q:在我看来,做VC有个能力:当有经验积累后,挑项目的时候,是能够预判出项目发展路径的。但问题在于,当一个项目到了一定的标准,投与不投,是多维度进行判断的。比如Saas,中国Saas目前看来还比较难做,如果满足了基本条件KPI达标,那么超越KPI的标准是什么?在此之上经纬看重什么?

熊飞:第一点,是个大市场。比如CRM,再比如人力资源,也有很多细分项目,比如做核心人力、做招聘,但肯定不只是做一个报表工具。企业服务公司所处的市场足够大,这是核心。企业服务本身是让企业为该职能相关痛点去付费。而销售、HR、客服、财务等职能,是企业最核心职能,痛点的商业价值最大。所以大市场的基础,是该产品关注的是企业核心职能,以及解决的是核心职能中的核心痛点。

第二点,要考虑这个项目是不是处在浪尖位置。我们经常说投浪尖。三五年前投Saas,那个时候对于早期项目来说是一个浪尖。过去一两年投infrastructure(IT底层架构),也是个浪尖,比如说marketing automation(营销自动化)、iot等等。所以如果你现在做客服Saas创业就不是浪尖了,因为已有环信这些头部项目。浪尖的优势在于你是最早做的,所有资源都给你。

总结一下:它应该是这个领域最早的探路者,且速度一直高速增长。如果市场够大,并处于浪尖的位置,是先人半步与先人一步的机会,这个我们是非常看重的。“企业服务,产品技术导向的创始人更有优势。

Q:在这两点满足的前提下,关于团队层面,有什么体会?你们看重创始人的哪些特质?

熊飞:我觉得没有完美决策,我们常说VC是一个判断+运气的连续体,但投ToB靠判断会更多一些。做的每一个判断都希望结果是大概率事件,但所谓大概率也只能证明这个项目七八成应该投,但没有百分之百。

我个人倾向产品技术导向的创始人。在我看来,投产品技术导向的团队没什么下行风险,但上行收益巨大;因为产品技术好,最差情况就是没销售,但优势在于产品壁垒高,一旦市场找到感觉,找到销售合伙人,业务可能就会以5 倍、10倍增速发展。但纯销售导向创始人,早期业务起来比较快,但如果竞争对手是产品技术导向,对手一旦找到市场感觉和销售合伙人,下行风险就很大。

宏观来看,企业服务公司产品技术的护城河宽不宽,有没有留下足够多的安全边际,是我们很关注的点。这也是经纬系企业服务公司,为什么普遍发展很扎实、高速健康增长的原因。我们在投的时候,是希望跟产品技术导向、着重于打磨自己产品的创始人去沟通。

Q:说到产品和技术,其实相对难判断,ToC可能是看KPI;ToB的话,特别是一些早期公司除了看创始人过去的背景,怎么去判断呢?

熊飞:我觉得有几点,第一,做reference track,团队的能力,是可以通过reference相当程度判断。

第二,团队投每个领域都会投入很多的时间,要了解趋势,知道有哪些领先的公司。形成初步投资假设。再去和公司聊发展、聊产品,就能够比较快的判断出这个团队的视野、产品意识。

第三,就是一些标杆客户的反馈,这个是实打实的。做到这三点就很快能做出不赖的判断。“先赢而后战。

Q:经纬五年前就开始布局ToB,坚持到现在。在我看来,五年前的时候应该非常寂寞。直到2015年大家才普遍觉得 ToB是风口,这期间你是怎么去判断的?

熊飞:投ToB其实投的创始人的特质,往往都是比较踏实、稳重、重逻辑、重积累,团队专注某一个方向;ToC则不然,可能需要创始人是愿意快速变化的人——这两类人是完全不一样的。

另外,我个人觉得在中国投ToB的长期回报会比美国投ToB好很多。原因在于:

在美国,因为Salesforce、Workday等已有领先者产品的市场占有度很高,导致创业公司长不动、长不大,很多都是10亿美金、12亿美金被并购。在中国,ToB领域竞争并不激烈,因为没有产品供给,很多公司创业两年,就可以做中国500强的生意,这在美国不可想象。所以从长期来看,国内 ToB创业公司的天花板显著的高。

另外,从运营效率来看国内Saas创业公司也有不小优势。美国很多Saas公司大概做到1 个亿美金收入还在不停亏损,还要不停地往前赶,很难实现现金流打平。但在国内,至少我们投的很多Saas公司做到亿元人民币量级的时候,或者之后一年,就有机会做到单月盈亏平衡。

最后,从经纬角度来说,最核心是投产品高壁垒和护城河足够宽的项目,比如像HR领域的北森现在发展很好,五年后还会发展很好、再比如销售易、环信、GrowingIO……这些公司现在很好,我们也能看到它们五年后都会很好。

大核心、大前提还是投到最优秀的公司。我很喜欢《孙子兵法》里面的一句话——先胜而后战,你要先确保你大概率能赢的再去打。张颖有一句话,叫自强则万强,只要把产品、技术做到行业内非常领先,我觉得融资的问题都是业务问题。“企业服务这么火,创业到底是该切入大客户还是小客户?

熊飞:经纬投企业服务五年时间,这个行业的发展是超出预期的。几点原因:

中国人力成本的提高到了一个转折点。我经常举例子,六年前一个人工资大概3000元 / 月,一台电脑5000元。现在反过来了,一个人工资5000元,笔记本电脑的价格只有2000元。企业主是很理性的,以前2:1,现在变1:2了,他希望更大投入提高效率。而且,最近中国经济增长放缓,三年前企业主都在谈拉贷款、扩产能,但是现在想的是如何高效地去提高利润,也落在软件上。

我有个观察,ToB市场爆发,不是留给海外巨头,而是给国内创业企业的巨大机会。很像七八年前智能手机的市场,当时移动手机市场刚起来,大家知道苹果、三星非常好,可是一台手机要六七千块。所以需求起来的时候,性价比更高的国产手机,小米、OPPO、华为、中兴爆发式增长。ToB领域也类似,软件从最初大型和超大型企业的刚需,过渡到中型以上企业的刚需,而这个爆发的市场更关注性价比和产品体验,使得国内创业公司成为最大受益方。

Q:那么现在如果再做企业服务创业的话,是否理想的客户反而不是中海油、中石油,而应该是中型企业?

熊飞:我们投的大部分成功企业服务公司,不是一上来就瞄准中海油等超大型企业,无法一击即中,因为超大型企业的功能需求太多了。它们往往是先瞄准100人到300人的中型企业,或者是中型偏小型企业,要先快速上手,再逐年向上走,今年可能是服务100人到300人的企业,明年可能是300人到800人,后年可能是1000人到2000人。随着功能不断地添加,这是一个“逆流而上”的策略。

Q:有个现象非常有趣——很多企业服务创业者会在两头摇摆,以前做大客户出身的会非常痛恨做大企业,过去诸如催款、服务等等小事,CEO、工程师动不动就被叫过去处理问题。 经历过做大客户的,现在就愿意做小企业或者中小企业,他觉得我是产品说话,不会像以前那样被牵着鼻子走;但又会发现一个新问题:收费有点困难。小企业消失得快,或者是需求率不高。他们就像一个钟摆在不断摇摆。你怎么看?

熊飞:我觉得一定要做中大企业。一点一点往上。全球IT投入90% 来自于财富两千强,再90% 来自于两万强,你做不到两万强的生意,你就只有1% 的市场,自然这个公司能够成为一个很大的、很牛的公司的概率也变得很小。“投资的魅力所在:不断地去证伪。

Q:经纬企业服务团队做的最快的一次决策多长时间?为什么?

熊飞:最快决策是当天见完觉得可以投,就签下TS。能这么快的原因是,团队在该领域已做了足够多思考,见了足够多公司,当遇到这家公司时,其实是捅破了这层“窗户纸”。

另外,我认为投资的魅力所在,是一个不断证伪的过程。VC这个行业是一个idea business,所有的回报取决于你的idea质量,本质在于两点:

第一,generate idea的能力,就是说你的视野够广,经常在一线跑,有很多的思考。

第二,证伪idea的能力。如果你没有证伪idea的能力,那就变成了自己做空中楼阁的假设。

经纬企业服务团队每天都在不断地拼命去证伪——比如17年初定了三四个ToB的主方向,现在看有两个觉得不错;但是已有一个觉得机会不大,还有一个待判断。所以每个季度都在推翻自己投资的思路和假设。

Q:Peter Thiel的书《Zero to One》里说过创投要有一个非常规的想法。如果说你提一个跟ToB相关的观点,比如“我觉得我这么认为,但是其他的投资人未必是这么认为的”。如果有,是什么?

熊飞:我觉得是中国企业服务创业公司机会规模,10倍于目前美国企业服务创业机会。原因在于,美国在enterprise是三波的创业浪潮,第一波是上世纪70年代到80年代,像SAP、微软、Oracle,他们现在都是1000亿到3000亿美金的公司。第二波是云计算,从上世纪90年代末到2000下半叶,这时崛起了Salesforce、workday、NetSuite、ServiceNow这一系列公司,从几十亿美金到六百亿美金。第三波就是现在,现在有一些AI企业服务创业公司开始起来。

在中国,这三波发展是融合在一起爆发的,三、四年前没有人谈企业服务,现在所有人都在谈企业服务,所有人都在谈企业服务直接上云计算,所有人都在谈企业服务和AI的结合。所以三波浪潮的合并,使得目前中国企业服务创业公司的天花板显著的高。

Q:会不会有这样一个趋势,SAP这些公司等于是压在中国公司头上的石头,首先会有一批企业服务本土企业。未来中国公司出海,反过来最后会不会变成中国公司把SAP干掉?

熊飞:第一,我不知道会不会干掉,但我相信未来的5 到10年中国的企业服务公司会在全球企业服务市场将占据重要地位,原因有两点:一是随着中国企业的出海而出海;二是价格优势,SAP、Oracle现在是一个85分到90分的产品,但我们中国的企业服务产品现在很努力地在赶上,虽然可能还是一个75分的产品,但是价格是其1 /3。三是,未来中国企业的最佳实践,会成为第三世界国家(企业服务下一波机会所在地)的最佳实践。
0
评论

《IT经理世界》特写:环信的Alpha刘,布局未来的商业智能! 新闻资讯 IT经理世界 环信 刘俊彦

新闻资讯 发表了文章 • 623 次浏览 • 2017-06-27 11:21 • 来自相关话题

6月20号刊

新疆界




刘俊彦说不想做一家小老头公司——规模不大,每年挣个几千万元,日子过得滋润,但每年只有10%左右的增长。

技术男刘俊彦的思维很跳跃,2014年做即时通讯云,一年后开始做客服云,不到一年,又开辟了智能机器人业务。看起来好像在分片作战,但突然有一天他已经在一个更大的战略布局里了。

这些年,云的概念被炒到火热,企业不惜花血本布局云计算,可一轮下来之后,不同的业务还是要各养一套人马,各养一套软件系统,说好的大数据,量是上去了,但是实际利用率却如挤牙膏,效用微乎其微。很多企业现在正处在一个升级也不是,不升级也不是的难受期。

见到刘俊彦的时候,他刚送走一家航空公司的几位管理人员,他们现在的烦恼是,守着一大批高净值的用户,只能卖个机票,最多再卖个保险,利润已经碰到天花板,有种守着宝藏却挖不出金子的感觉。刘俊彦在他的小会议室的黑板上,画了一个完整的从用户服务到用户营销的闭环图,这张图里包含了航空公司乃至一些大企业当下的几大痛点及应对招数,如同在下一盘围棋,细节处棋势做得够厚,大局又跳出常人思维之外,细看与AlphaGo的风格颇为相似。

这是刘俊彦第一次将自己成熟的大局想法展示给外界。
 
高效融资与快速换挡
 
刘俊彦毕业于英国伦敦大学国王学院计算机专业,后一直在IT外企从事技术研发工作,2013年,离职创业前已经成为红帽开源软件领域领先的专家。这一年,他已经年过40。

最初的一年多时间,是在海淀图书城的车库咖啡里度过的,当时刘俊彦和另外三位合伙人都刚从外企里出来,各自都已经是行业里优秀的技术人才,都实现了财务自由,清楚自己要的是什么,且志趣相投,所以走到了一起。

刚开始,大家专注于做产品,也没有急着去找投资。一年后,一个偶然的机会,投资自己找上了门。

2014年5月,刘俊彦他们进驻到氪空间的当天下午,经纬的投资人找到了他们,大概聊了两个多小时,双方就达成了合作意向。紧接着不到半年,SIG和红杉资本相继成为投资方。几家投资方看中的是刘俊彦等人创立的环信公司在即时通讯领域的开发能力和社交大数据分析能力,以及环信自主研发的高并发可扩展架构。

此前,刘俊彦拥有17年的开发经验,其擅长的领域在于实时消息系统和高并发消息中间件等。2013年,社交软件开始大行其道,当时很多人找他为APP开发即时通讯聊天功能,一般如果企业自己开发的话,怎么都需要好几个月时间,而使用刘俊彦的团队的产品只需一天功夫就出来了。因此,最初的产品并非他们刻意做出来的,而是需求在先,而且令他们也没想到的是,做着做着就成“风口”了。

很快,使用了环信即时通讯功能的APP上的用户从几万飞速上升到几千万,乃至后来的几个亿,每天下发的消息达20亿条。曾经在短信高峰时代,中国移动每天的消息量是7亿,目前国内能支撑并发连接几千万的团队不超过5个,包括腾讯、阿里、新浪微博、陌陌等,另外还有一个就是环信。

用户上去之后,新的需求又来了。开始,很多人只是把APP内的聊天功能用作连接人与人的社交管道,但很快就不断有人找上门来,希望把APP内的聊天功能做成淘宝旺旺那样连接人和商业的客服工具。

从本质上来讲,环信早期推出的即时通讯云是基于PaaS平台的服务,而要做客服云则需建立在SaaS平台上,如此跨平台的转变,对于一家创业公司,无论是人才、资本、研发或渠道等各方面都会带来严峻的挑战。

2015年4月,A轮的三家投资方在前几个轮次共900万美元的基础上,再次追加了共1250万美元的B轮投资,在资本方的财力和战略加持下,一个月后,环信客服产品线上市,一年后环信客服产品的客户量、销售额等硬指标均达到几十倍上百倍的增长。

据刘俊彦介绍,早期客服云的客户几乎一半多来自即时通讯云,相当于后者是前者的流量导入渠道,后者反过来巩固了前者的价值所在。

目前,环信客服产品的企业用户已经超过5万多家,用户也从国美在线、58到家、新东方等扩展到了十几个行业当中。

然而,IT业一年相当于传统行业十年,这是一个变换以秒速推进的行业,刘俊彦很快又迎上了新的挑战。

痛点与前瞻

随着产品的积累和行业的扩展,刘俊彦开始接触到一些保险、证券、航空等行业大客户。曾经有一家保险公司的客户跟他提到亲身经历的一件事情,以往保险公司客户经理做客户维护的通常做法就是每年会定期提前一两个月给老客户打电话,提醒他们保险快到期,可以续费了。其中有一个老客户,关系维护得挺好,但是这个老客户最近新买了辆哈雷摩托车,而他的客户经理没能及时了解并提供摩托车的保险报价,结果错失了老用户。

这种个案在保险公司普遍存在。如果有更懂用户的数据,进行再分析和精准营销,就能很快帮老用户接上新的业务,还可以把以前让利给渠道的部分,直接反馈给用户,大幅提高销售成功率。

刘俊彦说,做即时通讯,做客服,真正的差距在于,怎么通过商业智能帮助企业去挖掘以前看不到的客户信息,提高销售转换率,发掘新销售机会,以及人工智能技术怎么代替人工,怎么帮企业营销,这都是未来技术。

2016年年初,环信基于企业一体化智能商业的需求,开始推全媒体智能客户服务。所谓全媒体就是不管客服请求来自微信、微博或APP,还是网页或电话,都可以同时呈现在一个界面上,由专人统一处理。

以前企业不同的渠道由不同的人马在支持,各自软件系统也不一样,信息也是各自孤立的,片段化的,环信做到了让一个支持人员同时监控所有渠道,客户身份也可以从孤立的信息中关联起来,形成一个统一身份。也就是说,同一个用户打完电话,再用微信接入,通过各种技术方法可以跨屏身份合并被识别为是同一个人。

此外,一家企业如果每天进来10万条消息,环信的技术可以识别出来自不同渠道不同数据格式的信息,然后对其进行数据清理,再做主题分析和情感分析,从而知道用户今天都反馈了什么问题,情感是愤怒还是高兴,可能的消费趋势是什么?进一步还可以給出用户画像,画像信息详尽,一直可追溯到用户城市、职业、性别、喜好、消费能力、行为轨迹,等等。

这些数据对于企业至关重要。不仅是保险公司,证券公司、航空公司等等行业都存在类似的强烈需求。

环信还在自己研发客服机器人。刘俊彦认为,环信既有SaaS客服软件高市场占有率的通道优势,又有了大量的数据积累,加上对垂直行业的深度理解,在开发具有高度行业特征的客服机器人上,又领先了其他对手。

2017年 ,环信整合旗下即时通信云、移动客服、智能客服机器人和主动营销产品线,推出环信CEC (Customer Engagement Cloud),向企业提供从客户互动渠道,到客户服务,再到精准客户营销的全流程客户互动解决方案。

技术出身的刘俊彦,既可以不断挖掘出用户的痛点,在技术细节上下足功夫,又可以跳出来,把握住前瞻性技术,果断出击。当一个个看似不大相关的痛点技术在量的积累上突破一个爆发性临界点时,全新的需求与应用又把之前所有的技术关联在了一起。

这一切使得刘俊彦像一个“做局”的高手。

转变与坚持

创业仅仅4年,刘俊彦已经看惯了互联网领域的迎来送往,2014年,他还经常在微信里看见做社交应用的CEO们发朋友圈,到2015年左右,这些人大多看不到了,换了一批做O2O的CEO,一年以后,这些人又看不见踪影了。大浪淘沙,互联网的残酷淘汰是铁律。

当年那些做即时通讯服务的环信的老对手们,现在大多还在做老业务,日子过得还不错。刘俊彦却早已不在当初的格局里了。

做即时通讯云有一个特点,从几十万用户到几百万用户是一个技术节点,从几百万到几千万又是一个节点,用户过亿之后则是一个更大的节点。每一个节点处,基本上架构要推倒重写一遍。这要求技术团队快速的迭代和积累,一旦有一个环节出问题,就有可能导致服务不可用。

这期间,环信团队也经历了重大考验,也被客户骂过,好在最后都坚持过来了。现在环信即时通讯技术架构早已稳定下来,即使再扩容4~5倍也不成问题。

然而,就在这么一个节点上,刘俊彦毅然决定再另外做一个SaaS平台,这对于整个团队是一种怎样的震撼。虽然对于技术能力强悍的环信团队来讲,技术难题最终都是可以克服的,而对市场的敏锐嗅觉以及果断决策,却非易事。事实上刘俊彦的判断是精准的。

环信最初的客户群主要集中在互联网领域,这些客户的生命周期比较短,付费能力比较低,好处是决策周期短,商业谈判简单,能迅速达成交易,迅速验证需求,这适合早期创业。

有了这段经历也让刘俊彦开始明白,为什么美国的SaaS软件同行们天天讲生命周期价值,讲内容营销,因为他们也跟环信一样做的是小客户,可见对于小客户这一招中外通吃。而大客户不是这么玩的。

在美国做企业服务,底层有一批创业公司,天花板是做到几亿美元到几十亿美元市值,基本很难再往上突破了。这是因为大客户都被微软、甲骨文、Salesforce这样的公司牢牢掌握着,小企业根本没机会进入那个圈子。

某种程度上,中国也差不多,但也有很大不同。中国大型企业还没有强大的科技公司可以很好地服务于他们,这些年主要依赖于一些大型系统集成商,系统集成商的做法跟甲骨文等这些科技巨头又不一样,他们以项目运行的方式推进,在创新和积累上相对较弱。

以前中国的大型国企或私企也认可这种做法,但随着整体经济环境进入L型经济,增长放缓,企业追求利润的结果就是更加注重创新,尤其是服务创新,这两年刘俊彦明显地感觉到国内大型企业有一种创新急迫感,他意识到谁能服务中国500强企业,谁就会成为中国的甲骨文。

由于求稳,当年环信的竞争对手就没赶上这波新的机会。“如果我们到现在还只是在做最初的一个业务,我们也就成为了一家小老头公司。”刘俊彦平静地说。

2017年3月,环信完成1.03亿元的C轮融资,由经纬领投,银泰嘉禾跟投。

当然,考验仍然存在。SaaS是一种功能密集型的技术,最考验大规模研发团队的研发效率和管理能力。2016年新组建的智能机器人团队则是资本密集型,这个团队虽然人不多,但是一年投入却上千万元。

不同的技术、人才、资本结构,对于管理是一大考验。不过刘俊彦认为,既然创业就要全力以赴去做,“挖人要看眼光,选择很重要,路线很重要,信任也很重要,既然选择上了火箭飞船,就不要考虑是几等舱。”
 作者 | 刘晓芳

微信编辑 | 李昊原

原文发表于《IT经理世界》,转载请注明 查看全部

微信图片_20170627113413.gif
6月20号刊

新疆界

微信图片_20170627111638.jpg

刘俊彦说不想做一家小老头公司——规模不大,每年挣个几千万元,日子过得滋润,但每年只有10%左右的增长。

技术男刘俊彦的思维很跳跃,2014年做即时通讯云,一年后开始做客服云,不到一年,又开辟了智能机器人业务。看起来好像在分片作战,但突然有一天他已经在一个更大的战略布局里了。

这些年,云的概念被炒到火热,企业不惜花血本布局云计算,可一轮下来之后,不同的业务还是要各养一套人马,各养一套软件系统,说好的大数据,量是上去了,但是实际利用率却如挤牙膏,效用微乎其微。很多企业现在正处在一个升级也不是,不升级也不是的难受期。

见到刘俊彦的时候,他刚送走一家航空公司的几位管理人员,他们现在的烦恼是,守着一大批高净值的用户,只能卖个机票,最多再卖个保险,利润已经碰到天花板,有种守着宝藏却挖不出金子的感觉。刘俊彦在他的小会议室的黑板上,画了一个完整的从用户服务到用户营销的闭环图,这张图里包含了航空公司乃至一些大企业当下的几大痛点及应对招数,如同在下一盘围棋,细节处棋势做得够厚,大局又跳出常人思维之外,细看与AlphaGo的风格颇为相似。

这是刘俊彦第一次将自己成熟的大局想法展示给外界。
 
高效融资与快速换挡
 
刘俊彦毕业于英国伦敦大学国王学院计算机专业,后一直在IT外企从事技术研发工作,2013年,离职创业前已经成为红帽开源软件领域领先的专家。这一年,他已经年过40。

最初的一年多时间,是在海淀图书城的车库咖啡里度过的,当时刘俊彦和另外三位合伙人都刚从外企里出来,各自都已经是行业里优秀的技术人才,都实现了财务自由,清楚自己要的是什么,且志趣相投,所以走到了一起。

刚开始,大家专注于做产品,也没有急着去找投资。一年后,一个偶然的机会,投资自己找上了门。

2014年5月,刘俊彦他们进驻到氪空间的当天下午,经纬的投资人找到了他们,大概聊了两个多小时,双方就达成了合作意向。紧接着不到半年,SIG和红杉资本相继成为投资方。几家投资方看中的是刘俊彦等人创立的环信公司在即时通讯领域的开发能力和社交大数据分析能力,以及环信自主研发的高并发可扩展架构。

此前,刘俊彦拥有17年的开发经验,其擅长的领域在于实时消息系统和高并发消息中间件等。2013年,社交软件开始大行其道,当时很多人找他为APP开发即时通讯聊天功能,一般如果企业自己开发的话,怎么都需要好几个月时间,而使用刘俊彦的团队的产品只需一天功夫就出来了。因此,最初的产品并非他们刻意做出来的,而是需求在先,而且令他们也没想到的是,做着做着就成“风口”了。

很快,使用了环信即时通讯功能的APP上的用户从几万飞速上升到几千万,乃至后来的几个亿,每天下发的消息达20亿条。曾经在短信高峰时代,中国移动每天的消息量是7亿,目前国内能支撑并发连接几千万的团队不超过5个,包括腾讯、阿里、新浪微博、陌陌等,另外还有一个就是环信。

用户上去之后,新的需求又来了。开始,很多人只是把APP内的聊天功能用作连接人与人的社交管道,但很快就不断有人找上门来,希望把APP内的聊天功能做成淘宝旺旺那样连接人和商业的客服工具。

从本质上来讲,环信早期推出的即时通讯云是基于PaaS平台的服务,而要做客服云则需建立在SaaS平台上,如此跨平台的转变,对于一家创业公司,无论是人才、资本、研发或渠道等各方面都会带来严峻的挑战。

2015年4月,A轮的三家投资方在前几个轮次共900万美元的基础上,再次追加了共1250万美元的B轮投资,在资本方的财力和战略加持下,一个月后,环信客服产品线上市,一年后环信客服产品的客户量、销售额等硬指标均达到几十倍上百倍的增长。

据刘俊彦介绍,早期客服云的客户几乎一半多来自即时通讯云,相当于后者是前者的流量导入渠道,后者反过来巩固了前者的价值所在。

目前,环信客服产品的企业用户已经超过5万多家,用户也从国美在线、58到家、新东方等扩展到了十几个行业当中。

然而,IT业一年相当于传统行业十年,这是一个变换以秒速推进的行业,刘俊彦很快又迎上了新的挑战。

痛点与前瞻

随着产品的积累和行业的扩展,刘俊彦开始接触到一些保险、证券、航空等行业大客户。曾经有一家保险公司的客户跟他提到亲身经历的一件事情,以往保险公司客户经理做客户维护的通常做法就是每年会定期提前一两个月给老客户打电话,提醒他们保险快到期,可以续费了。其中有一个老客户,关系维护得挺好,但是这个老客户最近新买了辆哈雷摩托车,而他的客户经理没能及时了解并提供摩托车的保险报价,结果错失了老用户。

这种个案在保险公司普遍存在。如果有更懂用户的数据,进行再分析和精准营销,就能很快帮老用户接上新的业务,还可以把以前让利给渠道的部分,直接反馈给用户,大幅提高销售成功率。

刘俊彦说,做即时通讯,做客服,真正的差距在于,怎么通过商业智能帮助企业去挖掘以前看不到的客户信息,提高销售转换率,发掘新销售机会,以及人工智能技术怎么代替人工,怎么帮企业营销,这都是未来技术。

2016年年初,环信基于企业一体化智能商业的需求,开始推全媒体智能客户服务。所谓全媒体就是不管客服请求来自微信、微博或APP,还是网页或电话,都可以同时呈现在一个界面上,由专人统一处理。

以前企业不同的渠道由不同的人马在支持,各自软件系统也不一样,信息也是各自孤立的,片段化的,环信做到了让一个支持人员同时监控所有渠道,客户身份也可以从孤立的信息中关联起来,形成一个统一身份。也就是说,同一个用户打完电话,再用微信接入,通过各种技术方法可以跨屏身份合并被识别为是同一个人。

此外,一家企业如果每天进来10万条消息,环信的技术可以识别出来自不同渠道不同数据格式的信息,然后对其进行数据清理,再做主题分析和情感分析,从而知道用户今天都反馈了什么问题,情感是愤怒还是高兴,可能的消费趋势是什么?进一步还可以給出用户画像,画像信息详尽,一直可追溯到用户城市、职业、性别、喜好、消费能力、行为轨迹,等等。

这些数据对于企业至关重要。不仅是保险公司,证券公司、航空公司等等行业都存在类似的强烈需求。

环信还在自己研发客服机器人。刘俊彦认为,环信既有SaaS客服软件高市场占有率的通道优势,又有了大量的数据积累,加上对垂直行业的深度理解,在开发具有高度行业特征的客服机器人上,又领先了其他对手。

2017年 ,环信整合旗下即时通信云、移动客服、智能客服机器人和主动营销产品线,推出环信CEC (Customer Engagement Cloud),向企业提供从客户互动渠道,到客户服务,再到精准客户营销的全流程客户互动解决方案。

技术出身的刘俊彦,既可以不断挖掘出用户的痛点,在技术细节上下足功夫,又可以跳出来,把握住前瞻性技术,果断出击。当一个个看似不大相关的痛点技术在量的积累上突破一个爆发性临界点时,全新的需求与应用又把之前所有的技术关联在了一起。

这一切使得刘俊彦像一个“做局”的高手。

转变与坚持

创业仅仅4年,刘俊彦已经看惯了互联网领域的迎来送往,2014年,他还经常在微信里看见做社交应用的CEO们发朋友圈,到2015年左右,这些人大多看不到了,换了一批做O2O的CEO,一年以后,这些人又看不见踪影了。大浪淘沙,互联网的残酷淘汰是铁律。

当年那些做即时通讯服务的环信的老对手们,现在大多还在做老业务,日子过得还不错。刘俊彦却早已不在当初的格局里了。

做即时通讯云有一个特点,从几十万用户到几百万用户是一个技术节点,从几百万到几千万又是一个节点,用户过亿之后则是一个更大的节点。每一个节点处,基本上架构要推倒重写一遍。这要求技术团队快速的迭代和积累,一旦有一个环节出问题,就有可能导致服务不可用。

这期间,环信团队也经历了重大考验,也被客户骂过,好在最后都坚持过来了。现在环信即时通讯技术架构早已稳定下来,即使再扩容4~5倍也不成问题。

然而,就在这么一个节点上,刘俊彦毅然决定再另外做一个SaaS平台,这对于整个团队是一种怎样的震撼。虽然对于技术能力强悍的环信团队来讲,技术难题最终都是可以克服的,而对市场的敏锐嗅觉以及果断决策,却非易事。事实上刘俊彦的判断是精准的。

环信最初的客户群主要集中在互联网领域,这些客户的生命周期比较短,付费能力比较低,好处是决策周期短,商业谈判简单,能迅速达成交易,迅速验证需求,这适合早期创业。

有了这段经历也让刘俊彦开始明白,为什么美国的SaaS软件同行们天天讲生命周期价值,讲内容营销,因为他们也跟环信一样做的是小客户,可见对于小客户这一招中外通吃。而大客户不是这么玩的。

在美国做企业服务,底层有一批创业公司,天花板是做到几亿美元到几十亿美元市值,基本很难再往上突破了。这是因为大客户都被微软、甲骨文、Salesforce这样的公司牢牢掌握着,小企业根本没机会进入那个圈子。

某种程度上,中国也差不多,但也有很大不同。中国大型企业还没有强大的科技公司可以很好地服务于他们,这些年主要依赖于一些大型系统集成商,系统集成商的做法跟甲骨文等这些科技巨头又不一样,他们以项目运行的方式推进,在创新和积累上相对较弱。

以前中国的大型国企或私企也认可这种做法,但随着整体经济环境进入L型经济,增长放缓,企业追求利润的结果就是更加注重创新,尤其是服务创新,这两年刘俊彦明显地感觉到国内大型企业有一种创新急迫感,他意识到谁能服务中国500强企业,谁就会成为中国的甲骨文。

由于求稳,当年环信的竞争对手就没赶上这波新的机会。“如果我们到现在还只是在做最初的一个业务,我们也就成为了一家小老头公司。”刘俊彦平静地说。

2017年3月,环信完成1.03亿元的C轮融资,由经纬领投,银泰嘉禾跟投。

当然,考验仍然存在。SaaS是一种功能密集型的技术,最考验大规模研发团队的研发效率和管理能力。2016年新组建的智能机器人团队则是资本密集型,这个团队虽然人不多,但是一年投入却上千万元。

不同的技术、人才、资本结构,对于管理是一大考验。不过刘俊彦认为,既然创业就要全力以赴去做,“挖人要看眼光,选择很重要,路线很重要,信任也很重要,既然选择上了火箭飞船,就不要考虑是几等舱。”
 
作者 | 刘晓芳

微信编辑 | 李昊原

原文发表于《IT经理世界》,转载请注明
0
评论

云安全fun享会 | 第三期 《未知安全威胁的检测与防御》 环信 活动 云锁

新闻资讯 发表了文章 • 652 次浏览 • 2017-06-09 14:41 • 来自相关话题

活动时间:2017年06月24日 13:30—16:30
活动地点:北京市朝阳区酒仙桥北路9号恒通国际创新园C8栋 MeePark







   WannaCry、Struts 2等安全事件告诉我们,用规则去防御安全漏洞永远比黑客慢一步,如何在与黑客抗争中先知先觉,占据主动地位,是未来信息安全战争的关键!

   云安全fun享会第三期《未知安全威胁的检测与防御》,邀请业界安全专家,与您分享沙盒、RASP、蜜罐、安全态势感知等对抗未知威胁的利器。

与其惧怕0day,不如来听听我们的安全沙龙!








椒图科技助理总经理 吴康
《利用沙盒检测加密及未知WebShell》




云锁产品总监 田强
《RASP技术在中国的落地与实践》
更多议题陆续添加中,也欢迎您的议题投稿:lidong@jowto.com






2017年06月24日 13:30
北京朝阳区酒仙桥北路9号恒通国际创新园C8栋 MeePark
除了精彩的议题外,我们还准备点心和礼品,等你到来
会务联络:sunyx@jowto.com




























本次fun享会活动场地由 MEE-PARK 智能活动空间提供,特此感谢。






活动报名:报名地址 查看全部
活动时间:2017年06月24日 13:30—16:30
活动地点:北京市朝阳区酒仙桥北路9号恒通国际创新园C8栋 MeePark


01.jpg


   WannaCry、Struts 2等安全事件告诉我们,用规则去防御安全漏洞永远比黑客慢一步,如何在与黑客抗争中先知先觉,占据主动地位,是未来信息安全战争的关键!

   云安全fun享会第三期《未知安全威胁的检测与防御》,邀请业界安全专家,与您分享沙盒、RASP、蜜罐、安全态势感知等对抗未知威胁的利器。

与其惧怕0day,不如来听听我们的安全沙龙!
02.png

03.jpg

椒图科技助理总经理 吴康
《利用沙盒检测加密及未知WebShell》


04.jpg

云锁产品总监 田强
《RASP技术在中国的落地与实践》


更多议题陆续添加中,也欢迎您的议题投稿:lidong@jowto.com


05.png

2017年06月24日 13:30
北京朝阳区酒仙桥北路9号恒通国际创新园C8栋 MeePark
除了精彩的议题外,我们还准备点心和礼品,等你到来
会务联络:sunyx@jowto.com

06.jpg


07.jpg

08.jpg


09.png

10.jpg


11.png

本次fun享会活动场地由 MEE-PARK 智能活动空间提供,特此感谢。
12.png



活动报名:报名地址
0
评论

环信CEC亮相GMIS 2017峰会,智能客服大有可为! 新闻资讯 Gartner 环信

新闻资讯 发表了文章 • 562 次浏览 • 2017-06-06 11:40 • 来自相关话题

    近日,2017全球机器智能峰会(GMIS 2017)在北京圆满举行,47位重磅嘉宾带来的32场演讲、4个圆桌论坛、1场人机大战及5个主题Session轮番上演,使GMIS 2017成为聚焦人工智能及相关领域的顶级行业盛宴。说出来你可能不信,环信是唯一受邀参展GMIS 2017的智能客服公司!




   LSTM 之父&Dalle Molle 人工智能研究所副主任Jürgen Schmidhube大胆预测,在未来几年人类将创造出具有灵长类动物智能的人工智能系统。而现阶段AI在行业发挥最大生产力更可能是在垂直行业,特别是客服行业,智能客服聊天机器人已经展示给世人强大的生产力。




  也许你已经被环信诸如“全球最大、国际领先、国内市场占有率第一...”等狂轰滥炸的晕头转向了,我也很懵逼啊,我只是一个新媒体小编,对于市场第一描述词汇量的匮乏我也很绝望啊...




   环信作为智能客服企业的先行者,基于自然语言处理和机器学习技术推出了环信智能客服机器人,辅助或代替人工客服精准回答常见或高频问题,降低企业客服人力成本。目前,环信在客服领域已经服务了58541家标杆客户,积累了人工智能在客户服务行业落地的大量最佳实践。





为什么环信在AI方面有领先优势,投资人说的对!






   主会场演讲嘉宾美国通用电气GE Transportation CTO Wesly Mukai谈到机器学习目前已经应用在美国铁路运输这种非常实际的领域中,为提高效率做出了很大贡献。Wesly先生会后来到环信展台深入了解国内智能客服机器人在客服行业的应用,他认真听取了环信客服聊天机器人的实现方式(单轮会话、多轮会话、人机协作...)和应用场景以及帮助客户取得的效果和成绩,他认为中国企业在智能客服行业的探索已经走在了世界前列,同时他很看好AI在垂直领域所爆发的强大生产力。





Wesly和环信员工谈笑风生(照片由Wesly先生私人翻译帮助拍摄提供)






   Citadel 首席人工智能官邓力发表了以“无监督学习的最新进展(Recent Advances in Unsupervised Learning)”为主题的演讲。他认为,聚类方法、GAN 和变分自编码器(VAE)等传统无监督学习方法关注的重点是对输入数据的结构建模。腾讯 AI Lab 副主任俞栋在大会上洞悉了语音识别领域的前沿研究,今日头条、第四范式等嘉宾们从语音交互领域、自然语言处理及人工智能平台等领域切入,详细解构了其在人工智能时代所实践的产业创新,展示出AI技术在不同领域产生的巨大价值及未来机遇。




   当下,科技和创新进入拐点式爆发,人工智能的浪潮席卷全球。在此背景下,GMIS 2017作为国内首次汇集起全球人工智能和机器人领域顶级专家的大会,中立、权威、系统地呈现了机器智能相关技术的前沿研究,为全球人工智能领域前沿专家学者共同探讨机器智能如何从技术转化成产品和应用提供了绝佳平台,同时深切关注人工智能未来能够解决哪些具体问题,及如何帮助人类智慧生活的体验得到提升。GMIS将对行业产生积极而深远的影响,并开启人工智能发展的新起点。




   最后提前剧透:环信联合Gartner即将在国内发布客服行业首个机器人选型报告《智能客服机器人之客户服务行业最佳实践》我会到处乱说么?
 
报告抢先看
 
   市场上关于机器人的分类很多,误区也有很多。往往人们会将客服机器人等同于聊天机器人,但客服机器人其实只是聊天机器人的一种。聊天机器人主要分为两个大类:闲聊机器人与Task Oriented 机器人。Task Oriented 机器人是以任务目的为导向的机器人,又包括个人助理机器人与客服机器人。





上表对闲聊机器人、个人助理机器人、客服机器人从解决问题领域、平台系统开放性、技术方案的角度进行了详细比较。





智能客服机器人概述与分类 查看全部
    近日,2017全球机器智能峰会(GMIS 2017)在北京圆满举行,47位重磅嘉宾带来的32场演讲、4个圆桌论坛、1场人机大战及5个主题Session轮番上演,使GMIS 2017成为聚焦人工智能及相关领域的顶级行业盛宴。说出来你可能不信,环信是唯一受邀参展GMIS 2017的智能客服公司!
001.jpg

   LSTM 之父&Dalle Molle 人工智能研究所副主任Jürgen Schmidhube大胆预测,在未来几年人类将创造出具有灵长类动物智能的人工智能系统。而现阶段AI在行业发挥最大生产力更可能是在垂直行业,特别是客服行业,智能客服聊天机器人已经展示给世人强大的生产力。
002.jpg

  也许你已经被环信诸如“全球最大、国际领先、国内市场占有率第一...”等狂轰滥炸的晕头转向了,我也很懵逼啊,我只是一个新媒体小编,对于市场第一描述词汇量的匮乏我也很绝望啊...
003.jpg

   环信作为智能客服企业的先行者,基于自然语言处理和机器学习技术推出了环信智能客服机器人,辅助或代替人工客服精准回答常见或高频问题,降低企业客服人力成本。目前,环信在客服领域已经服务了58541家标杆客户,积累了人工智能在客户服务行业落地的大量最佳实践。


004.jpg

为什么环信在AI方面有领先优势,投资人说的对!



005.jpg

   主会场演讲嘉宾美国通用电气GE Transportation CTO Wesly Mukai谈到机器学习目前已经应用在美国铁路运输这种非常实际的领域中,为提高效率做出了很大贡献。Wesly先生会后来到环信展台深入了解国内智能客服机器人在客服行业的应用,他认真听取了环信客服聊天机器人的实现方式(单轮会话、多轮会话、人机协作...)和应用场景以及帮助客户取得的效果和成绩,他认为中国企业在智能客服行业的探索已经走在了世界前列,同时他很看好AI在垂直领域所爆发的强大生产力。


006.jpg

Wesly和环信员工谈笑风生(照片由Wesly先生私人翻译帮助拍摄提供)



007.jpg

   Citadel 首席人工智能官邓力发表了以“无监督学习的最新进展(Recent Advances in Unsupervised Learning)”为主题的演讲。他认为,聚类方法、GAN 和变分自编码器(VAE)等传统无监督学习方法关注的重点是对输入数据的结构建模。腾讯 AI Lab 副主任俞栋在大会上洞悉了语音识别领域的前沿研究,今日头条、第四范式等嘉宾们从语音交互领域、自然语言处理及人工智能平台等领域切入,详细解构了其在人工智能时代所实践的产业创新,展示出AI技术在不同领域产生的巨大价值及未来机遇。
008jpg.jpg

   当下,科技和创新进入拐点式爆发,人工智能的浪潮席卷全球。在此背景下,GMIS 2017作为国内首次汇集起全球人工智能和机器人领域顶级专家的大会,中立、权威、系统地呈现了机器智能相关技术的前沿研究,为全球人工智能领域前沿专家学者共同探讨机器智能如何从技术转化成产品和应用提供了绝佳平台,同时深切关注人工智能未来能够解决哪些具体问题,及如何帮助人类智慧生活的体验得到提升。GMIS将对行业产生积极而深远的影响,并开启人工智能发展的新起点。
009.jpg

   最后提前剧透:环信联合Gartner即将在国内发布客服行业首个机器人选型报告《智能客服机器人之客户服务行业最佳实践》我会到处乱说么?
 
报告抢先看
 
   市场上关于机器人的分类很多,误区也有很多。往往人们会将客服机器人等同于聊天机器人,但客服机器人其实只是聊天机器人的一种。聊天机器人主要分为两个大类:闲聊机器人与Task Oriented 机器人。Task Oriented 机器人是以任务目的为导向的机器人,又包括个人助理机器人与客服机器人。

010.jpg

上表对闲聊机器人、个人助理机器人、客服机器人从解决问题领域、平台系统开放性、技术方案的角度进行了详细比较。

011.jpg

智能客服机器人概述与分类
0
评论

【客户世界·洞察者】智能客服机器人是下一代客服的核心驱动力(附Gartner报告全文) 新闻资讯 环信 洞察者

新闻资讯 发表了文章 • 1921 次浏览 • 2017-05-17 11:50 • 来自相关话题

    上期我们谈完了工具层、知识层一个领先的SaaS客服厂商是如何做的,接着我们再来聊聊现在最火的AI。随着全媒体客服的普及和广泛应用导致企业和消费者多点接触,同时用户体验得到了企业的重视,导致客服咨询量暴增,企业有限的客服人力资源与日益增加的客服请求之间的矛盾日益尖锐,如何用有限的客服资源服务不断增长的海量客服请求需要一个颠覆型的技术来解决。相比人工客服,智能客服机器人将提供极大的效率优势。
 
   Gartner报告指出智能客服机器人(VCA-virtual customer assistance)的使用正处于临界点。大幅改进的自然语言处理技术,以聊天为中心的移动渠道与客户互动的应用,以及客户对机器人技术的接受程度,这些因素使得人们对VCA的兴趣越來越大。从被动的被人类编程出来的可以在结构化和非结构化内容库中找到问题答案的虚拟助手,到主动的有时候是机器学习得到的VCA的转变,其考察个人的特征并代表他们行动。虚拟助手正在经历从被动的被人类编程出来在结构化和非结构化内容库中找到问题答案到主动的通过机器学习能够理解用户个性化的需求并且随之采取灵活应对行为的转变。
 
   环信作为智能客服企业的先行者,基于自然语言处理和机器学习技术推出了环信智能客服机器人,辅助或代替人工客服精准回答常见或高频问题,降低企业客服人力成本。目前,环信在客服领域已经服务了58541家标杆客户,积累了人工智能在客户服务行业落地的大量最佳实践。
 
视频观看地址:点击观看
 
3.1,智能客服机器人在客服场景下的最佳实践:
 
3.1.1,无需人工标记和人工维护的机器人单轮会话,极大降低客服机器人的维护成本。

   一些问题是不依赖于对话历史,仅根据当前句子就能给出答案,难点在于机器能否理解同一语义的不同表达方法。环信智能机器人采用自然语言处理技术和深度学习技术建立对话模型,使用海量数据对模型进行训练,并借助客服系统中访客和客服的实时反馈来增强学习,精准识别用户意图,帮助人工客服回答各种问题。相比基于关键词匹配和人工定义规则大量标注数据的传统问答技术,环信智能机器人无需人工标记和人工维护相似问法,就可以在会话过程中识别同一问题的多种不同问法。




图1示例:环信机器人无需人工维护相似问法,就可以在会话过程中识别同一问题的多种不同问法。

3.1.2机器人多轮会话,支持更多复杂业务,进一步拓展机器人使用场景。

   而另一些问题则由于缺少足够信息或者过于模糊,需要通过多轮对话的方式来明确用户的需求。比如用户想查物流,但是缺少订单号等信息,机器人需要引导用户提供这些数据。这和单轮的问答相比,多轮对话的技术难点更多,比如指代的理解,句子的省略,用户状态的维护等等。

   环信智能机器人支持上下文语义和多轮会话,并预装多行业的领域知识,如电商行业的物流状态查询模型,产品保修会话模型等。这种基于行业领域和业务模型的多轮会话能力,相比单轮会话,进一步扩展了客服机器人对复杂客服业务场景的自动支撑能力。




图2示例:环信机器人通过多轮会话支持查询物流状态,并和企业业务系统做集成,真正意义上节省人工。

3.1.3无缝人机协作体验,复杂场景下最佳用户体验的客服模式。

   在一些比较复杂和特殊的服务场景,比如高客单价的金融行业售前咨询,机器人客服不能完全理解客户的个性化咨询要求的时候,我们可以无缝进入人机混合模式。在人机混合模式下,环信智能客服机器人向人工客服推荐备选答案,人工客服起到了保证答案质量充当专家客服的角色,这样既保证了客服的响应速度又提高了问题的回答准确性,同时降低了人工客服的工作量。

3.1.4,智能质检,准确率达到替代人工质检水平。

   环信机器人还提供自动智能质检功能,可以对全部客服会话进行实时或离线质检。 智能质检是基于环信在线客服各个领域的海量用户对话,提取出数百个客服对话特征,并用这些特征训练得到的一个通用质检模型。智能质检的准确率达到替代人工质检水平。

3.1.5. 支持智能自主学习,更高效的知识库

   环信智能机器人可以快速高效搭建知识库。既支持批量导入FAQ或用户手动维护问答知识,也支持智能自主学习。智能自主学习是指客服机器人自主学习人工客服的会话,自动生成新知识规则。相比手动维护问答知识,智能自主学习能力显著降低了客服机器人的维护成本,提高了知识库的准确性和时效性。环信智能机器人可预装多个领域的行业知识库。

附录:Gartner研究——虚拟客户助手(智能客服机器人) 分析师:布莱恩·玛纳萨马

定义:虚拟客户助理(VCA),代表公司进行模拟对话以传递信息和/或代表客户采取行动并执行交易。 VCA由四部分组成:

   ■接收请求和传递回应的用户界面■用于文本和语音的自然语言处理引擎■可以检索知识和内容数据存储库的搜索和知识引擎■用于分析意图的上下文引擎一些VCA还具有机器学习功能。

   定位和市场接受速度:IBM Watson,Microsoft Cortana,Next-IT,Creative Virtual和其他VCA供应商的工作正在提高人们对作为实用工具的虚拟助理(VA)技术的认知。 VCA的使用正处于临界点。大幅改进的自然语言处理技术,以聊天为中心的移动渠道与客户互动的应用,以及客户对机器人技术的接受程度,这些因素使得人们对VCA的兴趣越來越大。从被动的被人类编程出来的可以在结构化和非结构化内容库中找到问题答案的虚拟助手,到主动的有时候是机器学习得到的VCA的转变,其考察个人的特征并代表他们行动。虚拟助手正在经历从被动的被人类编程出来在结构化和非结构化内容库中找到问题答案到主动的通过机器学习能够理解用户个性化的需求并且随之采取灵活应对行为的转变。VCA技术有望在两至五年内成为主流。随着移动优先的用户体验转向,许多VCA都亟待更新,以支持多渠道客户与统一知识库的互动,特别是支持客户手机。

   用户建议:确定客户服务平台的当前状态和所需状态。今天您将使用什么样的客服方式和客服工具?您是否使用自然语言处理技术来确定客户到底咨询了什么?是将这个呼叫咨询分派给正确的客服接线员还是让客服机器人提供自动回复?VCA将成为支持多个客服渠道的起点。 VCA未来将可能改变你的日常生活;它可以是一个帮助你在移动设备上购买新健身设备的向导,也可以是一个帮助你开设银行帐户的虚拟客服人员。

   市场正在发生一种变化,对虚拟客服助手的逐渐重视以及使用频次的减少,这个现象已不如以前那么明显。在数字渠道中提供拟人化体验的驱动力正在发生改变。随着客户逐渐适应和接受与计算机的互动,其对具有拟人化情感的3D图像的需求正在减少。公司部署虚拟客服助手时他们发现有对于提升品牌的附加价值,而非仅仅模拟一种店内体验。VCA不仅是面向客户的,而是越来越多地部署为面向员工——帮助客户服务中心减少人工坐席操作时间以及保障客户咨询回复的一致性。

   将一组简单的串行项目与一个复杂的大型项目进行比较,以满足所有确定的需求。找到构成完整呼叫的最高频简单对话,以简单的方式实现自动化和提升客户满意度。然后,识别下一组完整的呼叫:在一段时间,技术与人工可进行合作处理这组呼叫,即当技术检测到问题(如技术储备的知识不足、客户声音难以辨别、或客户通过正确的操作明确要求由人类进行对话)时,人工操作员将接管此组呼叫。

   业务影响:VCA是狭义的、具有特殊用途的VA,用于销售、客户服务和数字商务,且具有独特的目标。VCA的商业案例有三方面。其解决了以下需求:

   ■满足客户对网络和移动渠道中客户支持的期望——更高的互动频率;全天候、即时的聊天可用性■将互动转向价格更低的客户自助服务渠道,更快获取解决方案;降低服务成本■提供积极的建议和参与,培养忠诚度和客户满意度。

    VCA的有效使用便于组织衡量其——特别是联络中心的——参与数量。在数字亭或自动取款机上使用启用语音的VCA可降低对类型化干预的需求,且有助于为非传统受众提供有趣的互动。

好处评级:高

市场渗透率:目标受众的5%至20%

成熟度:未成熟
 
点击查看Gartner报告全文 查看全部
    上期我们谈完了工具层、知识层一个领先的SaaS客服厂商是如何做的,接着我们再来聊聊现在最火的AI。随着全媒体客服的普及和广泛应用导致企业和消费者多点接触,同时用户体验得到了企业的重视,导致客服咨询量暴增,企业有限的客服人力资源与日益增加的客服请求之间的矛盾日益尖锐,如何用有限的客服资源服务不断增长的海量客服请求需要一个颠覆型的技术来解决。相比人工客服,智能客服机器人将提供极大的效率优势。
 
   Gartner报告指出智能客服机器人(VCA-virtual customer assistance)的使用正处于临界点。大幅改进的自然语言处理技术,以聊天为中心的移动渠道与客户互动的应用,以及客户对机器人技术的接受程度,这些因素使得人们对VCA的兴趣越來越大。从被动的被人类编程出来的可以在结构化和非结构化内容库中找到问题答案的虚拟助手,到主动的有时候是机器学习得到的VCA的转变,其考察个人的特征并代表他们行动。虚拟助手正在经历从被动的被人类编程出来在结构化和非结构化内容库中找到问题答案到主动的通过机器学习能够理解用户个性化的需求并且随之采取灵活应对行为的转变。
 
   环信作为智能客服企业的先行者,基于自然语言处理和机器学习技术推出了环信智能客服机器人,辅助或代替人工客服精准回答常见或高频问题,降低企业客服人力成本。目前,环信在客服领域已经服务了58541家标杆客户,积累了人工智能在客户服务行业落地的大量最佳实践。
 
视频观看地址:点击观看
 
3.1,智能客服机器人在客服场景下的最佳实践:
 
3.1.1,无需人工标记和人工维护的机器人单轮会话,极大降低客服机器人的维护成本。

   一些问题是不依赖于对话历史,仅根据当前句子就能给出答案,难点在于机器能否理解同一语义的不同表达方法。环信智能机器人采用自然语言处理技术和深度学习技术建立对话模型,使用海量数据对模型进行训练,并借助客服系统中访客和客服的实时反馈来增强学习,精准识别用户意图,帮助人工客服回答各种问题。相比基于关键词匹配和人工定义规则大量标注数据的传统问答技术,环信智能机器人无需人工标记和人工维护相似问法,就可以在会话过程中识别同一问题的多种不同问法。
001.png

图1示例:环信机器人无需人工维护相似问法,就可以在会话过程中识别同一问题的多种不同问法。

3.1.2机器人多轮会话,支持更多复杂业务,进一步拓展机器人使用场景。

   而另一些问题则由于缺少足够信息或者过于模糊,需要通过多轮对话的方式来明确用户的需求。比如用户想查物流,但是缺少订单号等信息,机器人需要引导用户提供这些数据。这和单轮的问答相比,多轮对话的技术难点更多,比如指代的理解,句子的省略,用户状态的维护等等。

   环信智能机器人支持上下文语义和多轮会话,并预装多行业的领域知识,如电商行业的物流状态查询模型,产品保修会话模型等。这种基于行业领域和业务模型的多轮会话能力,相比单轮会话,进一步扩展了客服机器人对复杂客服业务场景的自动支撑能力。
002.png

图2示例:环信机器人通过多轮会话支持查询物流状态,并和企业业务系统做集成,真正意义上节省人工。

3.1.3无缝人机协作体验,复杂场景下最佳用户体验的客服模式。

   在一些比较复杂和特殊的服务场景,比如高客单价的金融行业售前咨询,机器人客服不能完全理解客户的个性化咨询要求的时候,我们可以无缝进入人机混合模式。在人机混合模式下,环信智能客服机器人向人工客服推荐备选答案,人工客服起到了保证答案质量充当专家客服的角色,这样既保证了客服的响应速度又提高了问题的回答准确性,同时降低了人工客服的工作量。

3.1.4,智能质检,准确率达到替代人工质检水平。

   环信机器人还提供自动智能质检功能,可以对全部客服会话进行实时或离线质检。 智能质检是基于环信在线客服各个领域的海量用户对话,提取出数百个客服对话特征,并用这些特征训练得到的一个通用质检模型。智能质检的准确率达到替代人工质检水平。

3.1.5. 支持智能自主学习,更高效的知识库

   环信智能机器人可以快速高效搭建知识库。既支持批量导入FAQ或用户手动维护问答知识,也支持智能自主学习。智能自主学习是指客服机器人自主学习人工客服的会话,自动生成新知识规则。相比手动维护问答知识,智能自主学习能力显著降低了客服机器人的维护成本,提高了知识库的准确性和时效性。环信智能机器人可预装多个领域的行业知识库。

附录:Gartner研究——虚拟客户助手(智能客服机器人) 分析师:布莱恩·玛纳萨马

定义:虚拟客户助理(VCA),代表公司进行模拟对话以传递信息和/或代表客户采取行动并执行交易。 VCA由四部分组成:

   ■接收请求和传递回应的用户界面■用于文本和语音的自然语言处理引擎■可以检索知识和内容数据存储库的搜索和知识引擎■用于分析意图的上下文引擎一些VCA还具有机器学习功能。

   定位和市场接受速度:IBM Watson,Microsoft Cortana,Next-IT,Creative Virtual和其他VCA供应商的工作正在提高人们对作为实用工具的虚拟助理(VA)技术的认知。 VCA的使用正处于临界点。大幅改进的自然语言处理技术,以聊天为中心的移动渠道与客户互动的应用,以及客户对机器人技术的接受程度,这些因素使得人们对VCA的兴趣越來越大。从被动的被人类编程出来的可以在结构化和非结构化内容库中找到问题答案的虚拟助手,到主动的有时候是机器学习得到的VCA的转变,其考察个人的特征并代表他们行动。虚拟助手正在经历从被动的被人类编程出来在结构化和非结构化内容库中找到问题答案到主动的通过机器学习能够理解用户个性化的需求并且随之采取灵活应对行为的转变。VCA技术有望在两至五年内成为主流。随着移动优先的用户体验转向,许多VCA都亟待更新,以支持多渠道客户与统一知识库的互动,特别是支持客户手机。

   用户建议:确定客户服务平台的当前状态和所需状态。今天您将使用什么样的客服方式和客服工具?您是否使用自然语言处理技术来确定客户到底咨询了什么?是将这个呼叫咨询分派给正确的客服接线员还是让客服机器人提供自动回复?VCA将成为支持多个客服渠道的起点。 VCA未来将可能改变你的日常生活;它可以是一个帮助你在移动设备上购买新健身设备的向导,也可以是一个帮助你开设银行帐户的虚拟客服人员。

   市场正在发生一种变化,对虚拟客服助手的逐渐重视以及使用频次的减少,这个现象已不如以前那么明显。在数字渠道中提供拟人化体验的驱动力正在发生改变。随着客户逐渐适应和接受与计算机的互动,其对具有拟人化情感的3D图像的需求正在减少。公司部署虚拟客服助手时他们发现有对于提升品牌的附加价值,而非仅仅模拟一种店内体验。VCA不仅是面向客户的,而是越来越多地部署为面向员工——帮助客户服务中心减少人工坐席操作时间以及保障客户咨询回复的一致性。

   将一组简单的串行项目与一个复杂的大型项目进行比较,以满足所有确定的需求。找到构成完整呼叫的最高频简单对话,以简单的方式实现自动化和提升客户满意度。然后,识别下一组完整的呼叫:在一段时间,技术与人工可进行合作处理这组呼叫,即当技术检测到问题(如技术储备的知识不足、客户声音难以辨别、或客户通过正确的操作明确要求由人类进行对话)时,人工操作员将接管此组呼叫。

   业务影响:VCA是狭义的、具有特殊用途的VA,用于销售、客户服务和数字商务,且具有独特的目标。VCA的商业案例有三方面。其解决了以下需求:

   ■满足客户对网络和移动渠道中客户支持的期望——更高的互动频率;全天候、即时的聊天可用性■将互动转向价格更低的客户自助服务渠道,更快获取解决方案;降低服务成本■提供积极的建议和参与,培养忠诚度和客户满意度。

    VCA的有效使用便于组织衡量其——特别是联络中心的——参与数量。在数字亭或自动取款机上使用启用语音的VCA可降低对类型化干预的需求,且有助于为非传统受众提供有趣的互动。

好处评级:高

市场渗透率:目标受众的5%至20%

成熟度:未成熟
 
点击查看Gartner报告全文
7
评论

【视频教程+源码】基于环信IM做一个仿微信APP-更新ing 郭永峰 高仿微信 仿微信 环信 XMPP

郭永峰 发表了文章 • 20133 次浏览 • 2017-05-16 15:29 • 来自相关话题

我只是一个普通人,做人要谦虚。
我不是大神,我也不是很厉害的。
天外有天,人外有人。
老师引入门,修行靠个人。
希望能帮助大家,谢谢。
    大家好,我是郭永峰(峰哥) | 一个普通大学计算机系毕业的大学生,曾就职于澳门遊澳集团有限公司,负责大型银联支付业务系统、跨国际短信业务系统(基于电信的SGIP)以及集团内部通讯系统 (负责android和openfire后台二次开发)的主要开发任务,担任项目负责人。13年就职于广州拓谷科技有限公司负责“酷蛙”车联网产品研发及汽车销售产品研发。14来年到17年2月份,就职于国内知名教育机构,负责教学研发及授课的工作。
 
本人现状况:
  
   在家录制教学视频(无收入),搞工作室,组建团队成立公司,如果大家觉得分享内容很喜欢,可以给我打点赏支持本人的工作室,二维码在文末,就不影响阅读了。

 
郭永峰IT教育工作室于2017年4月12日成立!
 
成立原因:

希望把近10年来从事IT互联网的知识分享给大家,包括Linux,WindowServer,Java,PHP,Android,iOS,H5等等等。
 

进入正题,本套课程基于环信IM教大家如何做一个类似微信的APP,只用于技术交流,请勿用于任何商业用途。
4月12号成立工作室,现在18号,过了一个星期一个星期录了5天的环信教程视频,我将放在网盘免费分享环信的教程视频主要是针对有开发经验者教程主要是使用环信来模仿微信来做一个即时通讯的案例课程主要是先讲socket基础 -> 环信 ->自定义协议希望这些教程视频能帮助大家,对即时通讯、socket和自定义协议有个较深入的了解同时能希望大家在面试时,在即时通讯这块不在陌生
  持续更新

第一阶段:即时通讯的了解和微信APP开发前的准备!

【视频教程+源码】基于环信IM做一个仿微信APP-01.即时通讯简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-02.XMPP简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-03.XMPP实现即时通信的准备工作(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-04.环信简介(了解) 

【视频教程+源码】基于环信IM做一个仿微信APP-05.集成环信的前提准备(掌握)
 
【视频教程+源码】基于环信IM做一个仿微信APP-06.环信SDK的版本的区别(掌握)

【视频教程+源码】基于环信IM做一个仿微信APP-07.微信-项目创建及代码目录结构规范(MVC)

【视频教程+源码】基于环信IM做一个仿微信APP-08.微信-集成环信SDK

【视频教程+源码】基于环信IM做一个仿微信APP-09.微信-登录界面排版

【视频教程+源码】基于环信IM做一个仿微信APP-10.微信-主界面搭建

【视频教程+源码】基于环信IM做一个仿微信APP-11.微信-注册功能

【视频教程+源码】基于环信IM做一个仿微信APP- 12.微信-登录功能

【视频教程+源码】基于环信IM做一个仿微信APP- 13.微信-自动登录

【视频教程+源码】基于环信IM做一个仿微信APP- 14.微信-主动退出
 
【视频教程+源码】基于环信IM做一个仿微信APP-15.微信-在其它设备登录
 
整个项目源码,git地址https://github.com/mayaole/fWeiXin

 微信打赏






支付宝打赏






谢谢大家的支持,个人微信号清扫描下面张图






 
郭永峰IT交流QQ群请加:596441895 查看全部
我只是一个普通人,做人要谦虚。
我不是大神,我也不是很厉害的。
天外有天,人外有人。
老师引入门,修行靠个人。
希望能帮助大家,谢谢。

    大家好,我是郭永峰(峰哥) | 一个普通大学计算机系毕业的大学生,曾就职于澳门遊澳集团有限公司,负责大型银联支付业务系统、跨国际短信业务系统(基于电信的SGIP)以及集团内部通讯系统 (负责android和openfire后台二次开发)的主要开发任务,担任项目负责人。13年就职于广州拓谷科技有限公司负责“酷蛙”车联网产品研发及汽车销售产品研发。14来年到17年2月份,就职于国内知名教育机构,负责教学研发及授课的工作。
 
本人现状况:
  
   在家录制教学视频(无收入),搞工作室,组建团队成立公司,如果大家觉得分享内容很喜欢,可以给我打点赏支持本人的工作室,二维码在文末,就不影响阅读了。

 
郭永峰IT教育工作室于2017年4月12日成立!
 
成立原因:

希望把近10年来从事IT互联网的知识分享给大家,包括Linux,WindowServer,Java,PHP,Android,iOS,H5等等等。
 

进入正题,本套课程基于环信IM教大家如何做一个类似微信的APP,只用于技术交流,请勿用于任何商业用途。
  1. 4月12号成立工作室,现在18号,过了一个星期
  2. 一个星期录了5天的环信教程视频,我将放在网盘免费分享
  3. 环信的教程视频主要是针对有开发经验者
  4. 教程主要是使用环信来模仿微信来做一个即时通讯的案例
  5. 课程主要是先讲socket基础 -> 环信 ->自定义协议
  6. 希望这些教程视频能帮助大家,对即时通讯、socket和自定义协议有个较深入的了解
  7. 同时能希望大家在面试时,在即时通讯这块不在陌生

  持续更新

第一阶段:即时通讯的了解和微信APP开发前的准备!

【视频教程+源码】基于环信IM做一个仿微信APP-01.即时通讯简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-02.XMPP简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-03.XMPP实现即时通信的准备工作(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-04.环信简介(了解) 

【视频教程+源码】基于环信IM做一个仿微信APP-05.集成环信的前提准备(掌握)
 
【视频教程+源码】基于环信IM做一个仿微信APP-06.环信SDK的版本的区别(掌握)

【视频教程+源码】基于环信IM做一个仿微信APP-07.微信-项目创建及代码目录结构规范(MVC)

【视频教程+源码】基于环信IM做一个仿微信APP-08.微信-集成环信SDK

【视频教程+源码】基于环信IM做一个仿微信APP-09.微信-登录界面排版

【视频教程+源码】基于环信IM做一个仿微信APP-10.微信-主界面搭建

【视频教程+源码】基于环信IM做一个仿微信APP-11.微信-注册功能

【视频教程+源码】基于环信IM做一个仿微信APP- 12.微信-登录功能

【视频教程+源码】基于环信IM做一个仿微信APP- 13.微信-自动登录

【视频教程+源码】基于环信IM做一个仿微信APP- 14.微信-主动退出
 
【视频教程+源码】基于环信IM做一个仿微信APP-15.微信-在其它设备登录
 
整个项目源码,git地址https://github.com/mayaole/fWeiXin

 微信打赏

微信.png


支付宝打赏

支付宝.png


谢谢大家的支持,个人微信号清扫描下面张图

个人.png


 
郭永峰IT交流QQ群请加:596441895
0
评论

【视频教程+源码】基于环信IM做一个仿微信APP-15.微信-在其它设备登录 环信 仿微信 郭永峰

郭永峰 发表了文章 • 2260 次浏览 • 2017-05-16 11:39 • 来自相关话题

接上篇

【视频教程+源码】基于环信IM做一个仿微信APP-01.即时通讯简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-02.XMPP简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-03.XMPP实现即时通信的准备工作(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-04.环信简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-05.集成环信的前提准备(掌握)
【视频教程+源码】基于环信IM做一个仿微信APP-06.环信SDK的版本的区别(掌握)
【视频教程+源码】基于环信IM做一个仿微信APP-07.微信-项目创建及代码目录结构规范(MVC)
【视频教程+源码】基于环信IM做一个仿微信APP-08.微信-集成环信SDK
【视频教程+源码】基于环信IM做一个仿微信APP-09.微信-登录界面排版
【视频教程+源码】基于环信IM做一个仿微信APP-10.微信-主界面搭建
【视频教程+源码】基于环信IM做一个仿微信APP-11.微信-注册功能
【视频教程+源码】基于环信IM做一个仿微信APP- 12.微信-登录功能
【视频教程+源码】基于环信IM做一个仿微信APP- 13.微信-自动登录
【视频教程+源码】基于环信IM做一个仿微信APP- 14.微信-主动退出
 
 
我是郭永峰,本套课程基于环信IM教大家如何做一个类似微信的APP,只用于技术交流,请勿用于任何商业用途。​
 
15.微信-在其它设备登录 查看全部
0
评论

【视频教程+源码】基于环信IM做一个仿微信APP- 14.微信-主动退出 仿微信 环信 郭永峰

郭永峰 发表了文章 • 924 次浏览 • 2017-05-16 11:35 • 来自相关话题

接上篇
【视频教程+源码】基于环信IM做一个仿微信APP-01.即时通讯简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-02.XMPP简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-03.XMPP实现即时通信的准备工作(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-04.环信简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-05.集成环信的前提准备(掌握)
【视频教程+源码】基于环信IM做一个仿微信APP-06.环信SDK的版本的区别(掌握)
【视频教程+源码】基于环信IM做一个仿微信APP-07.微信-项目创建及代码目录结构规范(MVC)
【视频教程+源码】基于环信IM做一个仿微信APP-08.微信-集成环信SDK
【视频教程+源码】基于环信IM做一个仿微信APP-09.微信-登录界面排版
【视频教程+源码】基于环信IM做一个仿微信APP-10.微信-主界面搭建
【视频教程+源码】基于环信IM做一个仿微信APP-11.微信-注册功能
【视频教程+源码】基于环信IM做一个仿微信APP- 12.微信-登录功能
【视频教程+源码】基于环信IM做一个仿微信APP- 13.微信-自动登录
 
 
我是郭永峰,本套课程基于环信IM教大家如何做一个类似微信的APP,只用于技术交流,请勿用于任何商业用途。​
 
 14.微信-主动退出 查看全部
0
评论

【视频教程+源码】基于环信IM做一个仿微信APP- 13.微信-自动登录 环信 仿微信 郭永峰

郭永峰 发表了文章 • 939 次浏览 • 2017-05-16 11:29 • 来自相关话题

接上篇

【视频教程+源码】基于环信IM做一个仿微信APP-01.即时通讯简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-02.XMPP简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-03.XMPP实现即时通信的准备工作(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-04.环信简介(了解) 
【视频教程+源码】基于环信IM做一个仿微信APP-05.集成环信的前提准备(掌握)
【视频教程+源码】基于环信IM做一个仿微信APP-06.环信SDK的版本的区别(掌握)
【视频教程+源码】基于环信IM做一个仿微信APP-07.微信-项目创建及代码目录结构规范(MVC)
【视频教程+源码】基于环信IM做一个仿微信APP-08.微信-集成环信SDK
【视频教程+源码】基于环信IM做一个仿微信APP-09.微信-登录界面排版
【视频教程+源码】基于环信IM做一个仿微信APP-10.微信-主界面搭建
【视频教程+源码】基于环信IM做一个仿微信APP-11.微信-注册功能
【视频教程+源码】基于环信IM做一个仿微信APP- 12.微信-登录功能
 
 
我是郭永峰,本套课程基于环信IM教大家如何做一个类似微信的APP,只用于技术交流,请勿用于任何商业用途。​
 
13.微信-自动登录 查看全部
0
评论

【视频教程+源码】基于环信IM做一个仿微信APP- 12.微信-登录功能 环信 仿微信 郭永峰

郭永峰 发表了文章 • 1060 次浏览 • 2017-05-16 11:25 • 来自相关话题

接上篇

【视频教程+源码】基于环信IM做一个仿微信APP-01.即时通讯简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-02.XMPP简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-03.XMPP实现即时通信的准备工作(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-04.环信简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-05.集成环信的前提准备(掌握)
【视频教程+源码】基于环信IM做一个仿微信APP-06.环信SDK的版本的区别(掌握)
【视频教程+源码】基于环信IM做一个仿微信APP-07.微信-项目创建及代码目录结构规范(MVC)
【视频教程+源码】基于环信IM做一个仿微信APP-08.微信-集成环信SDK
【视频教程+源码】基于环信IM做一个仿微信APP-09.微信-登录界面排版
【视频教程+源码】基于环信IM做一个仿微信APP-10.微信-主界面搭建
【视频教程+源码】基于环信IM做一个仿微信APP-11.微信-注册功能
 
 
我是郭永峰,本套课程基于环信IM教大家如何做一个类似微信的APP,只用于技术交流,请勿用于任何商业用途。​
 
12.微信-登录功能 查看全部
0
评论

【视频教程+源码】基于环信IM做一个仿微信APP-11.微信-注册功能 仿微信 环信 郭永峰

郭永峰 发表了文章 • 1027 次浏览 • 2017-05-16 11:21 • 来自相关话题

接上篇

【视频教程+源码】基于环信IM做一个仿微信APP-01.即时通讯简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-02.XMPP简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-03.XMPP实现即时通信的准备工作(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-04.环信简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-05.集成环信的前提准备(掌握)
【视频教程+源码】基于环信IM做一个仿微信APP-06.环信SDK的版本的区别(掌握)
【视频教程+源码】基于环信IM做一个仿微信APP-07.微信-项目创建及代码目录结构规范(MVC)
【视频教程+源码】基于环信IM做一个仿微信APP-08.微信-集成环信SDK
【视频教程+源码】基于环信IM做一个仿微信APP-09.微信-登录界面排版
【视频教程+源码】基于环信IM做一个仿微信APP-10.微信-主界面搭建
 
 
我是郭永峰,本套课程基于环信IM教大家如何做一个类似微信的APP,只用于技术交流,请勿用于任何商业用途。​
 
11.微信-注册功能 查看全部
0
评论

【视频教程+源码】基于环信IM做一个仿微信APP-10.微信-主界面搭建 郭永峰 仿微信 环信

郭永峰 发表了文章 • 1669 次浏览 • 2017-05-16 11:16 • 来自相关话题

接上篇

【视频教程+源码】基于环信IM做一个仿微信APP-01.即时通讯简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-02.XMPP简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-03.XMPP实现即时通信的准备工作(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-04.环信简介(了解)
【视频教程+源码】基于环信IM做一个仿微信APP-05.集成环信的前提准备(掌握)
【视频教程+源码】基于环信IM做一个仿微信APP-06.环信SDK的版本的区别(掌握)
【视频教程+源码】基于环信IM做一个仿微信APP-07.微信-项目创建及代码目录结构规范(MVC)
【视频教程+源码】基于环信IM做一个仿微信APP-08.微信-集成环信SDK
【视频教程+源码】基于环信IM做一个仿微信APP-09.微信-登录界面排版
 
 
我是郭永峰,本套课程基于环信IM教大家如何做一个类似微信的APP,只用于技术交流,请勿用于任何商业用途。​
 
10.微信-主界面搭建 查看全部