环信公开课19期回放:快速搭建一套直播答题系统实操

   本着对技术的热衷,对环信的眷恋和对党的忠诚,环信生态圈开发者基于环信即时通讯云写了直播答题开源项目-小信竞答。作为国内首个直播答题开源项目,“小信竞答”发表在IMGeek社区就受到了技术小伙伴们的好评,鉴于大家对直播答题的热情,3月29日举办了主题为“直播答题开源项目”的环信公开课,直播讲解如何快速搭建一套直播答题系统。
公开课第19期回放
 



 
 
课程大纲:

直播答题技术架构
1.    【同步问答】环信IM下发问题到海量用户确保毫秒级必达
2.    【视频美颜】环信人脸特效实时视频动态捕捉,贴纸美颜多种特效
3.    【无上限聊天室】环信直播聊天室高并发异步架构,弹性扩容应对流量峰值
4.    【智能反垃圾】环信智能反垃圾实时消息过滤及关键词屏蔽,及时规避风险
5.    【红包功能】奖金统计发放
6.    【复活卡、开黑组团】新玩法层出不穷
 “小信竞答”源码分享
1.    运行效果演示,现场互动答题送礼
2.    源码解读,国内首个开源直播答题项目
3.    经验之鉴,快速搭建一套直播答题系统实操

环信直播聊天室
1.    高并发异步架构,弹性扩容应对流量峰值
2.    多种消息格式,文字、表情、位置、扩展消息
3.    实时配置消息分级策略,重要消息优先必答
4.    后台管理审核功能,直播数据统计
5.    智能反垃圾,自定义敏感词过滤
6.    快速集成demo高质量代码示例
7.    聊天室人数无上限

小信竞答项目源码:github源码地址
 
感谢合作伙伴APICLloud,APKBUS,码客,七牛云,icustomer对本期环信公开课的大力支持
第19期公开课2副本.jpg

 
继续阅读 »
   本着对技术的热衷,对环信的眷恋和对党的忠诚,环信生态圈开发者基于环信即时通讯云写了直播答题开源项目-小信竞答。作为国内首个直播答题开源项目,“小信竞答”发表在IMGeek社区就受到了技术小伙伴们的好评,鉴于大家对直播答题的热情,3月29日举办了主题为“直播答题开源项目”的环信公开课,直播讲解如何快速搭建一套直播答题系统。
公开课第19期回放
 



 
 
课程大纲:

直播答题技术架构
1.    【同步问答】环信IM下发问题到海量用户确保毫秒级必达
2.    【视频美颜】环信人脸特效实时视频动态捕捉,贴纸美颜多种特效
3.    【无上限聊天室】环信直播聊天室高并发异步架构,弹性扩容应对流量峰值
4.    【智能反垃圾】环信智能反垃圾实时消息过滤及关键词屏蔽,及时规避风险
5.    【红包功能】奖金统计发放
6.    【复活卡、开黑组团】新玩法层出不穷
 “小信竞答”源码分享
1.    运行效果演示,现场互动答题送礼
2.    源码解读,国内首个开源直播答题项目
3.    经验之鉴,快速搭建一套直播答题系统实操

环信直播聊天室
1.    高并发异步架构,弹性扩容应对流量峰值
2.    多种消息格式,文字、表情、位置、扩展消息
3.    实时配置消息分级策略,重要消息优先必答
4.    后台管理审核功能,直播数据统计
5.    智能反垃圾,自定义敏感词过滤
6.    快速集成demo高质量代码示例
7.    聊天室人数无上限

小信竞答项目源码:github源码地址
 
感谢合作伙伴APICLloud,APKBUS,码客,七牛云,icustomer对本期环信公开课的大力支持
第19期公开课2副本.jpg

  收起阅读 »

iOS 自定义cell

简书地址:自定义cell(一)https://www.jianshu.com/p/8befabfdc4f0
               自定义cell(二)https://www.jianshu.com/p/85921a5da8d0

QQ20180410-161412@2x.png


QQ20180410-161420@2x.png

 
继续阅读 »
简书地址:自定义cell(一)https://www.jianshu.com/p/8befabfdc4f0
               自定义cell(二)https://www.jianshu.com/p/85921a5da8d0

QQ20180410-161412@2x.png


QQ20180410-161420@2x.png

  收起阅读 »

【环信征文】|PHP WEBIM整合到项目(一条龙服务包括保存聊天记录到本地数据库)

   我是用think PHP做的项目,我们的需求是用IM跟他人聊天并且保存聊天记录到本地。我把整个环信文件下载了下来放在了项目的js文件里。并且没有做单独的页面渲染直接用的环信原来的页面,所以大部分功能都写在了控制器里最后跳转到IM的页面。
第一步,IM集成
  这个可以参照文档,但是这个文档好像是过时的,如果集成失败可以上官方登陆页面 http://webim.easemob.com/ 把页面加载的文件抄下来。
第二步,自动登陆和他人聊天
  此步要先把网站上的用户注册一个环信账号,然后自动登陆跳过环信的登陆页面,然后把对方加为好友(此步如果对方没有环信账号也需要把好友注册一个环信账号)。上代码

微信图片_20180410135435.png


逻辑是这么实现的,因为在控制器里做的操作,所以登陆信息要保存在cookie里。里面的方法都可以在http://api-docs.easemob.com/%2 ... token这个环信的服务器端集成Swagger文档里找到,然后用Curl调用,或者一个更简单的方法,有一个完整的类可以用,链接在此https://github.com/easemob/emc ... t.php,简单的curl是这么用的

微信图片_20180409114955.png


好此步就此完成
第三步,头像、昵称 渲染
   这步我的处理方法是把你网站用户的头像和昵称查出来然后存在cookie里,然后在demojs文件里进行调用,这步主要麻烦的地方是需要在demo.js的文件里找到页面渲染的地方,大约有8个地方(23288,27321,29764,29862,30101,31211,31360,31465)
   这三步完成基本就完成了IM整合进项目了,还有一个保存聊天记录到本地,我没有用官方的接口来下载历史记录,听说下载下来是一个包,而且数据还会有丢失,所以我的做法是每次发送消息调用自己的Ajax来进行保存数据库操作,然后新在打开聊天的时候请求后台获得聊天记录。
  好,我在demojs里找到了2个发送消息时候的方法,一个是发送文字和表情,一个是发送图片。sendText(27399)这个方法是发送文字和表情的

微信图片_20180409135255.png


  msg.boy里面可以获得到你需要保存在数据库里的所有信息,chat_time是因为聊天记录的时间格式是2018/4/9 上午9:53:03这种的所以我自己加上去的。
  pictureChange(22977)这个方法是发送图片的,这里的url非常重要,而且在msg.set在外面拿不到所以我放在了方法里面调用的Ajax,这个url 是
https://a1.easemob.com/1110170 ... 79a8b
这样的二进制一会需要下载到本地或者上传到你需要的图片存储空间,我放在了七牛上。

微信图片_20180409135626.png


  保存文字信息非常简单,就像下图一样就可以了,下面的做的判断是当消息类型是图片的时候调用一下图片上传方法

微信图片_20180409140143.png



微信图片_20180410135615.png


  这个图片是图片上传方法,我在后台用CURL进行了上传操作,最开始我先把图片保存在了本地然后再上传,后来我找了二进制可以上传,改成了这个样子,值得注意的是我用CURL调用的url返回的值会有一个红色的符号,所以我用substr给它截掉了,之前没发现怎么都找不到图片。这里的接口就是一个普通的上传方法然后返回的是图片名称。这样聊天记录也保存完毕了。
  表结构

微信图片_20180409142529.png


  下一步是读取聊天记录releaseChatRecord这个方法是demojs每次你点击聊天窗口都会触发的方法,我把ajax放在这这里。

微信图片_20180409141116.png


  图片里的targetId就是你当天聊天的好友id,自己的id怎么得到不需要说了吧,你肯定是在登陆状态才能聊天。Demo.chatRecord这个就是需要替换的聊天记录,Ajax请求后台

微信图片_20180409141344.png


  这里注意的是要获得聊天记录需要进行红圈里的判断,来分别你给我发的消息和你给我发的消息,我之前犯得错误没判断最后只获得了我给他人发的消息记录。。。循环里的是构造demojs需要用的json数据。这个对象结构可以在releaseChatRecord方法里console.log()出来然后自己拼装。
  这样已经基本完成了最后上成功后的图片

微信图片_20180409142025.png


  还有个问题没处理就是未送达那个文字,因为我构造的数据里没有加上read=true.你可以选择把IM里这个功能关闭或者在数据里加上去。
  这样保存聊天记录的方式是每次发送都进行保存如果人数太多或太频繁可能会出现问题,以后可能会换成调用官网的获得历史记录的接口。
 
继续阅读 »
   我是用think PHP做的项目,我们的需求是用IM跟他人聊天并且保存聊天记录到本地。我把整个环信文件下载了下来放在了项目的js文件里。并且没有做单独的页面渲染直接用的环信原来的页面,所以大部分功能都写在了控制器里最后跳转到IM的页面。
第一步,IM集成
  这个可以参照文档,但是这个文档好像是过时的,如果集成失败可以上官方登陆页面 http://webim.easemob.com/ 把页面加载的文件抄下来。
第二步,自动登陆和他人聊天
  此步要先把网站上的用户注册一个环信账号,然后自动登陆跳过环信的登陆页面,然后把对方加为好友(此步如果对方没有环信账号也需要把好友注册一个环信账号)。上代码

微信图片_20180410135435.png


逻辑是这么实现的,因为在控制器里做的操作,所以登陆信息要保存在cookie里。里面的方法都可以在http://api-docs.easemob.com/%2 ... token这个环信的服务器端集成Swagger文档里找到,然后用Curl调用,或者一个更简单的方法,有一个完整的类可以用,链接在此https://github.com/easemob/emc ... t.php,简单的curl是这么用的

微信图片_20180409114955.png


好此步就此完成
第三步,头像、昵称 渲染
   这步我的处理方法是把你网站用户的头像和昵称查出来然后存在cookie里,然后在demojs文件里进行调用,这步主要麻烦的地方是需要在demo.js的文件里找到页面渲染的地方,大约有8个地方(23288,27321,29764,29862,30101,31211,31360,31465)
   这三步完成基本就完成了IM整合进项目了,还有一个保存聊天记录到本地,我没有用官方的接口来下载历史记录,听说下载下来是一个包,而且数据还会有丢失,所以我的做法是每次发送消息调用自己的Ajax来进行保存数据库操作,然后新在打开聊天的时候请求后台获得聊天记录。
  好,我在demojs里找到了2个发送消息时候的方法,一个是发送文字和表情,一个是发送图片。sendText(27399)这个方法是发送文字和表情的

微信图片_20180409135255.png


  msg.boy里面可以获得到你需要保存在数据库里的所有信息,chat_time是因为聊天记录的时间格式是2018/4/9 上午9:53:03这种的所以我自己加上去的。
  pictureChange(22977)这个方法是发送图片的,这里的url非常重要,而且在msg.set在外面拿不到所以我放在了方法里面调用的Ajax,这个url 是
https://a1.easemob.com/1110170 ... 79a8b
这样的二进制一会需要下载到本地或者上传到你需要的图片存储空间,我放在了七牛上。

微信图片_20180409135626.png


  保存文字信息非常简单,就像下图一样就可以了,下面的做的判断是当消息类型是图片的时候调用一下图片上传方法

微信图片_20180409140143.png



微信图片_20180410135615.png


  这个图片是图片上传方法,我在后台用CURL进行了上传操作,最开始我先把图片保存在了本地然后再上传,后来我找了二进制可以上传,改成了这个样子,值得注意的是我用CURL调用的url返回的值会有一个红色的符号,所以我用substr给它截掉了,之前没发现怎么都找不到图片。这里的接口就是一个普通的上传方法然后返回的是图片名称。这样聊天记录也保存完毕了。
  表结构

微信图片_20180409142529.png


  下一步是读取聊天记录releaseChatRecord这个方法是demojs每次你点击聊天窗口都会触发的方法,我把ajax放在这这里。

微信图片_20180409141116.png


  图片里的targetId就是你当天聊天的好友id,自己的id怎么得到不需要说了吧,你肯定是在登陆状态才能聊天。Demo.chatRecord这个就是需要替换的聊天记录,Ajax请求后台

微信图片_20180409141344.png


  这里注意的是要获得聊天记录需要进行红圈里的判断,来分别你给我发的消息和你给我发的消息,我之前犯得错误没判断最后只获得了我给他人发的消息记录。。。循环里的是构造demojs需要用的json数据。这个对象结构可以在releaseChatRecord方法里console.log()出来然后自己拼装。
  这样已经基本完成了最后上成功后的图片

微信图片_20180409142025.png


  还有个问题没处理就是未送达那个文字,因为我构造的数据里没有加上read=true.你可以选择把IM里这个功能关闭或者在数据里加上去。
  这样保存聊天记录的方式是每次发送都进行保存如果人数太多或太频繁可能会出现问题,以后可能会换成调用官网的获得历史记录的接口。
  收起阅读 »

iOS 中会话列表无法在获取消息后自动刷新,只能通过跳转到别的页面返回之后才会刷新。。

      在网上找到相似的答案,-(void)conversationListDidUpdate:(NSArray *)aConversationList{

    [self.tableView reloadData];

}说要实现这个方法。。可是这个方法是EMChatmanagerdelegate中的方法,单实现这个方法并没有走。。
大家有遇到过的吗?
继续阅读 »
      在网上找到相似的答案,-(void)conversationListDidUpdate:(NSArray *)aConversationList{

    [self.tableView reloadData];

}说要实现这个方法。。可是这个方法是EMChatmanagerdelegate中的方法,单实现这个方法并没有走。。
大家有遇到过的吗? 收起阅读 »

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

概述
 
今天看了环信的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已经完成,功能很简单,如果需要添加额外功能的话,可以自行参考官网,官网给出的教程还是很不错的!

最后希望大家能多多支持我,需要你们的支持喜欢!!
继续阅读 »
概述
 
今天看了环信的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已经完成,功能很简单,如果需要添加额外功能的话,可以自行参考官网,官网给出的教程还是很不错的!

最后希望大家能多多支持我,需要你们的支持喜欢!! 收起阅读 »

源码下载:全国首个直播答题开源项目了解一下!!!(基于环信即时通讯云)

   2018年伊始,全民直播答题浪潮来袭,一度被认为是一个新的互联网风口,王思聪凭借在现象级产品《冲顶大会》上疯狂"撒币"一时风光无二,凭借超高奖金和超低门槛吸引了大量网民参与和市场的目光。正因为直播答题是一种通过极低的成本来推动APP获客、保留存、拉活跃的新模式,各类直播答题APP如雨后春笋般进入大家的视野,越来越多企业希望赶上这波风口,快速搭建一套直播答题系统。作为一名环信生态圈资深开发者,本着对技术的热衷,对环信的眷恋和对党的忠诚,基于环信即时通讯云写了“小信竞答”这个直播答题开源项目,目前项目源码已全部免费开放,希望对有需求的企业和开发者提供一个思路和参考。



 

[b]
微信图片_20180316190105.jpg
[/b]
 
小信竞答技术架构图:
theFlowChart.png

     整个项目分为管理员端,观众端和服务端,首先在服务端预设好题目,由管理员发起直播开始答题,服务端收到指令将12道题目利用环信IM推送到观众端,观众端收到题目开始答题,将答案返回给服务端由服务端进行判断,如果答题正确进入下一题,答题错误判断是否使用复活卡,这里要注意的是需要加一个复活卡的使用次数判断。
 
   在整个答题过程中,管理员端会定时去服务端查询答题结果,等到全部答题结束,点击结束本次答题,服务端将计算好的结果返回并发放奖金,使用环信IM推送将答题结果推给观众端。
 
小信竞答效果图

微信图片_20180316190206.jpg


关于直播间:
   直播间由直播画面和聊天室两个部分组成,“小信竞答”的聊天室使用环信聊天室,集成比较简单,基础版就能支持5000人在线聊天,增值服务版聊天室人数无上限,可以去环信官网注册一个开发者账号,创建应用将APPKEY替换成自己的;环信直播聊天室可以集成所有市场主流CDN厂商的推拉流功能(腾讯,七牛,UCloud,网宿等)。
 
环信直播聊天室特点  
This is Title
 
1、采用支持高并发的异步架构,轻松应对千万级并发请求; 各项基础服务集群化,确保系统高可用性; 系统冗余度高,容量评估体系完善,弹性扩容应对流量峰值;
2、支持各种消息格式:文字、表情、图片、声音、视频、附件、位置、扩展消息;
3、支持实时配置的消息分级策略,确保重要消息优先必达; 
4、支持直播聊天室后台管理及审核功能,提供直播相关数据统计;
5、提供智能反垃圾和自定义敏感词过滤功能;
6、快速集成,demo提供高质量代码示例,可根据运营情况随时扩展;
7、聊天室人数无上限 
小信竞答项目源码: github源码地址
 
写到最后:
   
     小信竞答源码全部开放,仅供学习和参考,如果作为商业用途,按照广电总局对网络直播答题节目管理的,需要 “网络视听许可证、主持人持证、还有通过审批发放的节目备案号”,三证缺一不可,未持有《信息网络传播视听节目许可证》的任何机构和个人,一律不得开办网络直播答题节目。
 
本月底《环信公开课第19期-直播答题开源项目》将线上讲解“小信竞答”实现思路,手把手教您从零开始搭建一个直播答题项目,扫码加入公开课微信群与大牛面对面交流。
微信图片_20180316190334.jpg

 
继续阅读 »
   2018年伊始,全民直播答题浪潮来袭,一度被认为是一个新的互联网风口,王思聪凭借在现象级产品《冲顶大会》上疯狂"撒币"一时风光无二,凭借超高奖金和超低门槛吸引了大量网民参与和市场的目光。正因为直播答题是一种通过极低的成本来推动APP获客、保留存、拉活跃的新模式,各类直播答题APP如雨后春笋般进入大家的视野,越来越多企业希望赶上这波风口,快速搭建一套直播答题系统。作为一名环信生态圈资深开发者,本着对技术的热衷,对环信的眷恋和对党的忠诚,基于环信即时通讯云写了“小信竞答”这个直播答题开源项目,目前项目源码已全部免费开放,希望对有需求的企业和开发者提供一个思路和参考。



 

[b]
微信图片_20180316190105.jpg
[/b]
 
小信竞答技术架构图:
theFlowChart.png

     整个项目分为管理员端,观众端和服务端,首先在服务端预设好题目,由管理员发起直播开始答题,服务端收到指令将12道题目利用环信IM推送到观众端,观众端收到题目开始答题,将答案返回给服务端由服务端进行判断,如果答题正确进入下一题,答题错误判断是否使用复活卡,这里要注意的是需要加一个复活卡的使用次数判断。
 
   在整个答题过程中,管理员端会定时去服务端查询答题结果,等到全部答题结束,点击结束本次答题,服务端将计算好的结果返回并发放奖金,使用环信IM推送将答题结果推给观众端。
 
小信竞答效果图

微信图片_20180316190206.jpg


关于直播间:
   直播间由直播画面和聊天室两个部分组成,“小信竞答”的聊天室使用环信聊天室,集成比较简单,基础版就能支持5000人在线聊天,增值服务版聊天室人数无上限,可以去环信官网注册一个开发者账号,创建应用将APPKEY替换成自己的;环信直播聊天室可以集成所有市场主流CDN厂商的推拉流功能(腾讯,七牛,UCloud,网宿等)。
 
环信直播聊天室特点  
This is Title
 
1、采用支持高并发的异步架构,轻松应对千万级并发请求; 各项基础服务集群化,确保系统高可用性; 系统冗余度高,容量评估体系完善,弹性扩容应对流量峰值;
2、支持各种消息格式:文字、表情、图片、声音、视频、附件、位置、扩展消息;
3、支持实时配置的消息分级策略,确保重要消息优先必达; 
4、支持直播聊天室后台管理及审核功能,提供直播相关数据统计;
5、提供智能反垃圾和自定义敏感词过滤功能;
6、快速集成,demo提供高质量代码示例,可根据运营情况随时扩展;
7、聊天室人数无上限 
小信竞答项目源码: github源码地址
 
写到最后:
   
     小信竞答源码全部开放,仅供学习和参考,如果作为商业用途,按照广电总局对网络直播答题节目管理的,需要 “网络视听许可证、主持人持证、还有通过审批发放的节目备案号”,三证缺一不可,未持有《信息网络传播视听节目许可证》的任何机构和个人,一律不得开办网络直播答题节目。
 
本月底《环信公开课第19期-直播答题开源项目》将线上讲解“小信竞答”实现思路,手把手教您从零开始搭建一个直播答题项目,扫码加入公开课微信群与大牛面对面交流。
微信图片_20180316190334.jpg

  收起阅读 »

【环信集成指南】Android sdk 的两种导入方式

环信AndroidSDK官网文档提供了两种导入方式,线上gradle远程连接导入和本地导入,线上导入方便快捷,本地导入较为灵活,今天就跟大家详细讲解下两种方式的具体实现,小伙伴们可以根据自己的业务自由选择。
1.线上gradle远程连接导入

线上导入方便快捷,直接使用环信最新版sdk,但是值得注意的是线上的sdk不包含实施音视频,也不支持easeui库线上导入


首先在项目根目录build.gradle文件的allprojects→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.3.0'
}
官网文档参考
 
2.本地导入(sdk和easeui两种)

本地导入比较灵活,可以根据自己项目的开发需求根据功能去导入,比如sdk分为有实时音视频的sdk和没有实时音视频的sdk包,用户大可根据自己的需求去导入,这样稍微减少了sdk包大的问题


 easeui的导入
   本地导入也可以导入easeui库,easeui库是基于sdk开发的带ui的库,功能基本都实现,并携带写好的ui,用户在看过demo示例之后认为easeui符合自己的开发需求可以直接依赖Easeui,导入方式 
Eclipse 中导入
   先把 EaseUI 项目导入到 Eclipse 中。
在自己的项目中把 EaseUI 作为一个 library 引入。右键你的项目→Android→点击右下角的Add按钮→选中 EaseUI→OK→OK。
Android Studio 中导入
打开你的 AS 项目→File→New→Import Module→选择或输入 EaseUI 库路径→Next→Next→Finish。
 
sdk导入
   很多用户是不知道sdk是包含哪些文件的,sdk是有jar包和so包组成,其中jar包命名hyphenatechat_3.3.8.jar  
其中后边的数字3.3.8就是使用的sdk的具体版本号。
   So包有arm64-v8a、armeabi、armeabi-v7a、x86 其中x86根据自己项目需求可以去了,x86针对的是虚拟机,可以直接去了。
   armeabi和armeabi-v7a是相近似的指令集,armeabi和armeabi-v7a可以互换,v7a是增强型指令集,运行速度,效率均有所提高,他们都是32位指令,并且兼容,arm64-v8a对应arm64位指令集

3.3_.8_sdk_.png


有实时音视频和没有实时音视频包
   libs.av 文件夹:包含IM和实时音视频功能所需要的 jar 和 so 文件
   libs.lite 文件夹:无实时语音、实时视频功能的 SDK 包,如果项目中只用到聊天功能,可以把项目里的 jar 和 so 文件替换成此文件夹里的文件  文档参考

 

 

 
 
 
 
继续阅读 »
环信AndroidSDK官网文档提供了两种导入方式,线上gradle远程连接导入和本地导入,线上导入方便快捷,本地导入较为灵活,今天就跟大家详细讲解下两种方式的具体实现,小伙伴们可以根据自己的业务自由选择。
1.线上gradle远程连接导入

线上导入方便快捷,直接使用环信最新版sdk,但是值得注意的是线上的sdk不包含实施音视频,也不支持easeui库线上导入


首先在项目根目录build.gradle文件的allprojects→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.3.0'
}
官网文档参考
 
2.本地导入(sdk和easeui两种)

本地导入比较灵活,可以根据自己项目的开发需求根据功能去导入,比如sdk分为有实时音视频的sdk和没有实时音视频的sdk包,用户大可根据自己的需求去导入,这样稍微减少了sdk包大的问题


 easeui的导入
   本地导入也可以导入easeui库,easeui库是基于sdk开发的带ui的库,功能基本都实现,并携带写好的ui,用户在看过demo示例之后认为easeui符合自己的开发需求可以直接依赖Easeui,导入方式 
Eclipse 中导入
   先把 EaseUI 项目导入到 Eclipse 中。
在自己的项目中把 EaseUI 作为一个 library 引入。右键你的项目→Android→点击右下角的Add按钮→选中 EaseUI→OK→OK。
Android Studio 中导入
打开你的 AS 项目→File→New→Import Module→选择或输入 EaseUI 库路径→Next→Next→Finish。
 
sdk导入
   很多用户是不知道sdk是包含哪些文件的,sdk是有jar包和so包组成,其中jar包命名hyphenatechat_3.3.8.jar  
其中后边的数字3.3.8就是使用的sdk的具体版本号。
   So包有arm64-v8a、armeabi、armeabi-v7a、x86 其中x86根据自己项目需求可以去了,x86针对的是虚拟机,可以直接去了。
   armeabi和armeabi-v7a是相近似的指令集,armeabi和armeabi-v7a可以互换,v7a是增强型指令集,运行速度,效率均有所提高,他们都是32位指令,并且兼容,arm64-v8a对应arm64位指令集

3.3_.8_sdk_.png


有实时音视频和没有实时音视频包
   libs.av 文件夹:包含IM和实时音视频功能所需要的 jar 和 so 文件
   libs.lite 文件夹:无实时语音、实时视频功能的 SDK 包,如果项目中只用到聊天功能,可以把项目里的 jar 和 so 文件替换成此文件夹里的文件  文档参考

 

 

 
 
 
  收起阅读 »

【环信征文】| iOS集成环信推送,最详细流程(证书创建、环信集成、测试)

这几天项目里又用到了环信的推送,虽然之前做过,但是很久不做还是有很多细节没有注意到,所以还是决定从头开始做一遍,把每一个环节都详细记录下来,同样的把每一个坑也记录下来.方便自己以后做的时候忘记哪个流程了可以在看一遍.我很能理解那种遇到问题网上百度一堆类似答案但是并不好使的情况,所以我会将我在项目中遇到的问题都贴出来,希望能给大家带来些许参考和帮助,

一.推送的原理和流程(着急做推送的可以跳过这一步)
首先给大家推荐一个介绍推送机制很优秀的帖子:http://www.jianshu.com/p/e347f999ed95 ,里面关于本地推送和远程推送的介绍都很详细,至少我看了感觉还是收获很多的.尤其是里面有几张图片不知道是博主在哪里找的,但是真的是一看就透,太赞了,所以我果断盗过来了0.0. 这里我对推送的流程做了一个简单的叙述,力求用最简单的语言能说明整个推送的机制.

先搬过来一张图再说

692194-fc99211b942ffb8c.png


再搬一张:

692194-a1764a5b6ef76592.png



当我们的苹果手机联网的时候,会自动与苹果的服务器建立长连接,长连接的好处有很多,比如系统升级、时间校准、数据传输和响应比较快以及数据可以保持最新状态等功能.上面这两张图片简单的讲述了推送的流程:

- 1.首先我们需要将自己设备的UDID和应用的Bundle Identifier发送到苹果的服务器,然后苹果的服务器会返回给我们一个DeviceToken,这个在我看来就是创建推送证书和描述文件的过程.
- 2.我们将包含手机和应用标示的打包文件上传到做推送的服务器上去,当我们从推送服务器的后台发起推送消息的时候,推送服务器会将我们的DeviceToken和需要发送的消息Message发送到苹果的APNS(Apple push Notification Service)服务器.
- 3.当苹果的服务器收到DeviceToken和需要发送的消息Message时,会根据DeviceToken中的UDID查找设备,根据DeviceToken中的Bundle Identfier查找该应用,并将Message发送到该设备上.

下面是以QQ服务器为栗子说明的即时通讯的机制:

692194-42cd5b5723039e84.png


图片已经说得够详细明了了,我就不插嘴了,下面开始我们的工程.

二.具体流程

我们创建一个名为TestDemo的工程,我是使用Xcode8.1来开发的,工程名为PushDemo,创建好的工程界面如下(Xcode8)

1232108-fecb3186b8c4700d.png


从Xcode8之后,Xcode提供了自动管理证书的功能,这个用起来很方便,我目前在工程中用到的最多的地方就是创建好一个Demo之后,如果想真机运行的话,那么只需要在Team选择框里选择我的开发账户,接下来下面会出现一个加载提示圈,等它加载完了就可以在真机上运行了,这个过程实际上是Xcode使用你当前的BundleId去该账户的开发这中心创建了对应的AppId和描述文件,但是我们既然是作为一个开发流程的记录,就自己来创建这些东西,所以,我们取消选择Automatically manage signing选项.此时界面如下:

1232108-6da09aaa4693b3b3.png



好了,我们要正式开始我们的工作了GO GO GO!
1. 首先我们先去官网创建AppID和描述文件.      

我们是要集成推送的,所以我们需要用到cer文件,这个东西实际上就是苹果给开发者颁发的一个证书,我们需要将它导入到我们的AppId配置里,否则的话是无法集成推送的,还记得安装应该的时候会提示"无法安装为认证发布者的应用"之类的信息么,我猜测这个cer文件就是我们身份的标示,使我们开发的应用可以供人们正常安装使用,关于证书有一篇很详细的帖子,希望了解证书之类信息的看官可以去瞅瞅:http://m.blog.csdn.net/article/details?id=8617788

创建cer文件的流程很简单,打开"钥匙串访问"(虽然很好找,但是还是把图贴出来吧,怕小朋友迷路)

1232108-ab1cf50531874785.png



1232108-6438c3fb50b4aaa5.png



打开钥匙串之后点击"从证书颁发机构请求证书"


1232108-d4a8951b51e6cceb.png


邮箱和常用名随便填写,记住下面的选择框选择"存储到磁盘"

1232108-bda705277e11698e.png



点击存储

1232108-07e46d1757718ea4.png



已经在桌面保存了


1232108-43a584c54d8f6cf2.png



到此,我们已经创建好了cer文件,接着我们去开发者中心创建AppId和描述文件

2. 创建AppId和描述文件

首先进入开发者中心,百度搜索Apple Developer,(哎 真的是详细到家了啊,我都人不下去了)
上图

1232108-cedf60744b970a2e.png



输入开发者账户,登录进去


1232108-2b564af543f98b20.png


你将看到这个页面

1232108-a8daff6248a1238a.png



点击看到:

1232108-e9a6e57aa9930544.png


输入AppId文件名和BundleId

1232108-ae96fe218d56e753.png


选中下面的PushNotifications

1232108-38bf6bb6a67f51d2.png


点击Continue:

1232108-934cf686ea792fe8.png


点击register:

1232108-083327989bcbe786.png


点击Done回到AppId列表页面

1232108-0538ef84dea33c70.png


在AppId列表页面可以看到我们的AppID了

1232108-95b229c6dbadcdac.png



但是,还没有完成,因为我们是要做推送的,所以需要上传我们的cer文件
,点击我们的AppId,在展开的详情里可以看到:

1232108-15f6e6cba67bcf32.png




Push Notification的两个指示灯还是黄色的状态,我们要将它启用,点击Edit,在点开的页面里滑动至底部,记得要选中Push Notification按钮,接着点击上方的开发证书下的创建证书按钮:

1232108-6e60ef33f39c3c3e.png



点击Continue

1232108-20ba8ef5aac404fe.png



点击 choose file:

1232108-a8b6d1f97c9f57a7.png



将我们从开发机构请求的证书传上去,之后点击Register:

1232108-be277d8092ca589a.png



点击Register之后的页面,点击download,将其下载到桌面上,download之后记得点击done完成文件创建:

1232108-70ad59ee048b37de.png



桌面上的文件:

1232108-ea6f4078346a5a1c.png



现在我们就完成了给AppID创建开发者证书,然后我们要给它创建发布者证书,点击Done之后回到AppIds列表,如果找不到的话,点击右边的App IDs

1232108-f3563cf07940ad50.png



点开项目的AppId,此时界面如下,点击最下面的CreateCertificate,开始给AppID创建发布者证书,给AppId创建发布者证书流程跟创建开发者证书是一样的!给AppId创建发布者证书流程跟创建开发者证书是一样的!给AppId创建发布者证书流程跟创建开发者证书是一样的!重要的事情说三遍!!因为我不贴出来创建发布证书的图了,所以各位根据创建开发证书的流程再走一遍就好,同样也要将发布者证书下载到本地.:

1232108-5d146f8fcbf96aa2.png



1232108-f4959adf27635124.png



当创建好之后在回到这个页面时,应该显示如下所示:

1232108-d9e0b2bf3794fad2.png



此时本地我们下载的文件如下:

1232108-651e46a585df0fd2.png



然后将这两个证书拖到钥匙串里,步骤如下:
首先打开钥匙串:

1232108-2ed433418c0ceaf9.png



1232108-4907f4f3f01371e6.png


然后先点击:系统-证书,然后将两个文件拖进去,会提示你输入开机密码,输入就好了(建议添加之前先对这个界面截屏,添加完之后可以对比刚刚添加了那些文件)

1232108-9e9434ee2246e3ce.png



添加完之后是这个样子,画框的是我们的证书

1232108-c71476ca00c853ec.png



然后选择左边的"登录"选项,可以看到我们刚才创建的证书

1232108-b7e1a0917e1bdc6a.png


选中第一个证书,然后右键(你懂得右键的意思),选择导出...

1232108-b020b7d0a48f795d.png



选择导出为P12文件,存储在桌面上,获取到P12文件.对这两个证书进行同样的操作.(记得标题有(Develop)的起名为Product文件,第二个证书导出的时候起名为Develop,名字可以自己定,只是为了区别)

1232108-04d80a4621bc1708.png


然后会提示你输入密码,这里我设置的密码是zx123456,自己设定好一定要记住,一会儿要用.

1232108-409c20593f4f262e.png


然后可以在桌面上看到我们导出的P12文件啦

1232108-964de37f66433eaa.png



现在我们就完成了所有的证书的创建,可以去环信上创建我们的应用啦.

3.创建真机调试文件以及导入到项目中

因为必须要进行真机测试,而且我们关闭了自动管理证书,就导致Xcode8不会自动帮我们生成证书,所以我们要自己创建真机调试证书并导入到项目中去,流程如下:

创建描述文件:

1232108-9dbec2cea23ab8e1.png



选择开发模式,下一步:

1232108-edece2d8c17d8f27.png



选择对应的AppID,选择我们刚才创建的AppId:

1232108-ee9029c89f0c34d2.png



选择开发团队,我一般都是全选的,下一步:

1232108-3744e08d9d10aa55.png



选择真机调试的机器,全选,下一步:

1232108-124184468c7c6531.png



下一步:

1232108-c6c0e50e57add4be.png



将创建好的描述文件下载下来,放到桌面上:

1232108-8a2c9400633c796d.png



创建好的描述文件:

1232108-40bebec424947b9d.png



首先选择debug模式下载的真机调试描述文件:

1232108-a1d8a4c3a0bb0a23.png


选择桌面上刚刚下载的描述文件:

1232108-692279ac01c7d137.png



使用同样的步骤,选择Release模式下的真机调试文件,一模一样的操作,不贴图了.两个文件都导入进去之后,插上真机,就可以进行真机调试了.

4.在环信创建我们的应用

首先百度搜索环信,打开他们的官网,先注册账户,注册过的可以跳过了,上图:
注册的时候选择"注册即时通讯云"

1232108-672cbab760c523f9.png



注册的时候需要填写各种信息,按照格式填写就好了,填写完之后登陆,点击创建应用

1232108-bd67f4f4f35cd764.png



填写应用信息

1232108-4d748bd8c621d0ff.png



填写完如下图咯

1232108-bbdc1fbea11501aa.png



然后需要上传我们的P12文件,图片很清晰- -,不多说,第一次我选择上传的是生产证书:

1232108-6b5a19a243a78839.png



第二次上传开发证书:

1232108-538c02769688cac0.png



至此,我们的证书开发也都上传完了,路漫漫其修远兮,开始集成环信到代码里吧

5.集成环信到项目中

首先在这里下载最新的SDK(截至到写本文时最新的SDK为)

http://www.easemob.com/download/im 环信推送SDK下载链接

点击iOS的最新SDK下载,这里下载的是V3.x的SDK

1232108-279c3c47c46ec724.png



下载到桌面是这个鬼样子

1232108-9d5b7d0ee1c2d404.png



我们只需要将画圈的两个文件夹导进去工程里就好了,其他的用不上

1232108-e8d9522b4f496454.png



导进去之后文件列表是这样,编译会出错别急,慢慢改.

1232108-da727a18407e70d1.png



向项目里添加需要的库

1232108-e0ac523eac1d6042.png



上面的图片是截取的环信官方文档,我添加完是这个样子的:

1232108-5409054190742754.png


方便复制库名的文字:
CoreMedia.framework
AudioToolbox.framework
AVFoundation.framework
MobileCoreServices.framework
ImageIO.framework
libc++.dylib
libz.dylib
libstdc++.6.0.9.dylib
libsqlite3.dylib
(如果使用的是 xcode7,后缀为 tbd。)
这一步很重要,因为SDK 不支持 bitcode,所以要将 Build Settings → Linking → Enable Bitcode 中设置 NO。


1232108-96cd9023e11f17bd.png



command+B编译工程,大量爆红.别着急,修改我们的PCH文件就好了
在PCH文件添加
```
#ifdef __OBJC__
    #import <UIKit/UIKit.h>
#endif
```

将我们所有定义和添加的头文件和宏定义,都放在#ifdef __OBJC__和#endif中间
就可以解决这个问题.

然后在项目里打开推送:

1232108-96cd9023e11f17bd.png



6.测试是否集成成功

首先,我们去环信的后台给我们的应用添加一个用户

1232108-8abe301c76c6c7f4.png



用户名我设置成了:13051698888  密码设置成了:222222

1232108-94c1ef7dbdf3014c.png



接着我们要去appledate.m文件里添加东西了,很重要一步,废话不多说,直接贴出来需要配置的代码,直接拿去用0.0,需要添加的东西我在注释里注释的很明白...
记得要导进去头文件
#import "EMSDK.h"

```
@interface AppDelegate ()<EMChatManagerDelegate>

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //AppKey:注册的AppKey,点击"应用概述"可以看到AppKey,粘贴过来就可以。
    //apnsCertName:推送证书名,填写你的开发证书或者发布证书名,就是上传到环信后台的两个中的一个,什么环境下测试使用什么环境的证书。
    EMOptions *options = [EMOptions optionsWithAppkey:@"1192161108178165#testpushdemo"];
    options.apnsCertName = @"Develop";
    [[EMClient sharedClient] initializeSDKWithOptions:options];

    //登录环信 这里使用的是我刚才在环信后台创建的账户名和密码,使用这个账户登录,到时候如果在后台给客户端发消息的话,就可以找到该用户
    [[EMClient sharedClient] loginWithUsername:@"13051698888"
                                      password:@"222222"
                                    completion:^(NSString *aUsername, EMError *aError) {
                                        if (!aError) {
                                            NSLog(@"环信登陆成功");
                                            EMPushOptions *emoptions = [[EMClient sharedClient] pushOptions];
                                            //设置有消息过来时的显示方式:1.显示收到一条消息 2.显示具体消息内容.
                                            //自己可以测试下
                                            emoptions.displayStyle = EMPushDisplayStyleSimpleBanner;
                                            [[EMClient sharedClient] updatePushOptionsToServer];
                                        } else {
                                            NSLog(@"环信登陆失败");
                                        }
                                    }];
    
    
    /**
     注册APNS离线推送  iOS8 注册APNS
     */
    if ([application respondsToSelector:@selector(registerForRemoteNotifications)]) {
        [application registerForRemoteNotifications];
        UIUserNotificationType notificationTypes = UIUserNotificationTypeBadge |
        UIUserNotificationTypeSound |
        UIUserNotificationTypeAlert;
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:notificationTypes categories:nil];
        [application registerUserNotificationSettings:settings];
    }
    else{
        UIRemoteNotificationType notificationTypes = UIRemoteNotificationTypeBadge |
        UIRemoteNotificationTypeSound |
        UIRemoteNotificationTypeAlert;
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:notificationTypes];
    }
    
    //添加监听在线推送消息
   [[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];    
    return YES;
}

//监听环信在线推送消息
- (void)messagesDidReceive:(NSArray *)aMessages{
    
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"收到环信通知" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
        [alertView show];
        
        //aMessages是一个对象,包含了发过来的所有信息,怎么提取想要的信息我会在后面贴出来.
}

// 将得到的deviceToken传给SDK
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
    [[EMClient sharedClient] bindDeviceToken:deviceToken];
}

// 注册deviceToken失败
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
    NSLog(@"error -- %@",error);
}

// APP进入后台
- (void)applicationDidEnterBackground:(UIApplication *)application
{
    [[EMClient sharedClient] applicationDidEnterBackground:application];
}

// APP将要从后台返回
- (void)applicationWillEnterForeground:(UIApplication *)application
{
    [[EMClient sharedClient] applicationWillEnterForeground:application];
}
```
上面的几个方法在appdelegate里是必须重写的,不然会直接导致推送不成功.其中.需要重点说明的是:

- 只有在应用完全退出被杀掉的状态下,才可以收到环信推送的通知;
- 如果要发送在线的通知,需要在messagesDidReceive方法里获取到环信推送的消息之后给用户发起一个本地通知,这个大家可以自己研究下.
- 通过设置emoptions.displayStyle = EMPushDisplayStyleSimpleBanner;(上面代码有)可以设置有通知过来的时候的显示方式,显示一个提示或者显示完整的消息.
- 上传证书下面填写的应用包名,指的是你的BundleID !!!!我在这里踩了坑,切记!!.

测试推送:
1. 在应用完全退出的情况下(使用在环信注册的账户登录一次,确认登录成功之后再完全退出),选中我们的用户,点击发送消息:

1232108-8e6a60d144269c67.png



点击发送:

1232108-17f029870d36abef.png



测试结果:

1232108-aa2b808cf5cd1c6d.png




2.程序在线的时候测试推送,还是发送"你好啊",然后我们在messagesDidReceive拦截环信的EMMessage对象,针对EMMessage对象的解析方式如下,完整的抽取环信推送消息的方法:
```
- (void)messagesDidReceive:(NSArray *)aMessages{
    
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"收到环信通知" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
        [alertView show];
    
        for (EMMessage *message in aMessages) {
            EMMessageBody *msgBody = message.body;
            switch (msgBody.type) {
                case EMMessageBodyTypeText:
                {
                    // 收到的文字消息
                    EMTextMessageBody *textBody = (EMTextMessageBody *)msgBody;
                    NSString *txt = textBody.text;
                    NSLog(@"收到的文字是 txt -- %@",txt);
                }
                    break;
                case EMMessageBodyTypeImage:
                {
                    // 得到一个图片消息body
                    EMImageMessageBody *body = ((EMImageMessageBody *)msgBody);
                    NSLog(@"大图remote路径 -- %@"   ,body.remotePath);
                    NSLog(@"大图local路径 -- %@"    ,body.localPath); // // 需要使用sdk提供的下载方法后才会存在
                    NSLog(@"大图的secret -- %@"    ,body.secretKey);
                    NSLog(@"大图的W -- %f ,大图的H -- %f",body.size.width,body.size.height);
                    NSLog(@"大图的下载状态 -- %u",body.downloadStatus);
    
    
                    // 缩略图sdk会自动下载
                    NSLog(@"小图remote路径 -- %@"   ,body.thumbnailRemotePath);
                    NSLog(@"小图local路径 -- %@"    ,body.thumbnailLocalPath);
                    NSLog(@"小图的secret -- %@"    ,body.thumbnailSecretKey);
                    NSLog(@"小图的W -- %f ,大图的H -- %f",body.thumbnailSize.width,body.thumbnailSize.height);
                    NSLog(@"小图的下载状态 -- %u",body.thumbnailDownloadStatus);
                }
                    break;
                case EMMessageBodyTypeLocation:
                {
                    EMLocationMessageBody *body = (EMLocationMessageBody *)msgBody;
                    NSLog(@"纬度-- %f",body.latitude);
                    NSLog(@"经度-- %f",body.longitude);
                    NSLog(@"地址-- %@",body.address);
                }
                    break;
                case EMMessageBodyTypeVoice:
                {
                    // 音频sdk会自动下载
                    EMVoiceMessageBody *body = (EMVoiceMessageBody *)msgBody;
                    NSLog(@"音频remote路径 -- %@"      ,body.remotePath);
                    NSLog(@"音频local路径 -- %@"       ,body.localPath); // 需要使用sdk提供的下载方法后才会存在(音频会自动调用)
                    NSLog(@"音频的secret -- %@"        ,body.secretKey);
                    NSLog(@"音频文件大小 -- %lld"       ,body.fileLength);
                    NSLog(@"音频文件的下载状态 -- %u"   ,body.downloadStatus);
                    NSLog(@"音频的时间长度 -- %u"      ,body.duration);
                }
                    break;
                case EMMessageBodyTypeVideo:
                {
                    EMVideoMessageBody *body = (EMVideoMessageBody *)msgBody;
    
                    NSLog(@"视频remote路径 -- %@"      ,body.remotePath);
                    NSLog(@"视频local路径 -- %@"       ,body.localPath); // 需要使用sdk提供的下载方法后才会存在
                    NSLog(@"视频的secret -- %@"        ,body.secretKey);
                    NSLog(@"视频文件大小 -- %lld"       ,body.fileLength);
                    NSLog(@"视频文件的下载状态 -- %u"   ,body.downloadStatus);
                    NSLog(@"视频的时间长度 -- %u"      ,body.duration);
                    NSLog(@"视频的W -- %f ,视频的H -- %f", body.thumbnailSize.width, body.thumbnailSize.height);
    
                    // 缩略图sdk会自动下载
                    NSLog(@"缩略图的remote路径 -- %@"     ,body.thumbnailRemotePath);
                    NSLog(@"缩略图的local路径 -- %@"      ,body.thumbnailLocalPath);
                    NSLog(@"缩略图的secret -- %@"        ,body.thumbnailSecretKey);
                    NSLog(@"缩略图的下载状态 -- %u"      ,body.thumbnailDownloadStatus);
                }
                    break;
                case EMMessageBodyTypeFile:
                {
                    EMFileMessageBody *body = (EMFileMessageBody *)msgBody;
                    NSLog(@"文件remote路径 -- %@"      ,body.remotePath);
                    NSLog(@"文件local路径 -- %@"       ,body.localPath); // 需要使用sdk提供的下载方法后才会存在
                    NSLog(@"文件的secret -- %@"        ,body.secretKey);
                    NSLog(@"文件文件大小 -- %lld"       ,body.fileLength);
                    NSLog(@"文件文件的下载状态 -- %u"   ,body.downloadStatus);
                }
                    break;
                    
                default:
                    break;
            }
        }
}
```

发送成功之后打印结果如下:
```
2016-12-01 16:03:26.060088 PushDemo[1392:450230] 收到的文字是 txt -- 你好啊
```
三.结语

至此,我们就成功集成了环信推送到我们的项目中.另外提供一些在做推送的时候经常会用到的小方法
- 设置应用图标右上角数字角标.
```
UIApplication *application = [UIApplication sharedApplication]; [application setApplicationIconBadgeNumber:3];
```
补充一个环信坑:
编译通过后,运行的时候爆炸,提示:dyld: Library not loaded: @rpath/Hyphenate.framework/Hyphenate
需要设置Hyphenate.frameword的Embedded Binariew属性


1232108-0167fe66d3cd3151.png



- 如果推送证书那里没看特别明白的话,提供一个创建推送证书的链接:http://www.jianshu.com/p/78282e16db66


- 设置推送过来时候的_apns_昵称:
```
[[EMClient sharedClient] setApnsNickname:@"推送昵称"];
```

一直在抽时间写这篇博客,平常比较忙没有大块的时间来写和记录这些东西,不过东拼西凑,没事写一点最终还是写完了.希望看到这里的小伙伴都可以成功集成环信推送,有问题可以在下面留言,我看到了肯定会回复的.希望围观的小伙伴可以不吝指点这篇博客中出现的错误,不管是文字错误还是逻辑错误等等,我一定会尽快修正,不给后人留坑.....

给出项目gitHub地址:
https://github.com/TheRuningAnt/PushDemo.git  喜欢的话,记得给小星星哈

排版可能有点问题,原博客地址:http://blog.csdn.net/mumubumao ... 23393
 
继续阅读 »
这几天项目里又用到了环信的推送,虽然之前做过,但是很久不做还是有很多细节没有注意到,所以还是决定从头开始做一遍,把每一个环节都详细记录下来,同样的把每一个坑也记录下来.方便自己以后做的时候忘记哪个流程了可以在看一遍.我很能理解那种遇到问题网上百度一堆类似答案但是并不好使的情况,所以我会将我在项目中遇到的问题都贴出来,希望能给大家带来些许参考和帮助,

一.推送的原理和流程(着急做推送的可以跳过这一步)
首先给大家推荐一个介绍推送机制很优秀的帖子:http://www.jianshu.com/p/e347f999ed95 ,里面关于本地推送和远程推送的介绍都很详细,至少我看了感觉还是收获很多的.尤其是里面有几张图片不知道是博主在哪里找的,但是真的是一看就透,太赞了,所以我果断盗过来了0.0. 这里我对推送的流程做了一个简单的叙述,力求用最简单的语言能说明整个推送的机制.

先搬过来一张图再说

692194-fc99211b942ffb8c.png


再搬一张:

692194-a1764a5b6ef76592.png



当我们的苹果手机联网的时候,会自动与苹果的服务器建立长连接,长连接的好处有很多,比如系统升级、时间校准、数据传输和响应比较快以及数据可以保持最新状态等功能.上面这两张图片简单的讲述了推送的流程:

- 1.首先我们需要将自己设备的UDID和应用的Bundle Identifier发送到苹果的服务器,然后苹果的服务器会返回给我们一个DeviceToken,这个在我看来就是创建推送证书和描述文件的过程.
- 2.我们将包含手机和应用标示的打包文件上传到做推送的服务器上去,当我们从推送服务器的后台发起推送消息的时候,推送服务器会将我们的DeviceToken和需要发送的消息Message发送到苹果的APNS(Apple push Notification Service)服务器.
- 3.当苹果的服务器收到DeviceToken和需要发送的消息Message时,会根据DeviceToken中的UDID查找设备,根据DeviceToken中的Bundle Identfier查找该应用,并将Message发送到该设备上.

下面是以QQ服务器为栗子说明的即时通讯的机制:

692194-42cd5b5723039e84.png


图片已经说得够详细明了了,我就不插嘴了,下面开始我们的工程.

二.具体流程

我们创建一个名为TestDemo的工程,我是使用Xcode8.1来开发的,工程名为PushDemo,创建好的工程界面如下(Xcode8)

1232108-fecb3186b8c4700d.png


从Xcode8之后,Xcode提供了自动管理证书的功能,这个用起来很方便,我目前在工程中用到的最多的地方就是创建好一个Demo之后,如果想真机运行的话,那么只需要在Team选择框里选择我的开发账户,接下来下面会出现一个加载提示圈,等它加载完了就可以在真机上运行了,这个过程实际上是Xcode使用你当前的BundleId去该账户的开发这中心创建了对应的AppId和描述文件,但是我们既然是作为一个开发流程的记录,就自己来创建这些东西,所以,我们取消选择Automatically manage signing选项.此时界面如下:

1232108-6da09aaa4693b3b3.png



好了,我们要正式开始我们的工作了GO GO GO!
1. 首先我们先去官网创建AppID和描述文件.      

我们是要集成推送的,所以我们需要用到cer文件,这个东西实际上就是苹果给开发者颁发的一个证书,我们需要将它导入到我们的AppId配置里,否则的话是无法集成推送的,还记得安装应该的时候会提示"无法安装为认证发布者的应用"之类的信息么,我猜测这个cer文件就是我们身份的标示,使我们开发的应用可以供人们正常安装使用,关于证书有一篇很详细的帖子,希望了解证书之类信息的看官可以去瞅瞅:http://m.blog.csdn.net/article/details?id=8617788

创建cer文件的流程很简单,打开"钥匙串访问"(虽然很好找,但是还是把图贴出来吧,怕小朋友迷路)

1232108-ab1cf50531874785.png



1232108-6438c3fb50b4aaa5.png



打开钥匙串之后点击"从证书颁发机构请求证书"


1232108-d4a8951b51e6cceb.png


邮箱和常用名随便填写,记住下面的选择框选择"存储到磁盘"

1232108-bda705277e11698e.png



点击存储

1232108-07e46d1757718ea4.png



已经在桌面保存了


1232108-43a584c54d8f6cf2.png



到此,我们已经创建好了cer文件,接着我们去开发者中心创建AppId和描述文件

2. 创建AppId和描述文件

首先进入开发者中心,百度搜索Apple Developer,(哎 真的是详细到家了啊,我都人不下去了)
上图

1232108-cedf60744b970a2e.png



输入开发者账户,登录进去


1232108-2b564af543f98b20.png


你将看到这个页面

1232108-a8daff6248a1238a.png



点击看到:

1232108-e9a6e57aa9930544.png


输入AppId文件名和BundleId

1232108-ae96fe218d56e753.png


选中下面的PushNotifications

1232108-38bf6bb6a67f51d2.png


点击Continue:

1232108-934cf686ea792fe8.png


点击register:

1232108-083327989bcbe786.png


点击Done回到AppId列表页面

1232108-0538ef84dea33c70.png


在AppId列表页面可以看到我们的AppID了

1232108-95b229c6dbadcdac.png



但是,还没有完成,因为我们是要做推送的,所以需要上传我们的cer文件
,点击我们的AppId,在展开的详情里可以看到:

1232108-15f6e6cba67bcf32.png




Push Notification的两个指示灯还是黄色的状态,我们要将它启用,点击Edit,在点开的页面里滑动至底部,记得要选中Push Notification按钮,接着点击上方的开发证书下的创建证书按钮:

1232108-6e60ef33f39c3c3e.png



点击Continue

1232108-20ba8ef5aac404fe.png



点击 choose file:

1232108-a8b6d1f97c9f57a7.png



将我们从开发机构请求的证书传上去,之后点击Register:

1232108-be277d8092ca589a.png



点击Register之后的页面,点击download,将其下载到桌面上,download之后记得点击done完成文件创建:

1232108-70ad59ee048b37de.png



桌面上的文件:

1232108-ea6f4078346a5a1c.png



现在我们就完成了给AppID创建开发者证书,然后我们要给它创建发布者证书,点击Done之后回到AppIds列表,如果找不到的话,点击右边的App IDs

1232108-f3563cf07940ad50.png



点开项目的AppId,此时界面如下,点击最下面的CreateCertificate,开始给AppID创建发布者证书,给AppId创建发布者证书流程跟创建开发者证书是一样的!给AppId创建发布者证书流程跟创建开发者证书是一样的!给AppId创建发布者证书流程跟创建开发者证书是一样的!重要的事情说三遍!!因为我不贴出来创建发布证书的图了,所以各位根据创建开发证书的流程再走一遍就好,同样也要将发布者证书下载到本地.:

1232108-5d146f8fcbf96aa2.png



1232108-f4959adf27635124.png



当创建好之后在回到这个页面时,应该显示如下所示:

1232108-d9e0b2bf3794fad2.png



此时本地我们下载的文件如下:

1232108-651e46a585df0fd2.png



然后将这两个证书拖到钥匙串里,步骤如下:
首先打开钥匙串:

1232108-2ed433418c0ceaf9.png



1232108-4907f4f3f01371e6.png


然后先点击:系统-证书,然后将两个文件拖进去,会提示你输入开机密码,输入就好了(建议添加之前先对这个界面截屏,添加完之后可以对比刚刚添加了那些文件)

1232108-9e9434ee2246e3ce.png



添加完之后是这个样子,画框的是我们的证书

1232108-c71476ca00c853ec.png



然后选择左边的"登录"选项,可以看到我们刚才创建的证书

1232108-b7e1a0917e1bdc6a.png


选中第一个证书,然后右键(你懂得右键的意思),选择导出...

1232108-b020b7d0a48f795d.png



选择导出为P12文件,存储在桌面上,获取到P12文件.对这两个证书进行同样的操作.(记得标题有(Develop)的起名为Product文件,第二个证书导出的时候起名为Develop,名字可以自己定,只是为了区别)

1232108-04d80a4621bc1708.png


然后会提示你输入密码,这里我设置的密码是zx123456,自己设定好一定要记住,一会儿要用.

1232108-409c20593f4f262e.png


然后可以在桌面上看到我们导出的P12文件啦

1232108-964de37f66433eaa.png



现在我们就完成了所有的证书的创建,可以去环信上创建我们的应用啦.

3.创建真机调试文件以及导入到项目中

因为必须要进行真机测试,而且我们关闭了自动管理证书,就导致Xcode8不会自动帮我们生成证书,所以我们要自己创建真机调试证书并导入到项目中去,流程如下:

创建描述文件:

1232108-9dbec2cea23ab8e1.png



选择开发模式,下一步:

1232108-edece2d8c17d8f27.png



选择对应的AppID,选择我们刚才创建的AppId:

1232108-ee9029c89f0c34d2.png



选择开发团队,我一般都是全选的,下一步:

1232108-3744e08d9d10aa55.png



选择真机调试的机器,全选,下一步:

1232108-124184468c7c6531.png



下一步:

1232108-c6c0e50e57add4be.png



将创建好的描述文件下载下来,放到桌面上:

1232108-8a2c9400633c796d.png



创建好的描述文件:

1232108-40bebec424947b9d.png



首先选择debug模式下载的真机调试描述文件:

1232108-a1d8a4c3a0bb0a23.png


选择桌面上刚刚下载的描述文件:

1232108-692279ac01c7d137.png



使用同样的步骤,选择Release模式下的真机调试文件,一模一样的操作,不贴图了.两个文件都导入进去之后,插上真机,就可以进行真机调试了.

4.在环信创建我们的应用

首先百度搜索环信,打开他们的官网,先注册账户,注册过的可以跳过了,上图:
注册的时候选择"注册即时通讯云"

1232108-672cbab760c523f9.png



注册的时候需要填写各种信息,按照格式填写就好了,填写完之后登陆,点击创建应用

1232108-bd67f4f4f35cd764.png



填写应用信息

1232108-4d748bd8c621d0ff.png



填写完如下图咯

1232108-bbdc1fbea11501aa.png



然后需要上传我们的P12文件,图片很清晰- -,不多说,第一次我选择上传的是生产证书:

1232108-6b5a19a243a78839.png



第二次上传开发证书:

1232108-538c02769688cac0.png



至此,我们的证书开发也都上传完了,路漫漫其修远兮,开始集成环信到代码里吧

5.集成环信到项目中

首先在这里下载最新的SDK(截至到写本文时最新的SDK为)

http://www.easemob.com/download/im 环信推送SDK下载链接

点击iOS的最新SDK下载,这里下载的是V3.x的SDK

1232108-279c3c47c46ec724.png



下载到桌面是这个鬼样子

1232108-9d5b7d0ee1c2d404.png



我们只需要将画圈的两个文件夹导进去工程里就好了,其他的用不上

1232108-e8d9522b4f496454.png



导进去之后文件列表是这样,编译会出错别急,慢慢改.

1232108-da727a18407e70d1.png



向项目里添加需要的库

1232108-e0ac523eac1d6042.png



上面的图片是截取的环信官方文档,我添加完是这个样子的:

1232108-5409054190742754.png


方便复制库名的文字:
CoreMedia.framework
AudioToolbox.framework
AVFoundation.framework
MobileCoreServices.framework
ImageIO.framework
libc++.dylib
libz.dylib
libstdc++.6.0.9.dylib
libsqlite3.dylib
(如果使用的是 xcode7,后缀为 tbd。)
这一步很重要,因为SDK 不支持 bitcode,所以要将 Build Settings → Linking → Enable Bitcode 中设置 NO。


1232108-96cd9023e11f17bd.png



command+B编译工程,大量爆红.别着急,修改我们的PCH文件就好了
在PCH文件添加
```
#ifdef __OBJC__
    #import <UIKit/UIKit.h>
#endif
```

将我们所有定义和添加的头文件和宏定义,都放在#ifdef __OBJC__和#endif中间
就可以解决这个问题.

然后在项目里打开推送:

1232108-96cd9023e11f17bd.png



6.测试是否集成成功

首先,我们去环信的后台给我们的应用添加一个用户

1232108-8abe301c76c6c7f4.png



用户名我设置成了:13051698888  密码设置成了:222222

1232108-94c1ef7dbdf3014c.png



接着我们要去appledate.m文件里添加东西了,很重要一步,废话不多说,直接贴出来需要配置的代码,直接拿去用0.0,需要添加的东西我在注释里注释的很明白...
记得要导进去头文件
#import "EMSDK.h"

```
@interface AppDelegate ()<EMChatManagerDelegate>

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //AppKey:注册的AppKey,点击"应用概述"可以看到AppKey,粘贴过来就可以。
    //apnsCertName:推送证书名,填写你的开发证书或者发布证书名,就是上传到环信后台的两个中的一个,什么环境下测试使用什么环境的证书。
    EMOptions *options = [EMOptions optionsWithAppkey:@"1192161108178165#testpushdemo"];
    options.apnsCertName = @"Develop";
    [[EMClient sharedClient] initializeSDKWithOptions:options];

    //登录环信 这里使用的是我刚才在环信后台创建的账户名和密码,使用这个账户登录,到时候如果在后台给客户端发消息的话,就可以找到该用户
    [[EMClient sharedClient] loginWithUsername:@"13051698888"
                                      password:@"222222"
                                    completion:^(NSString *aUsername, EMError *aError) {
                                        if (!aError) {
                                            NSLog(@"环信登陆成功");
                                            EMPushOptions *emoptions = [[EMClient sharedClient] pushOptions];
                                            //设置有消息过来时的显示方式:1.显示收到一条消息 2.显示具体消息内容.
                                            //自己可以测试下
                                            emoptions.displayStyle = EMPushDisplayStyleSimpleBanner;
                                            [[EMClient sharedClient] updatePushOptionsToServer];
                                        } else {
                                            NSLog(@"环信登陆失败");
                                        }
                                    }];
    
    
    /**
     注册APNS离线推送  iOS8 注册APNS
     */
    if ([application respondsToSelector:@selector(registerForRemoteNotifications)]) {
        [application registerForRemoteNotifications];
        UIUserNotificationType notificationTypes = UIUserNotificationTypeBadge |
        UIUserNotificationTypeSound |
        UIUserNotificationTypeAlert;
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:notificationTypes categories:nil];
        [application registerUserNotificationSettings:settings];
    }
    else{
        UIRemoteNotificationType notificationTypes = UIRemoteNotificationTypeBadge |
        UIRemoteNotificationTypeSound |
        UIRemoteNotificationTypeAlert;
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:notificationTypes];
    }
    
    //添加监听在线推送消息
   [[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];    
    return YES;
}

//监听环信在线推送消息
- (void)messagesDidReceive:(NSArray *)aMessages{
    
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"收到环信通知" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
        [alertView show];
        
        //aMessages是一个对象,包含了发过来的所有信息,怎么提取想要的信息我会在后面贴出来.
}

// 将得到的deviceToken传给SDK
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken{
    [[EMClient sharedClient] bindDeviceToken:deviceToken];
}

// 注册deviceToken失败
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error{
    NSLog(@"error -- %@",error);
}

// APP进入后台
- (void)applicationDidEnterBackground:(UIApplication *)application
{
    [[EMClient sharedClient] applicationDidEnterBackground:application];
}

// APP将要从后台返回
- (void)applicationWillEnterForeground:(UIApplication *)application
{
    [[EMClient sharedClient] applicationWillEnterForeground:application];
}
```
上面的几个方法在appdelegate里是必须重写的,不然会直接导致推送不成功.其中.需要重点说明的是:

- 只有在应用完全退出被杀掉的状态下,才可以收到环信推送的通知;
- 如果要发送在线的通知,需要在messagesDidReceive方法里获取到环信推送的消息之后给用户发起一个本地通知,这个大家可以自己研究下.
- 通过设置emoptions.displayStyle = EMPushDisplayStyleSimpleBanner;(上面代码有)可以设置有通知过来的时候的显示方式,显示一个提示或者显示完整的消息.
- 上传证书下面填写的应用包名,指的是你的BundleID !!!!我在这里踩了坑,切记!!.

测试推送:
1. 在应用完全退出的情况下(使用在环信注册的账户登录一次,确认登录成功之后再完全退出),选中我们的用户,点击发送消息:

1232108-8e6a60d144269c67.png



点击发送:

1232108-17f029870d36abef.png



测试结果:

1232108-aa2b808cf5cd1c6d.png




2.程序在线的时候测试推送,还是发送"你好啊",然后我们在messagesDidReceive拦截环信的EMMessage对象,针对EMMessage对象的解析方式如下,完整的抽取环信推送消息的方法:
```
- (void)messagesDidReceive:(NSArray *)aMessages{
    
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"提示" message:@"收到环信通知" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
        [alertView show];
    
        for (EMMessage *message in aMessages) {
            EMMessageBody *msgBody = message.body;
            switch (msgBody.type) {
                case EMMessageBodyTypeText:
                {
                    // 收到的文字消息
                    EMTextMessageBody *textBody = (EMTextMessageBody *)msgBody;
                    NSString *txt = textBody.text;
                    NSLog(@"收到的文字是 txt -- %@",txt);
                }
                    break;
                case EMMessageBodyTypeImage:
                {
                    // 得到一个图片消息body
                    EMImageMessageBody *body = ((EMImageMessageBody *)msgBody);
                    NSLog(@"大图remote路径 -- %@"   ,body.remotePath);
                    NSLog(@"大图local路径 -- %@"    ,body.localPath); // // 需要使用sdk提供的下载方法后才会存在
                    NSLog(@"大图的secret -- %@"    ,body.secretKey);
                    NSLog(@"大图的W -- %f ,大图的H -- %f",body.size.width,body.size.height);
                    NSLog(@"大图的下载状态 -- %u",body.downloadStatus);
    
    
                    // 缩略图sdk会自动下载
                    NSLog(@"小图remote路径 -- %@"   ,body.thumbnailRemotePath);
                    NSLog(@"小图local路径 -- %@"    ,body.thumbnailLocalPath);
                    NSLog(@"小图的secret -- %@"    ,body.thumbnailSecretKey);
                    NSLog(@"小图的W -- %f ,大图的H -- %f",body.thumbnailSize.width,body.thumbnailSize.height);
                    NSLog(@"小图的下载状态 -- %u",body.thumbnailDownloadStatus);
                }
                    break;
                case EMMessageBodyTypeLocation:
                {
                    EMLocationMessageBody *body = (EMLocationMessageBody *)msgBody;
                    NSLog(@"纬度-- %f",body.latitude);
                    NSLog(@"经度-- %f",body.longitude);
                    NSLog(@"地址-- %@",body.address);
                }
                    break;
                case EMMessageBodyTypeVoice:
                {
                    // 音频sdk会自动下载
                    EMVoiceMessageBody *body = (EMVoiceMessageBody *)msgBody;
                    NSLog(@"音频remote路径 -- %@"      ,body.remotePath);
                    NSLog(@"音频local路径 -- %@"       ,body.localPath); // 需要使用sdk提供的下载方法后才会存在(音频会自动调用)
                    NSLog(@"音频的secret -- %@"        ,body.secretKey);
                    NSLog(@"音频文件大小 -- %lld"       ,body.fileLength);
                    NSLog(@"音频文件的下载状态 -- %u"   ,body.downloadStatus);
                    NSLog(@"音频的时间长度 -- %u"      ,body.duration);
                }
                    break;
                case EMMessageBodyTypeVideo:
                {
                    EMVideoMessageBody *body = (EMVideoMessageBody *)msgBody;
    
                    NSLog(@"视频remote路径 -- %@"      ,body.remotePath);
                    NSLog(@"视频local路径 -- %@"       ,body.localPath); // 需要使用sdk提供的下载方法后才会存在
                    NSLog(@"视频的secret -- %@"        ,body.secretKey);
                    NSLog(@"视频文件大小 -- %lld"       ,body.fileLength);
                    NSLog(@"视频文件的下载状态 -- %u"   ,body.downloadStatus);
                    NSLog(@"视频的时间长度 -- %u"      ,body.duration);
                    NSLog(@"视频的W -- %f ,视频的H -- %f", body.thumbnailSize.width, body.thumbnailSize.height);
    
                    // 缩略图sdk会自动下载
                    NSLog(@"缩略图的remote路径 -- %@"     ,body.thumbnailRemotePath);
                    NSLog(@"缩略图的local路径 -- %@"      ,body.thumbnailLocalPath);
                    NSLog(@"缩略图的secret -- %@"        ,body.thumbnailSecretKey);
                    NSLog(@"缩略图的下载状态 -- %u"      ,body.thumbnailDownloadStatus);
                }
                    break;
                case EMMessageBodyTypeFile:
                {
                    EMFileMessageBody *body = (EMFileMessageBody *)msgBody;
                    NSLog(@"文件remote路径 -- %@"      ,body.remotePath);
                    NSLog(@"文件local路径 -- %@"       ,body.localPath); // 需要使用sdk提供的下载方法后才会存在
                    NSLog(@"文件的secret -- %@"        ,body.secretKey);
                    NSLog(@"文件文件大小 -- %lld"       ,body.fileLength);
                    NSLog(@"文件文件的下载状态 -- %u"   ,body.downloadStatus);
                }
                    break;
                    
                default:
                    break;
            }
        }
}
```

发送成功之后打印结果如下:
```
2016-12-01 16:03:26.060088 PushDemo[1392:450230] 收到的文字是 txt -- 你好啊
```
三.结语

至此,我们就成功集成了环信推送到我们的项目中.另外提供一些在做推送的时候经常会用到的小方法
- 设置应用图标右上角数字角标.
```
UIApplication *application = [UIApplication sharedApplication]; [application setApplicationIconBadgeNumber:3];
```
补充一个环信坑:
编译通过后,运行的时候爆炸,提示:dyld: Library not loaded: @rpath/Hyphenate.framework/Hyphenate
需要设置Hyphenate.frameword的Embedded Binariew属性


1232108-0167fe66d3cd3151.png



- 如果推送证书那里没看特别明白的话,提供一个创建推送证书的链接:http://www.jianshu.com/p/78282e16db66


- 设置推送过来时候的_apns_昵称:
```
[[EMClient sharedClient] setApnsNickname:@"推送昵称"];
```

一直在抽时间写这篇博客,平常比较忙没有大块的时间来写和记录这些东西,不过东拼西凑,没事写一点最终还是写完了.希望看到这里的小伙伴都可以成功集成环信推送,有问题可以在下面留言,我看到了肯定会回复的.希望围观的小伙伴可以不吝指点这篇博客中出现的错误,不管是文字错误还是逻辑错误等等,我一定会尽快修正,不给后人留坑.....

给出项目gitHub地址:
https://github.com/TheRuningAnt/PushDemo.git  喜欢的话,记得给小星星哈

排版可能有点问题,原博客地址:http://blog.csdn.net/mumubumao ... 23393
  收起阅读 »

环信即时通讯云V3.3.8已发布,新增服务诊断接口,方便自定位接口问题

Android SDK V3.3.8 
1.添加服务诊断接口

2. 添加设置音频码率接口

3. 优化重连逻辑,减少重连次数

4. 添加社区版SDK注册用户,创建群组\聊天室达到数量限制的提示

ios SDK V3.3.8 
新功能: 

• 服务诊断接口, demo UI体现在“setting-debug-服务器诊断”


• 设置音频码率, 接口[EMCallOptions maxAudioKbps]


• 添加新的错误码(达到服务器上限),体现在创建用户,创建群组,创建聊天室


功能更新:

[EMClient isLoggedIn]语义有所改变,原意是是否已经完成登录操作,现在的意思是是否成功登录过

服务端诊断接口介绍:
服务诊断功能是为了在用户使用SDK出现登录失败等问题时用于辅助定位哪个接口服务出现问题.

服务诊断流程:
1.未登录账号诊断:
1.输入用户名和密码
2.验证用户名密码的合法性
3.诊断获取DNS列表接口
4.诊断获取Token接口
5.用户登录
7.用户登出
2.已登录账号诊断:
1.获取当前登录账户的账号和密码(无需用户输入)
2.诊断获取DNS列表接口
3.诊断获取Token接口
4.用户登录
说明: 已登录账号诊断无登出操作,以免影响已登录账户的正常使用.

使用说明:
1.Android:
1.登录界面: 右下方 "SDK接口诊断" link.(该link会被软键盘遮挡)
1.用户已登录: "设置-SDK接口诊断"
2.iOS:
“setting-debug-服务器诊断”




更新日志:Android更新 ios更新
SDK下载:下载地址
继续阅读 »
Android SDK V3.3.8 
1.添加服务诊断接口

2. 添加设置音频码率接口

3. 优化重连逻辑,减少重连次数

4. 添加社区版SDK注册用户,创建群组\聊天室达到数量限制的提示

ios SDK V3.3.8 
新功能: 

• 服务诊断接口, demo UI体现在“setting-debug-服务器诊断”


• 设置音频码率, 接口[EMCallOptions maxAudioKbps]


• 添加新的错误码(达到服务器上限),体现在创建用户,创建群组,创建聊天室


功能更新:

[EMClient isLoggedIn]语义有所改变,原意是是否已经完成登录操作,现在的意思是是否成功登录过

服务端诊断接口介绍:
服务诊断功能是为了在用户使用SDK出现登录失败等问题时用于辅助定位哪个接口服务出现问题.

服务诊断流程:
1.未登录账号诊断:
1.输入用户名和密码
2.验证用户名密码的合法性
3.诊断获取DNS列表接口
4.诊断获取Token接口
5.用户登录
7.用户登出
2.已登录账号诊断:
1.获取当前登录账户的账号和密码(无需用户输入)
2.诊断获取DNS列表接口
3.诊断获取Token接口
4.用户登录
说明: 已登录账号诊断无登出操作,以免影响已登录账户的正常使用.

使用说明:
1.Android:
1.登录界面: 右下方 "SDK接口诊断" link.(该link会被软键盘遮挡)
1.用户已登录: "设置-SDK接口诊断"
2.iOS:
“setting-debug-服务器诊断”




更新日志:Android更新 ios更新
SDK下载:下载地址 收起阅读 »

easeUI聊天界面中好友头像是如何传值的

easeUI聊天界面中好友头像是如何传值的
easeUI聊天界面中好友头像是如何传值的

php服务器端怎么获取到用户聊天记录。


public function chatRecord($ql = '', $cursor = '', $limit = 20) { $ql = ! empty ( $ql ) ? "ql=" . $ql : "order+by+timestamp+desc"; $cursor = ! empty ( $cursor ) ? "&cursor=" . $cursor : ''; $url = $this->url . "chatmessages?" . $ql . "&limit=" . $limit . $cursor; $access_token = $this->token (); $header [] = 'Authorization: Bearer ' . $access_token; $result = $this->curl ( $url, '', $header, $type = "GET " ); echo $result; }
在网上看别人是这样写的,但不知道$ql的值是什么格式
继续阅读 »

public function chatRecord($ql = '', $cursor = '', $limit = 20) { $ql = ! empty ( $ql ) ? "ql=" . $ql : "order+by+timestamp+desc"; $cursor = ! empty ( $cursor ) ? "&cursor=" . $cursor : ''; $url = $this->url . "chatmessages?" . $ql . "&limit=" . $limit . $cursor; $access_token = $this->token (); $header [] = 'Authorization: Bearer ' . $access_token; $result = $this->curl ( $url, '', $header, $type = "GET " ); echo $result; }
在网上看别人是这样写的,但不知道$ql的值是什么格式 收起阅读 »

环信客户互动云v5.32已发布,新增质检申诉功能

本次更新的主要内容为:
新增质检申诉功能,用于质检员完成会话质检后,客服可以向打分的质检员发起申诉,提交证据并要求复核质检结果。客服对质检结果发起申诉后,管理员和质检员可以查看客服的质检申诉详情,并对申诉进行处理。

客服模式

新增质检申诉功能


质检申诉功能用于质检员完成会话质检后,若客服认为质检结果不合理,可以向打分的质检员发起申诉,提交证据并要求复核质检结果。

客服模式新增质量检查模块,包含“质检记录”和“申诉记录”两个页面。在质检记录页面,客服可以查询会话质检结果并发起申诉;在申诉记录页面,客服可以查询申诉的进展状态,与质检员沟通会话相关情况。

查询质检记录

进入“质量检查 > 质检记录”页面,可以查看自己的会话质检结果。支持根据时间段、渠道、质检员、关联、会话标签等指标进行筛选,并支持导出筛选后的质检记录。

在质量检查页面的列表中,点击任意会话,可以查看该会话的详细质检评分和备注。 
001.png

发起质检申诉

在会话详情的“质检”页签,点击“质检申诉”按钮,并填写申诉主题和申诉理由,可以对会话的质检结果发起申诉。

质检申诉将由打分的质检员处理。 
002.png

查询申诉记录

进入“质量检查 > 申诉记录”页面,可以查看自己的申诉记录,包括未开启、处理中和已结束的申诉。

申诉状态:

未开启:客服发起会话的质检申诉后,默认为“未开启”状态。
处理中:质检员开始进行申诉处理后,申诉为“处理中”状态。
已结束:质检员与客服沟通完毕并结束申诉处理后,申诉为“已结束”状态。

在申诉记录列表中,点击任意申诉,可以查看质检员对该申诉的评论,申诉流程的记录,以及提交评论(包含文字和附件)。 
003.png

管理员模式

新增申诉管理功能


客服对质检结果发起申诉后,管理员和质检员可以查看客服的质检申诉详情,并对申诉进行处理。只有原打分的质检员能够修改申诉的会话的质检评分。

进入“管理员模式 > 质量检查 > 申诉管理”页面,查看所有未开启、处理中、已结束的质检申诉单。支持根据申诉单号搜索申诉单,以及支持根据时间段、申诉人筛选申诉单。

申诉状态:
  • 未开启:客服发起会话的质检申诉后,默认为“未开启”状态。
  • 处理中:质检员开始进行申诉处理后,申诉为“处理中”状态。
  • 已结束:质检员与客服沟通完毕并结束申诉处理后,申诉为“已结束”状态。
    004.png

在质检申诉列表中,点击任意申诉,可以查看该申诉的详情,包括创建人、会话ID、申诉主题、申诉理由、评论、申诉流程的记录等。

点击申诉详情右下角的“开始进行”按钮,开始处理该申诉。然后:

点击“会话详情”按钮,进入会话详情页修改质检评分(注:只有原打分的质检员能够修改申诉的会话的质检评分)。
在评论区,输入评论内容,对申诉进行评论。评论对发起申诉的客服可见。
005.png

完成申诉处理后,点击申诉详情右下角的“结束申诉”按钮,将申诉状态修改为“已结束”。

新增“访客完成满意度评价”事件

自定义事件推送功能,新增“访客完成满意度评价”事件。支持在访客完成对会话的满意度评价时,将满意度评价详情(包含满意度评价、会话、访客、客服信息)推送到接收事件的服务器,方便企业对客户满意度进行统计、留档。

推送“访客完成满意度评价”事件:
  1. 开通“自定义事件推送”功能。
  2. 进入“设置 > 自定义事件推送”页面,点击“创建事件推送”。
  3. 填写自定义事件名称、接收事件的服务器地址,勾选需要推送的事件(访客完成满意度评价),并保存。


关于“访客完成满意度评价”事件的消息内容和注释,请查看环信官网文档“自定义事件推送”章节。

注:自定义事件推送为标准版/旗舰版增值服务。如需开通,请提供租户ID并联系环信商务经理。 
 
Android客服工作台

当前版本:V3.7

新功能/优化:
  • 新增自定义表情功能(增值服务)
  • 优化告警功能部分提醒

 环信客户互动云更新文档地址
环信客户互动云登陆地址
继续阅读 »
本次更新的主要内容为:
新增质检申诉功能,用于质检员完成会话质检后,客服可以向打分的质检员发起申诉,提交证据并要求复核质检结果。客服对质检结果发起申诉后,管理员和质检员可以查看客服的质检申诉详情,并对申诉进行处理。

客服模式

新增质检申诉功能


质检申诉功能用于质检员完成会话质检后,若客服认为质检结果不合理,可以向打分的质检员发起申诉,提交证据并要求复核质检结果。

客服模式新增质量检查模块,包含“质检记录”和“申诉记录”两个页面。在质检记录页面,客服可以查询会话质检结果并发起申诉;在申诉记录页面,客服可以查询申诉的进展状态,与质检员沟通会话相关情况。

查询质检记录

进入“质量检查 > 质检记录”页面,可以查看自己的会话质检结果。支持根据时间段、渠道、质检员、关联、会话标签等指标进行筛选,并支持导出筛选后的质检记录。

在质量检查页面的列表中,点击任意会话,可以查看该会话的详细质检评分和备注。 
001.png

发起质检申诉

在会话详情的“质检”页签,点击“质检申诉”按钮,并填写申诉主题和申诉理由,可以对会话的质检结果发起申诉。

质检申诉将由打分的质检员处理。 
002.png

查询申诉记录

进入“质量检查 > 申诉记录”页面,可以查看自己的申诉记录,包括未开启、处理中和已结束的申诉。

申诉状态:

未开启:客服发起会话的质检申诉后,默认为“未开启”状态。
处理中:质检员开始进行申诉处理后,申诉为“处理中”状态。
已结束:质检员与客服沟通完毕并结束申诉处理后,申诉为“已结束”状态。

在申诉记录列表中,点击任意申诉,可以查看质检员对该申诉的评论,申诉流程的记录,以及提交评论(包含文字和附件)。 
003.png

管理员模式

新增申诉管理功能


客服对质检结果发起申诉后,管理员和质检员可以查看客服的质检申诉详情,并对申诉进行处理。只有原打分的质检员能够修改申诉的会话的质检评分。

进入“管理员模式 > 质量检查 > 申诉管理”页面,查看所有未开启、处理中、已结束的质检申诉单。支持根据申诉单号搜索申诉单,以及支持根据时间段、申诉人筛选申诉单。

申诉状态:
  • 未开启:客服发起会话的质检申诉后,默认为“未开启”状态。
  • 处理中:质检员开始进行申诉处理后,申诉为“处理中”状态。
  • 已结束:质检员与客服沟通完毕并结束申诉处理后,申诉为“已结束”状态。
    004.png

在质检申诉列表中,点击任意申诉,可以查看该申诉的详情,包括创建人、会话ID、申诉主题、申诉理由、评论、申诉流程的记录等。

点击申诉详情右下角的“开始进行”按钮,开始处理该申诉。然后:

点击“会话详情”按钮,进入会话详情页修改质检评分(注:只有原打分的质检员能够修改申诉的会话的质检评分)。
在评论区,输入评论内容,对申诉进行评论。评论对发起申诉的客服可见。
005.png

完成申诉处理后,点击申诉详情右下角的“结束申诉”按钮,将申诉状态修改为“已结束”。

新增“访客完成满意度评价”事件

自定义事件推送功能,新增“访客完成满意度评价”事件。支持在访客完成对会话的满意度评价时,将满意度评价详情(包含满意度评价、会话、访客、客服信息)推送到接收事件的服务器,方便企业对客户满意度进行统计、留档。

推送“访客完成满意度评价”事件:
  1. 开通“自定义事件推送”功能。
  2. 进入“设置 > 自定义事件推送”页面,点击“创建事件推送”。
  3. 填写自定义事件名称、接收事件的服务器地址,勾选需要推送的事件(访客完成满意度评价),并保存。


关于“访客完成满意度评价”事件的消息内容和注释,请查看环信官网文档“自定义事件推送”章节。

注:自定义事件推送为标准版/旗舰版增值服务。如需开通,请提供租户ID并联系环信商务经理。 
 
Android客服工作台

当前版本:V3.7

新功能/优化:
  • 新增自定义表情功能(增值服务)
  • 优化告警功能部分提醒

 环信客户互动云更新文档地址
环信客户互动云登陆地址 收起阅读 »

2017 本土开源大盘点!年度编程语言和开源项目 TOP 榜

摘要:年度最受国内开发者喜爱的编程语言?最受欢迎的开源项目?为你呈现最详细的国内开发者画像。

盘点.jpg

在即将过去的2017年,作为程序员的你过得怎么样呢?在这一年中你是否参与过开源项目的创建或运营?今天为大家带来最详细的本土开源现状报告,为你展现国内开发者喜爱的编程语言、最受欢迎的国内开源项目等丰富信息。

1. 国内开发者的地域分布


开发者.png


2. 国内开发者的性别分布
 


性别.png


3. 2017 年新增756 K 开源项目——Star 数增长排行
 


star.png


4. 2017 年新增756 K 开源项目——Fork 数增长排行


fork.png


5. 2017 年,更多人开始参与开源项目​


参与.png


6. 国内开源项目的语言占比是什么情况?​


预言.png


7. 国内开源项目的功能分类是什么情况?​


功能.png


8.国内开发者最喜爱的编程语言​


语言.png


9. 2017 年增速最快的语言


增长.png


本文数据由 码云 2017年度数据报告 提供,码云是开源中国旗下的云端协作开发平台,上线四年来用户突破200万,托管项目近300万,已成为经过大规模部署的成熟产品。码云的社区版的私有库完全免费,企业版(5人以下免费)则提供代码托管、项目管理、文档协作的一体化开发服务,竭诚为广大本土开发者服务。
继续阅读 »
摘要:年度最受国内开发者喜爱的编程语言?最受欢迎的开源项目?为你呈现最详细的国内开发者画像。

盘点.jpg

在即将过去的2017年,作为程序员的你过得怎么样呢?在这一年中你是否参与过开源项目的创建或运营?今天为大家带来最详细的本土开源现状报告,为你展现国内开发者喜爱的编程语言、最受欢迎的国内开源项目等丰富信息。

1. 国内开发者的地域分布


开发者.png


2. 国内开发者的性别分布
 


性别.png


3. 2017 年新增756 K 开源项目——Star 数增长排行
 


star.png


4. 2017 年新增756 K 开源项目——Fork 数增长排行


fork.png


5. 2017 年,更多人开始参与开源项目​


参与.png


6. 国内开源项目的语言占比是什么情况?​


预言.png


7. 国内开源项目的功能分类是什么情况?​


功能.png


8.国内开发者最喜爱的编程语言​


语言.png


9. 2017 年增速最快的语言


增长.png


本文数据由 码云 2017年度数据报告 提供,码云是开源中国旗下的云端协作开发平台,上线四年来用户突破200万,托管项目近300万,已成为经过大规模部署的成熟产品。码云的社区版的私有库完全免费,企业版(5人以下免费)则提供代码托管、项目管理、文档协作的一体化开发服务,竭诚为广大本土开发者服务。 收起阅读 »

webIM发送的文件,能接收到,但是收到的消息中没有文件大小

在webIM中发送附件消息,接收到的消息中文件大小为0
在webIM中发送附件消息,接收到的消息中文件大小为0

环信客户互动云v5.31已上线,新增随机质检功能,使质检结果更加公平、公正

本次更新的主要内容为:​优化智能机器人功能,支持为机器人知识规则设置应答策略,使机器人能够根据不同的渠道关联、时间计划发送不同的答案。新增随机质检功能,采取系统对质检样本随机抽样的方法管理质检流程,避免质检作弊,使质检结果更加公平、公正。


环信客户互动云v5.31_产品更新说明

发布日期:2017-12-25

客服模式


客服变更在线状态需要审批

新增“客服变更在线状态需要审批”功能。当管理员打开“客服变更状态需要审批”开关时,普通客服将在线状态从“空闲”切换为忙碌、离开、隐身状态需要管理员审批;当管理员关闭此开关时,普通客服可以随意切换在线状态。

管理员切换在线状态不受此开关影响。

客服变更在线状态:

开关打开时,客服将在线状态从“空闲”切换为忙碌、离开、隐身状态时,将收到弹窗提醒,需填写状态变更理由,并提交至管理员审批。

01.png


管理员审批状态变更:

管理员收到客服的状态变更请求后,将在消息中心收到系统消息提醒。可以进入“管理员模式 > 审批管理”页面,审批该请求。

审批通过后,系统自动完成客服的状态切换。同时,系统发送系统消息提醒客服,可在消息中心页面查看。

02.png



“客服状态变更需要审批”开关:

需要对客服的在线状态变更进行审批时,管理员可以进入“管理员模式 > 设置 > 系统开关”页面,打开“客服状态变更需要审批”开关。

03.png



待接入会话列表显示坐席名

待接入页面的会话列表增加一列:坐席名,用于显示会话指定的客服名称。

注:若会话未指定客服,则只显示技能组名称,不显示客服名称。

管理员模式

机器人知识规则

机器人知识规则新增分类管理、日志管理、和应答策略。日志管理支持管理员查看知识规则相关的日志。分类管理支持将知识规则添加至不同的分类,方便查询和管理知识规则。应答策略为知识规则中的答案的发送策略,支持设置根据不同的渠道关联、时间计划发送不同的答案。

分类管理

在机器人的知识规则页面,可以添加、编辑分类,并修改知识规则所在的分类。

查看分类:

在分类列表中选择任意分类,查看该分类中的知识规则。

管理分类:

在分类列表下方,点击“管理分类”按钮,添加、编辑分类。

修改分类:

选中一条或多条知识规则,在弹出窗口中点击“修改分类”按钮,修改选中的知识规则所属的分类。

04.png


日志管理

日志管理支持管理员查看知识规则相关的日志,可以按照时间范围查询,以及导出。

在知识规则页面,点击“添加规则”右侧的下拉按钮,点击“日志管理”按钮,查看日志。

应答策略

支持为知识规则中的答案单独设置发送策略,在添加、编辑知识规则时,均可以设置发送策略。策略包含策略名称、条件(渠道关联和时间计划)、执行(知识规则的答案),当满足策略中的条件时,发送对应的答案给客户。

当知识规则中有多个答案时,如果不设置发送策略,则默认随机发送其中一个答案。

编辑知识规则:

在知识规则页面,点击知识规则右侧的“编辑”按钮,可以编辑知识规则。包括添加/编辑问题、添加/编辑答案。编辑完成后,点击“确认”。

05.png



添加发送策略:

在添加、编辑知识规则页面,点击“添加策略”按钮。
填写策略名称,选择一个渠道关联(不选择时,策略不生效),选择一个时间计划(不选择时,默认为全部时间),选择知识规则的一条答案,并保存。

设置好发送策略后,当客户的消息匹配知识规则的问题,并满足渠道关联和时间计划这两个条件时,发送策略中设置的答案给客户。

05.png



随机质检

新增随机质检功能。采取系统对质检样本随机抽样的方法管理质检流程,避免质检作弊,使质检结果更加公平、公正。

随机质检功能为标准版/旗舰版增值服务,如需开通,请提供租户ID并联系环信商务经理。

查看质检任务

质检任务由管理员/质检员创建,质检任务包含系统基于筛选条件随机抽取的客户会话。

在随机质检页面,管理员可以查看所有质检任务;质检员可以查看所有/自己创建的质检任务。

07.png



设置质检权限

进入“管理员模式 > 设置 > 权限管理”页面,设置质检员查看质检任务的数据权限。
  • 租户:支持查看系统内全部质检任务
  • 客服:只能查看自己创建的质检任务



08.png



创建质检任务

管理员/质检员每次可以为自己创建一条质检任务。质检任务分为质检中、已完成两个状态。当有质检中的任务时,需要先完成该质检任务,才可以创建新的质检任务。

在随机质检页面,点击右上角“创建质检任务”按钮,设置相关质检条件,再次点击“创建质检任务”按钮。系统根据质检条件随机抽取对应数量的会话,并创建质检任务。
  • 任务名称:质检任务的名称。
  • 时间范围:必须为一个月内,如11月1日至11月30日。
  • 会话抽样范围:包含会话来源渠道、技能组、关联、会话标签、参与客服。
  • 会话质检条件:包含首次响应时长、会话时长、平均/单次响应时长、访客/坐席消息数、满意度评价。
  • 抽样数量:必须为1至300之间的数字。



09.png



完成质检任务

管理员/质检员可以随时对质检中的任务里的会话进行质检评分,完成所有会话的质检评分后,即可完成该质检任务。

在随机质检页面,点击自己创建的质检任务,可以查看任务详情以及会话列表。点击任意会话,可查看会话详情,并对会话进行质检评分。
10.png


“24小时排队趋势”显示排队的会话详情

在“统计查询 > 排队统计”页面,点击“24小时排队趋势”中的柱状图,可以查看对应的排队的会话详情。

注:从该版本开始,“排队统计”仅支持筛选最近3个月及当月的统计数据。例如,本月为12月,可筛选9月至12月的数据。

Android SDK访客端

当前版本:V1.1.3

新功能/优化:
  • 支持消息预知功能(增值服务)
  • 支持FCM推送

 
环信客户互动云更新日志http://docs.easemob.com/cs/releasenote/5.31 

环信客户互动云登陆地址http://kefu.easemob.com/
继续阅读 »
本次更新的主要内容为:​优化智能机器人功能,支持为机器人知识规则设置应答策略,使机器人能够根据不同的渠道关联、时间计划发送不同的答案。新增随机质检功能,采取系统对质检样本随机抽样的方法管理质检流程,避免质检作弊,使质检结果更加公平、公正。


环信客户互动云v5.31_产品更新说明

发布日期:2017-12-25

客服模式


客服变更在线状态需要审批

新增“客服变更在线状态需要审批”功能。当管理员打开“客服变更状态需要审批”开关时,普通客服将在线状态从“空闲”切换为忙碌、离开、隐身状态需要管理员审批;当管理员关闭此开关时,普通客服可以随意切换在线状态。

管理员切换在线状态不受此开关影响。

客服变更在线状态:

开关打开时,客服将在线状态从“空闲”切换为忙碌、离开、隐身状态时,将收到弹窗提醒,需填写状态变更理由,并提交至管理员审批。

01.png


管理员审批状态变更:

管理员收到客服的状态变更请求后,将在消息中心收到系统消息提醒。可以进入“管理员模式 > 审批管理”页面,审批该请求。

审批通过后,系统自动完成客服的状态切换。同时,系统发送系统消息提醒客服,可在消息中心页面查看。

02.png



“客服状态变更需要审批”开关:

需要对客服的在线状态变更进行审批时,管理员可以进入“管理员模式 > 设置 > 系统开关”页面,打开“客服状态变更需要审批”开关。

03.png



待接入会话列表显示坐席名

待接入页面的会话列表增加一列:坐席名,用于显示会话指定的客服名称。

注:若会话未指定客服,则只显示技能组名称,不显示客服名称。

管理员模式

机器人知识规则

机器人知识规则新增分类管理、日志管理、和应答策略。日志管理支持管理员查看知识规则相关的日志。分类管理支持将知识规则添加至不同的分类,方便查询和管理知识规则。应答策略为知识规则中的答案的发送策略,支持设置根据不同的渠道关联、时间计划发送不同的答案。

分类管理

在机器人的知识规则页面,可以添加、编辑分类,并修改知识规则所在的分类。

查看分类:

在分类列表中选择任意分类,查看该分类中的知识规则。

管理分类:

在分类列表下方,点击“管理分类”按钮,添加、编辑分类。

修改分类:

选中一条或多条知识规则,在弹出窗口中点击“修改分类”按钮,修改选中的知识规则所属的分类。

04.png


日志管理

日志管理支持管理员查看知识规则相关的日志,可以按照时间范围查询,以及导出。

在知识规则页面,点击“添加规则”右侧的下拉按钮,点击“日志管理”按钮,查看日志。

应答策略

支持为知识规则中的答案单独设置发送策略,在添加、编辑知识规则时,均可以设置发送策略。策略包含策略名称、条件(渠道关联和时间计划)、执行(知识规则的答案),当满足策略中的条件时,发送对应的答案给客户。

当知识规则中有多个答案时,如果不设置发送策略,则默认随机发送其中一个答案。

编辑知识规则:

在知识规则页面,点击知识规则右侧的“编辑”按钮,可以编辑知识规则。包括添加/编辑问题、添加/编辑答案。编辑完成后,点击“确认”。

05.png



添加发送策略:

在添加、编辑知识规则页面,点击“添加策略”按钮。
填写策略名称,选择一个渠道关联(不选择时,策略不生效),选择一个时间计划(不选择时,默认为全部时间),选择知识规则的一条答案,并保存。

设置好发送策略后,当客户的消息匹配知识规则的问题,并满足渠道关联和时间计划这两个条件时,发送策略中设置的答案给客户。

05.png



随机质检

新增随机质检功能。采取系统对质检样本随机抽样的方法管理质检流程,避免质检作弊,使质检结果更加公平、公正。

随机质检功能为标准版/旗舰版增值服务,如需开通,请提供租户ID并联系环信商务经理。

查看质检任务

质检任务由管理员/质检员创建,质检任务包含系统基于筛选条件随机抽取的客户会话。

在随机质检页面,管理员可以查看所有质检任务;质检员可以查看所有/自己创建的质检任务。

07.png



设置质检权限

进入“管理员模式 > 设置 > 权限管理”页面,设置质检员查看质检任务的数据权限。
  • 租户:支持查看系统内全部质检任务
  • 客服:只能查看自己创建的质检任务



08.png



创建质检任务

管理员/质检员每次可以为自己创建一条质检任务。质检任务分为质检中、已完成两个状态。当有质检中的任务时,需要先完成该质检任务,才可以创建新的质检任务。

在随机质检页面,点击右上角“创建质检任务”按钮,设置相关质检条件,再次点击“创建质检任务”按钮。系统根据质检条件随机抽取对应数量的会话,并创建质检任务。
  • 任务名称:质检任务的名称。
  • 时间范围:必须为一个月内,如11月1日至11月30日。
  • 会话抽样范围:包含会话来源渠道、技能组、关联、会话标签、参与客服。
  • 会话质检条件:包含首次响应时长、会话时长、平均/单次响应时长、访客/坐席消息数、满意度评价。
  • 抽样数量:必须为1至300之间的数字。



09.png



完成质检任务

管理员/质检员可以随时对质检中的任务里的会话进行质检评分,完成所有会话的质检评分后,即可完成该质检任务。

在随机质检页面,点击自己创建的质检任务,可以查看任务详情以及会话列表。点击任意会话,可查看会话详情,并对会话进行质检评分。
10.png


“24小时排队趋势”显示排队的会话详情

在“统计查询 > 排队统计”页面,点击“24小时排队趋势”中的柱状图,可以查看对应的排队的会话详情。

注:从该版本开始,“排队统计”仅支持筛选最近3个月及当月的统计数据。例如,本月为12月,可筛选9月至12月的数据。

Android SDK访客端

当前版本:V1.1.3

新功能/优化:
  • 支持消息预知功能(增值服务)
  • 支持FCM推送

 
环信客户互动云更新日志http://docs.easemob.com/cs/releasenote/5.31 

环信客户互动云登陆地址http://kefu.easemob.com/ 收起阅读 »

一款基于环信开发的APP-超级家委会

【产品简介】
 
“超级家委会”是一款基于环信开发的集活动、聊天、项目管理为一体的APP。

如需项目合作,请联系:石锋 18616870207(微信同号)

【功能介绍】

消息

享畅聊,与微信一样好用的通讯功能,免费即时沟通,但在这里只聊工作,去除娱乐化,支持单聊、普通群聊、活动群聊、部门群聊、团队群聊。

聊天.jpg


【单聊】和好友实时沟通
【群聊】邀请特定的人组建群聊
【活动群聊】对活动感兴趣的人员可以一起畅所欲言,也可和主办方沟通疑问,活动群聊 页面可一键直达活动
【部门/团队群聊】提供团队内部聊天功能,随时与同伴和团队沟通和讨论工作,让沟通更顺畅
【系统消息】实时接收重要信息的通知,如审核申请,报名信息,关注,评论等,并及时做出反馈;
 
实现功能
  • 好友/群内的文字、表情、图片、位置、收藏、名片发送和接收
  • 查看群信息
  • 快速查找
  • 新建群 
  • 系统消息推送
  • 删除会话
  • 获取未读消息
  • @功能正在实现中...


聊天功能介绍1.jpg

聊天功能介绍2.jpg

聊天功能介绍3.jpg

聊天功能介绍4.jpg

聊天功能介绍6.jpg

 
项目

提供了包括项目管理、行政办公、教育培训、营销工具等基本应用和丰富的插件功能,通过精心设计打造出体验出色的应用,且每个项目可直达相应群聊,让你和团队成员随时随地参与协作。

聊天功能介绍8.jpg

 
【快速立项】明确工作目标并创建项目 ,邀请团队成员加入项目一起来开展工作;
【任务管理】新建任务,指派执行者和添加参与者,添加并更新相关任务信息;
【工作安排】创建「日程」来安排会议、 记录外出和预约重点活动等等工作,也随时了解其他项目成员的工作安排;
【进展同步】通过任务列表随时关注项目进展的更新,进入项目查看具体的进展信息;
【插件丰富】丰富的移动办公应用接入,任务、签到、审批、笔记、文件、费用、班级、学生老师、课程、消课等,应有尽有。
 
活动
您可以参加活动聚会,学习一项新技能,带上孩子发现未知…更特别的是,您还可以自己组织发起活动,呼朋唤友一起玩耍。

聊天功能介绍9.jpg

 
【主办方】提供从发布活动、活动推广、报名管理到财务管理等全流程完整解决方案
【参与者】找到感兴趣的活动,志同道合的朋友,长假远行,家长课堂,周边游,培训课 程,聚会沙龙,冬夏令营,手工课程,多种活动,丰富娱乐生活
【报名信息 随时查收】支持自定义设置报名表单,报名信息详情可查,支持导出
【精彩活动 乐享群聊】一起进入活动群聊,可以和其他参与者一起互动
 
联系人
  • 搜索好友/群 
  • 添加好友/群 
  • 发送/接受好友申请


聊天功能介绍10.jpg


聊天功能介绍5.jpg

 
【技术实现】

本项目是基于官方最新SDK Hyphenate 进行开发 页面效果基于EasyUI调整 和微信页面效果看齐。
 
主要实现功能 
 
1、注册 登录 自动登录 重连 退出登录
EMError *error = [[EMClient sharedClient] registerWithUsername:@"8001" password:@"111111"];
if (error==nil) {
NSLog(@"注册成功");
}
EMError *error = [[EMClient sharedClient] loginWithUsername:@"8001" password:@"111111"];
if (!error) {
NSLog(@"登录成功");
}

自动登录:即首次登录成功后,不需要再次调用登录方法,在下次 APP 启动时,SDK 会自动为您登录。并且如果您自动登录失败,也可以读取到之前的会话信息。

SDK 中自动登录属性默认是关闭的,需要您在登录成功后设置,以便您在下次 APP 启动时不需要再次调用环信登录,并且能在没有网的情况下得到会话列表。

EMError *error = [[EMClient sharedClient] loginWithUsername:@"8001" password:@"111111"];
if (!error)
{
[[EMClient sharedClient].options setIsAutoLogin:YES];
}

2. 消息
IM 交互实体,在 SDK 中对应的类型是 EMMessage。EMMessage 由 EMMessageBody 组成。

构造文字消息 构造图片消息 构造图片消息 构造位置消息 构造语音消息 构造视频消息 构造扩展消息(系统消息)
构造文字消息
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要发送的消息"];
NSString *from = [[EMClient sharedClient] currentUsername];

//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息

构造图片消息
EMImageMessageBody *body = [[EMImageMessageBody alloc] initWithData:data displayName:@"image.png"];
// body.compressionRatio = 1.0f; 1.0表示发送原图不压缩。默认值是0.6,压缩的倍数是0.6倍
NSString *from = [[EMClient sharedClient] currentUsername];

//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息

构造扩展消息
// 以单聊消息举例
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要发送的消息"];
NSString *from = [[EMClient sharedClient] currentUsername];

//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息
//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息
//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息
message.ext = @{@"key":@"value"}; // 扩展消息部分

扩展消息主要用要系统消息里

3. 会话

操作聊天消息 EMMessage 的容器,在 SDK 中对应的类型是 EMConversation。

新建 、 获取一个会话 (根据 conversationId 创建一个 conversation)
[[EMClient sharedClient].chatManager getConversation:@"8001" type:EMConversationTypeChat createIfNotExist:YES];
//EMConversationTypeChat 单聊会话
//EMConversationTypeGroupChat 群聊会话
//EMConversationTypeChatRoom 聊天室会话


getConversation:创建与8001的会话
type:会话类型
createIfNotExist:不存在是否创建
 
4. 删除会话

删除单个会话
[[EMClient sharedClient].chatManager deleteConversation:@"8001" isDeleteMessages:YES completion:^(NSString *aConversationId, EMError *aError){
//code
}];


deleteConversation: 删除与8001的会话
deleteMessages: 删除会话中的消息
 
5. 获取会话列表

获取所有会话 (内存中有则从内存中取,否则从db中取)
NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations];

6. 获取会话未读消息 
[EMConversation unreadMessagesCount]; 显示红点       

7. 聊天 (发送消息 接收消息 解析普通消息 解析扩展消息)

登录成功之后才能进行聊天操作。发消息时,单聊和群聊调用的是统一接口,区别只是要设置下 message.chatType。
/*!
@property
@brief 发送消息
@discussion
异步方法
*/
- (void)sendMessage:(EMMessage *)aMessage
progress:(void (^)(int progress))aProgressBlock
completion:(void (^)(EMMessage *message, EMError *error))aCompletionBlock;

//调用:[[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *aError) {}];

//消息回调:EMChatManagerDelegate

//移除消息回调
[[EMClient sharedClient].chatManager removeDelegate:self];

//注册消息回调
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];

/*!
@method
@brief 接收到一条及以上非cmd消息
*/
- (void)messagesDidReceive:(NSArray *)aMessages;

解析普通消息
// 收到消息的回调,带有附件类型的消息可以用 SDK 提供的下载附件方法下载(后面会讲到)
- (void)messagesDidReceive:(NSArray *)aMessages {
for (EMMessage *message in aMessages) {
EMMessageBody *msgBody = message.body;
switch (msgBody.type) {
case EMMessageBodyTypeText:
{
// 收到的文字消息
EMTextMessageBody *textBody = (EMTextMessageBody *)msgBody;
NSString *txt = textBody.text;
NSLog(@"收到的文字是 txt -- %@",txt);
}
break;
case EMMessageBodyTypeImage:

解析扩展消息
- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages {
for (EMMessage *message in aCmdMessages) {
// cmd消息中的扩展属性
NSDictionary *ext = message.ext;
NSLog(@"cmd消息中的扩展属性是 -- %@",ext)
}
}
// 收到消息回调
- (void)messagesDidReceive:(NSArray *)aMessages {
for (EMMessage *message in aMessages) {
// 消息中的扩展属性
NSDictionary *ext = message.ext;
NSLog(@"消息中的扩展属性是 -- %@",ext);
}
}



 8. 好友管理 (本项目的好友管理是自己服务器上管理的)

9. 好友申请

发送好友申请
 EMError *error = [[EMClient sharedClient].contactManager addContact:@"6001" message:@"我想加您为好友"];
if (!error) {
NSLog(@"添加成功");
}

监听加好友请求 (项目里面 发送系统消息)
/*!
* 用户A发送加用户B为好友的申请,用户B会收到这个回调
*
* @param aUsername 用户名
* @param aMessage 附属信息
*/
- (void)friendRequestDidReceiveFromUser:(NSString *)aUsername
message:(NSString *)aMessage;

同意加好友申请 
EMError *error = [[EMClient sharedClient].contactManager acceptInvitationForUsername:@"8001"];
if (!error) {
NSLog(@"发送同意成功");
}

10 群组管理
创建群 后台创建的
加入群组 添人进群 退出群组 解散群组 修改群描述 获取群组成员列表

11 群组管理
1.后台配置推送证书
2.代码配置 APNs 使用的推送证书。
3.代码注册离线推送

【联系我们】
如需项目合作,请联系
石锋 18616870207 (微信同号)
继续阅读 »
【产品简介】
 
“超级家委会”是一款基于环信开发的集活动、聊天、项目管理为一体的APP。

如需项目合作,请联系:石锋 18616870207(微信同号)

【功能介绍】

消息

享畅聊,与微信一样好用的通讯功能,免费即时沟通,但在这里只聊工作,去除娱乐化,支持单聊、普通群聊、活动群聊、部门群聊、团队群聊。

聊天.jpg


【单聊】和好友实时沟通
【群聊】邀请特定的人组建群聊
【活动群聊】对活动感兴趣的人员可以一起畅所欲言,也可和主办方沟通疑问,活动群聊 页面可一键直达活动
【部门/团队群聊】提供团队内部聊天功能,随时与同伴和团队沟通和讨论工作,让沟通更顺畅
【系统消息】实时接收重要信息的通知,如审核申请,报名信息,关注,评论等,并及时做出反馈;
 
实现功能
  • 好友/群内的文字、表情、图片、位置、收藏、名片发送和接收
  • 查看群信息
  • 快速查找
  • 新建群 
  • 系统消息推送
  • 删除会话
  • 获取未读消息
  • @功能正在实现中...


聊天功能介绍1.jpg

聊天功能介绍2.jpg

聊天功能介绍3.jpg

聊天功能介绍4.jpg

聊天功能介绍6.jpg

 
项目

提供了包括项目管理、行政办公、教育培训、营销工具等基本应用和丰富的插件功能,通过精心设计打造出体验出色的应用,且每个项目可直达相应群聊,让你和团队成员随时随地参与协作。

聊天功能介绍8.jpg

 
【快速立项】明确工作目标并创建项目 ,邀请团队成员加入项目一起来开展工作;
【任务管理】新建任务,指派执行者和添加参与者,添加并更新相关任务信息;
【工作安排】创建「日程」来安排会议、 记录外出和预约重点活动等等工作,也随时了解其他项目成员的工作安排;
【进展同步】通过任务列表随时关注项目进展的更新,进入项目查看具体的进展信息;
【插件丰富】丰富的移动办公应用接入,任务、签到、审批、笔记、文件、费用、班级、学生老师、课程、消课等,应有尽有。
 
活动
您可以参加活动聚会,学习一项新技能,带上孩子发现未知…更特别的是,您还可以自己组织发起活动,呼朋唤友一起玩耍。

聊天功能介绍9.jpg

 
【主办方】提供从发布活动、活动推广、报名管理到财务管理等全流程完整解决方案
【参与者】找到感兴趣的活动,志同道合的朋友,长假远行,家长课堂,周边游,培训课 程,聚会沙龙,冬夏令营,手工课程,多种活动,丰富娱乐生活
【报名信息 随时查收】支持自定义设置报名表单,报名信息详情可查,支持导出
【精彩活动 乐享群聊】一起进入活动群聊,可以和其他参与者一起互动
 
联系人
  • 搜索好友/群 
  • 添加好友/群 
  • 发送/接受好友申请


聊天功能介绍10.jpg


聊天功能介绍5.jpg

 
【技术实现】

本项目是基于官方最新SDK Hyphenate 进行开发 页面效果基于EasyUI调整 和微信页面效果看齐。
 
主要实现功能 
 
1、注册 登录 自动登录 重连 退出登录
EMError *error = [[EMClient sharedClient] registerWithUsername:@"8001" password:@"111111"];
if (error==nil) {
NSLog(@"注册成功");
}
EMError *error = [[EMClient sharedClient] loginWithUsername:@"8001" password:@"111111"];
if (!error) {
NSLog(@"登录成功");
}

自动登录:即首次登录成功后,不需要再次调用登录方法,在下次 APP 启动时,SDK 会自动为您登录。并且如果您自动登录失败,也可以读取到之前的会话信息。

SDK 中自动登录属性默认是关闭的,需要您在登录成功后设置,以便您在下次 APP 启动时不需要再次调用环信登录,并且能在没有网的情况下得到会话列表。

EMError *error = [[EMClient sharedClient] loginWithUsername:@"8001" password:@"111111"];
if (!error)
{
[[EMClient sharedClient].options setIsAutoLogin:YES];
}

2. 消息
IM 交互实体,在 SDK 中对应的类型是 EMMessage。EMMessage 由 EMMessageBody 组成。

构造文字消息 构造图片消息 构造图片消息 构造位置消息 构造语音消息 构造视频消息 构造扩展消息(系统消息)
构造文字消息
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要发送的消息"];
NSString *from = [[EMClient sharedClient] currentUsername];

//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息

构造图片消息
EMImageMessageBody *body = [[EMImageMessageBody alloc] initWithData:data displayName:@"image.png"];
// body.compressionRatio = 1.0f; 1.0表示发送原图不压缩。默认值是0.6,压缩的倍数是0.6倍
NSString *from = [[EMClient sharedClient] currentUsername];

//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息

构造扩展消息
// 以单聊消息举例
EMTextMessageBody *body = [[EMTextMessageBody alloc] initWithText:@"要发送的消息"];
NSString *from = [[EMClient sharedClient] currentUsername];

//生成Message
EMMessage *message = [[EMMessage alloc] initWithConversationID:@"6001" from:from to:@"6001" body:body ext:messageExt];
message.chatType = EMChatTypeChat;// 设置为单聊消息
//message.chatType = EMChatTypeGroupChat;// 设置为群聊消息
//message.chatType = EMChatTypeChatRoom;// 设置为聊天室消息
message.ext = @{@"key":@"value"}; // 扩展消息部分

扩展消息主要用要系统消息里

3. 会话

操作聊天消息 EMMessage 的容器,在 SDK 中对应的类型是 EMConversation。

新建 、 获取一个会话 (根据 conversationId 创建一个 conversation)
[[EMClient sharedClient].chatManager getConversation:@"8001" type:EMConversationTypeChat createIfNotExist:YES];
//EMConversationTypeChat 单聊会话
//EMConversationTypeGroupChat 群聊会话
//EMConversationTypeChatRoom 聊天室会话


getConversation:创建与8001的会话
type:会话类型
createIfNotExist:不存在是否创建
 
4. 删除会话

删除单个会话
[[EMClient sharedClient].chatManager deleteConversation:@"8001" isDeleteMessages:YES completion:^(NSString *aConversationId, EMError *aError){
//code
}];


deleteConversation: 删除与8001的会话
deleteMessages: 删除会话中的消息
 
5. 获取会话列表

获取所有会话 (内存中有则从内存中取,否则从db中取)
NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations];

6. 获取会话未读消息 
[EMConversation unreadMessagesCount]; 显示红点       

7. 聊天 (发送消息 接收消息 解析普通消息 解析扩展消息)

登录成功之后才能进行聊天操作。发消息时,单聊和群聊调用的是统一接口,区别只是要设置下 message.chatType。
/*!
@property
@brief 发送消息
@discussion
异步方法
*/
- (void)sendMessage:(EMMessage *)aMessage
progress:(void (^)(int progress))aProgressBlock
completion:(void (^)(EMMessage *message, EMError *error))aCompletionBlock;

//调用:[[EMClient sharedClient].chatManager sendMessage:message progress:nil completion:^(EMMessage *aMessage, EMError *aError) {}];

//消息回调:EMChatManagerDelegate

//移除消息回调
[[EMClient sharedClient].chatManager removeDelegate:self];

//注册消息回调
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];

/*!
@method
@brief 接收到一条及以上非cmd消息
*/
- (void)messagesDidReceive:(NSArray *)aMessages;

解析普通消息
// 收到消息的回调,带有附件类型的消息可以用 SDK 提供的下载附件方法下载(后面会讲到)
- (void)messagesDidReceive:(NSArray *)aMessages {
for (EMMessage *message in aMessages) {
EMMessageBody *msgBody = message.body;
switch (msgBody.type) {
case EMMessageBodyTypeText:
{
// 收到的文字消息
EMTextMessageBody *textBody = (EMTextMessageBody *)msgBody;
NSString *txt = textBody.text;
NSLog(@"收到的文字是 txt -- %@",txt);
}
break;
case EMMessageBodyTypeImage:

解析扩展消息
- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages {
for (EMMessage *message in aCmdMessages) {
// cmd消息中的扩展属性
NSDictionary *ext = message.ext;
NSLog(@"cmd消息中的扩展属性是 -- %@",ext)
}
}
// 收到消息回调
- (void)messagesDidReceive:(NSArray *)aMessages {
for (EMMessage *message in aMessages) {
// 消息中的扩展属性
NSDictionary *ext = message.ext;
NSLog(@"消息中的扩展属性是 -- %@",ext);
}
}



 8. 好友管理 (本项目的好友管理是自己服务器上管理的)

9. 好友申请

发送好友申请
 EMError *error = [[EMClient sharedClient].contactManager addContact:@"6001" message:@"我想加您为好友"];
if (!error) {
NSLog(@"添加成功");
}

监听加好友请求 (项目里面 发送系统消息)
/*!
* 用户A发送加用户B为好友的申请,用户B会收到这个回调
*
* @param aUsername 用户名
* @param aMessage 附属信息
*/
- (void)friendRequestDidReceiveFromUser:(NSString *)aUsername
message:(NSString *)aMessage;

同意加好友申请 
EMError *error = [[EMClient sharedClient].contactManager acceptInvitationForUsername:@"8001"];
if (!error) {
NSLog(@"发送同意成功");
}

10 群组管理
创建群 后台创建的
加入群组 添人进群 退出群组 解散群组 修改群描述 获取群组成员列表

11 群组管理
1.后台配置推送证书
2.代码配置 APNs 使用的推送证书。
3.代码注册离线推送

【联系我们】
如需项目合作,请联系
石锋 18616870207 (微信同号) 收起阅读 »

【有奖互动】如果把各编程语言比作各国语言,哪种语言对应中文?

Quora 问答社区最近有人提了一个有趣的问题:

如果把编程语言比作各国语言,会分别对应什么?


目前点赞最高的回复如下:

Python 是英语,迅速成为许多人说的全球“默认”语言。多数情况下,相对容易学习,表达,语法简洁。

C 是中文,非常紧凑和快速,但很难学习和写作,容易“倒”在起点。
 
Lisp 是世界语(Esperanto)。只有一小群忠实的人说,并且一直告诉别人这有多棒。

Ruby 会是法语。这是一种可爱的语言,充满了例外和怪癖。一度受到精英的喜爱。现在虽然快要过时了,但仍然性感。

Ruby 会是法语,这是一种可爱的语言,充满了例外和怪癖。一度受到精英的喜爱。现在虽然快要过时了,但仍然性感。

Assembly 是拉丁语。现在几乎没什么人说了,尽管它是大多数现代语言的基础。



对此,中国小伙伴发表了他们的看法:

@网友:PHP是中文,想白话文就白话文,想文言文就文言文。


@网友:Java 是日语,入门很容易,精通很痛苦



对此问题,你怎么看?欢迎评论参与探讨。评论前5名同学送出环信定制指尖陀螺一个。


8201EEC6@7B48295(01-02-14-33-46).jpg

 
继续阅读 »
Quora 问答社区最近有人提了一个有趣的问题:

如果把编程语言比作各国语言,会分别对应什么?


目前点赞最高的回复如下:

Python 是英语,迅速成为许多人说的全球“默认”语言。多数情况下,相对容易学习,表达,语法简洁。

C 是中文,非常紧凑和快速,但很难学习和写作,容易“倒”在起点。
 
Lisp 是世界语(Esperanto)。只有一小群忠实的人说,并且一直告诉别人这有多棒。

Ruby 会是法语。这是一种可爱的语言,充满了例外和怪癖。一度受到精英的喜爱。现在虽然快要过时了,但仍然性感。

Ruby 会是法语,这是一种可爱的语言,充满了例外和怪癖。一度受到精英的喜爱。现在虽然快要过时了,但仍然性感。

Assembly 是拉丁语。现在几乎没什么人说了,尽管它是大多数现代语言的基础。



对此,中国小伙伴发表了他们的看法:

@网友:PHP是中文,想白话文就白话文,想文言文就文言文。


@网友:Java 是日语,入门很容易,精通很痛苦



对此问题,你怎么看?欢迎评论参与探讨。评论前5名同学送出环信定制指尖陀螺一个。


8201EEC6@7B48295(01-02-14-33-46).jpg

  收起阅读 »

2017环信八大开源项目源码放出:两个已获融资,单个20W+关注

“这是一家极具极客范的公司”,来过环信公司的每一位客户都这么评价到。有着“连接人与人,连接人与商业”愿景的环信正在一步一步慢慢用技术和场景改变每个人的生活和工作。生有涯而知无涯,业有涯而心无涯,路漫漫其修远,“开源”当上下而求索!

 环信成立于2013年,公司数位联合创始人都是技术大牛出身,在Symbian,Nokia,Red Hat等知名IT公司都是开源项目的重度参与者,环信的基因便因此打上了“开源”的烙印,在2014年即创办了国内首个即时通讯云开源社区“IMGeek社区”,经过了3年多的深耕,2017年度在环信IMGeek社区涌现了数十个优质开源项目,其中两个开源项目目前已经拿到融资,更有一个项目获得了超过20W+的关注度,环信正通过即时通讯云PaaS平台和客服PaaS平台一步步完善自己的商业梦想,也在一步步的通过开源回馈自己的开发者和产业链上下游的小伙伴。

微信图片_20171229142123.jpg

环信公司前台一角


2017年是企业服务丰收的一年,感谢伙伴们对环信一直以来的支持。18年伊始之际,我们总结了17年间基于环信开发者的八大开源项目,希望能对大家有所帮助。
 
小马直播间-开源直播APP
 
推荐理由:基于环信开发的开源直播应用,IMGeek收藏数量3W8,对于有直播需求的小伙伴们值得参考,教你从头开始开发一个移动端直播APP。
 
互联网直播平台催生了一批批网红大咖,作为程序猿,我们绝不甘于委身幕后做搬砖工,我们一定要闪亮登场!!!做一个属于我们程序猿的IOS版直播平台~~

小马直播间.png

应用截图


 实现功能:
  • 创建推流和拉流加速
  • 集成环信IM的聊天室功能
  • 集成UCloud的ULive直播云SDK
  • 在聊天室里集成推流(录制)和拉流(播放)功能

 相关链接:http://www.imgeek.org/article/825307904​ 

Dolores-基于环信IM开发完整的企业通讯解决方案
 
推荐理由:对企业而言,初选OA办公系统是为了满足需求,解决当下问题,由于OA办公系统的在公司运作流程中扮演的重要性,安全与隐私等问题急需未雨绸缪,“可定制”、“可私有化部署”的OA办公系统成为了更多企业的首选。
 
公司想自己开发一套IM系统应该从哪里开始呢? 企业通讯录怎么保持同步呢? 企业通讯录的权限管理应该怎么做?

89e5f4394605d1a330e558e46e7cc6b0.jpg

Dolores海报


相关链接:http://www.imgeek.org/article/825308805
 
凡信-百尺竿头更进一步,2017凡信携直播、红包而来
 
推荐理由:自凡信开源以来,更新了3个大版本,从基本聊天功能,到越来越多的开发者创建分支,累计收到了10W+的收藏,帮助了很多开发者进行开发即时通讯应用。
 
已完成功能:
  • 单聊
  • 群聊
  • 朋友圈
  • 钱包
  • 直播
  • 红包

凡信.png

项目运行效果图


相关链接:http://www.imgeek.org/article/825307930
 
 Slack聊天机器人-环信客服版
 
推荐理由:17年作为人工智能元年,聊天机器人(Chatbot)在各大行业的应用方兴未艾,国外包括Facebook Messenger、Slack等均引入了聊天机器人,所以毋庸置疑,聊天机器人将成为我们未来生活中不可或缺的一部分
,IMGEEK开源社区热心开发者&朝阳区群众“晨星桑”一言不合他就花2小时写了一个Slack的聊天机器人,您可以通过这个项目在Slack上对接客户服务,并且通过一些定制开发能够看见Slack用户的基本信息(比如:昵称、电话、团队名称等),并且可以二维码支付。
相关功能:
  • 事件订阅初始化
  • 处理消息的事件
  • 把消息发送到移动客服
  • 处理OAuth回调
  • 把收到的消息发给Slack 用户

 
相关链接:http://www.imgeek.org/article/825308711​ 
 
泛聊-厉害了我的开发者,基于环信的开源高仿QQ项目
 
推荐理由:聊天功能做到了极致,展示即时通讯基本功能的实现,包括注册登录,退出登录,联系人列表,添加好友,删除好友,收发消息,消息提醒等功能。

泛聊.png

项目运行效果图


实现功能:
  •  环信SDK的集成与使用
  •  MVP模式的运用
  •  ORM数据库的集成与使用
  •  模块化思想的运用

 相关链接:http://www.imgeek.org/article/825308542​ 
 
Baby-开源私密社交应用
 
推荐理由:私密社交APP,情侣、死党必备的一对一专属聊天应用。作者开发初期下载了市面上所有IM的demo源码跑一遍,从功能、集成难易和消息稳定几个方面对比,最终还是选择了环信。使用环信EaseUi集成,基本上一天就能集成完毕。

baby.png

项目运行效果图


实现功能:
  • 加入Tinker 热修复
  • 加入部分注释
  • 增加长按删除功能
  • 优化Rxbus订阅加载数据
  • 外国友人优化的一些细节
  • 增加了评论功能
  • 优化了相册加载
  • 把登陆注册事件换了个Zip操作符更符合流的思想

相关链接:http://www.imgeek.org/article/825308850

LITE-IM-环信webim的网页即时聊天

推荐理由:你见过最酷炫的WEB聊天项目,LITE-IM不仅能够担当客户服务来使用,还可以用作你网站粘连客户、活跃社区的媒介,提升用户的使用率。

lym.png

项目运行效果图


[b]实现功能:[/b]
  • 好友/群内的文字、表情、图片、文件 在线/离线消息发送和接收。
  • 查看群员列表。 
  • 面板内快速查找。 
  • 面板右键自定义事件 
  • 修改签名 
  • 自定义上传背景皮肤 
  • 搜索好友/群 
  • 添加好友/群 
  • 新建群 
  • 消息盒子展示

 相关链接:http://www.imgeek.org/article/825308961 
 
VMTVCall-使用环信3.xSDK 在 TV 端集成音视频通话功能
 
推荐理由:移动互联网方便了我们生活,移动端随时随地沟通成为了常态,今天我们推荐的是一个可以安装在电视机上进行视频通话的开源项目。

电视机.jpg

项目运行效果图


 
实现功能
  • 项目首次启动自动注册登录
  • 拨号盘实现
  • 历史通话记录 TODO
  • 视频通话功能(因为电视不需要语音通话以及最小化)
  • 视频通话的录制
  • 通话截图

 相关链接:http://www.imgeek.org/article/825308732
 
end.
 
生有涯而知无涯,业有涯而心无涯,路漫漫其修远,当上下而求索。未来,我们还将开源更多。
 
环信IMGeek社区开源项目地址http://www.imgeek.org/code/
 
继续阅读 »
“这是一家极具极客范的公司”,来过环信公司的每一位客户都这么评价到。有着“连接人与人,连接人与商业”愿景的环信正在一步一步慢慢用技术和场景改变每个人的生活和工作。生有涯而知无涯,业有涯而心无涯,路漫漫其修远,“开源”当上下而求索!

 环信成立于2013年,公司数位联合创始人都是技术大牛出身,在Symbian,Nokia,Red Hat等知名IT公司都是开源项目的重度参与者,环信的基因便因此打上了“开源”的烙印,在2014年即创办了国内首个即时通讯云开源社区“IMGeek社区”,经过了3年多的深耕,2017年度在环信IMGeek社区涌现了数十个优质开源项目,其中两个开源项目目前已经拿到融资,更有一个项目获得了超过20W+的关注度,环信正通过即时通讯云PaaS平台和客服PaaS平台一步步完善自己的商业梦想,也在一步步的通过开源回馈自己的开发者和产业链上下游的小伙伴。

微信图片_20171229142123.jpg

环信公司前台一角


2017年是企业服务丰收的一年,感谢伙伴们对环信一直以来的支持。18年伊始之际,我们总结了17年间基于环信开发者的八大开源项目,希望能对大家有所帮助。
 
小马直播间-开源直播APP
 
推荐理由:基于环信开发的开源直播应用,IMGeek收藏数量3W8,对于有直播需求的小伙伴们值得参考,教你从头开始开发一个移动端直播APP。
 
互联网直播平台催生了一批批网红大咖,作为程序猿,我们绝不甘于委身幕后做搬砖工,我们一定要闪亮登场!!!做一个属于我们程序猿的IOS版直播平台~~

小马直播间.png

应用截图


 实现功能:
  • 创建推流和拉流加速
  • 集成环信IM的聊天室功能
  • 集成UCloud的ULive直播云SDK
  • 在聊天室里集成推流(录制)和拉流(播放)功能

 相关链接:http://www.imgeek.org/article/825307904​ 

Dolores-基于环信IM开发完整的企业通讯解决方案
 
推荐理由:对企业而言,初选OA办公系统是为了满足需求,解决当下问题,由于OA办公系统的在公司运作流程中扮演的重要性,安全与隐私等问题急需未雨绸缪,“可定制”、“可私有化部署”的OA办公系统成为了更多企业的首选。
 
公司想自己开发一套IM系统应该从哪里开始呢? 企业通讯录怎么保持同步呢? 企业通讯录的权限管理应该怎么做?

89e5f4394605d1a330e558e46e7cc6b0.jpg

Dolores海报


相关链接:http://www.imgeek.org/article/825308805
 
凡信-百尺竿头更进一步,2017凡信携直播、红包而来
 
推荐理由:自凡信开源以来,更新了3个大版本,从基本聊天功能,到越来越多的开发者创建分支,累计收到了10W+的收藏,帮助了很多开发者进行开发即时通讯应用。
 
已完成功能:
  • 单聊
  • 群聊
  • 朋友圈
  • 钱包
  • 直播
  • 红包

凡信.png

项目运行效果图


相关链接:http://www.imgeek.org/article/825307930
 
 Slack聊天机器人-环信客服版
 
推荐理由:17年作为人工智能元年,聊天机器人(Chatbot)在各大行业的应用方兴未艾,国外包括Facebook Messenger、Slack等均引入了聊天机器人,所以毋庸置疑,聊天机器人将成为我们未来生活中不可或缺的一部分
,IMGEEK开源社区热心开发者&朝阳区群众“晨星桑”一言不合他就花2小时写了一个Slack的聊天机器人,您可以通过这个项目在Slack上对接客户服务,并且通过一些定制开发能够看见Slack用户的基本信息(比如:昵称、电话、团队名称等),并且可以二维码支付。
相关功能:
  • 事件订阅初始化
  • 处理消息的事件
  • 把消息发送到移动客服
  • 处理OAuth回调
  • 把收到的消息发给Slack 用户

 
相关链接:http://www.imgeek.org/article/825308711​ 
 
泛聊-厉害了我的开发者,基于环信的开源高仿QQ项目
 
推荐理由:聊天功能做到了极致,展示即时通讯基本功能的实现,包括注册登录,退出登录,联系人列表,添加好友,删除好友,收发消息,消息提醒等功能。

泛聊.png

项目运行效果图


实现功能:
  •  环信SDK的集成与使用
  •  MVP模式的运用
  •  ORM数据库的集成与使用
  •  模块化思想的运用

 相关链接:http://www.imgeek.org/article/825308542​ 
 
Baby-开源私密社交应用
 
推荐理由:私密社交APP,情侣、死党必备的一对一专属聊天应用。作者开发初期下载了市面上所有IM的demo源码跑一遍,从功能、集成难易和消息稳定几个方面对比,最终还是选择了环信。使用环信EaseUi集成,基本上一天就能集成完毕。

baby.png

项目运行效果图


实现功能:
  • 加入Tinker 热修复
  • 加入部分注释
  • 增加长按删除功能
  • 优化Rxbus订阅加载数据
  • 外国友人优化的一些细节
  • 增加了评论功能
  • 优化了相册加载
  • 把登陆注册事件换了个Zip操作符更符合流的思想

相关链接:http://www.imgeek.org/article/825308850

LITE-IM-环信webim的网页即时聊天

推荐理由:你见过最酷炫的WEB聊天项目,LITE-IM不仅能够担当客户服务来使用,还可以用作你网站粘连客户、活跃社区的媒介,提升用户的使用率。

lym.png

项目运行效果图


[b]实现功能:[/b]
  • 好友/群内的文字、表情、图片、文件 在线/离线消息发送和接收。
  • 查看群员列表。 
  • 面板内快速查找。 
  • 面板右键自定义事件 
  • 修改签名 
  • 自定义上传背景皮肤 
  • 搜索好友/群 
  • 添加好友/群 
  • 新建群 
  • 消息盒子展示

 相关链接:http://www.imgeek.org/article/825308961 
 
VMTVCall-使用环信3.xSDK 在 TV 端集成音视频通话功能
 
推荐理由:移动互联网方便了我们生活,移动端随时随地沟通成为了常态,今天我们推荐的是一个可以安装在电视机上进行视频通话的开源项目。

电视机.jpg

项目运行效果图


 
实现功能
  • 项目首次启动自动注册登录
  • 拨号盘实现
  • 历史通话记录 TODO
  • 视频通话功能(因为电视不需要语音通话以及最小化)
  • 视频通话的录制
  • 通话截图

 相关链接:http://www.imgeek.org/article/825308732
 
end.
 
生有涯而知无涯,业有涯而心无涯,路漫漫其修远,当上下而求索。未来,我们还将开源更多。
 
环信IMGeek社区开源项目地址http://www.imgeek.org/code/
  收起阅读 »

环信客户互动云v5.30已上线,支持客服主动发起视频邀请

本次更新的主要内容为:支持客服将个人常用语提交至公共常用语,方便整个客服团队共同维护公共常用语,提升常用语维护相关的工作效率。优化实时视频功能,支持客服在会话过程中主动发起视频邀请。
客服模式

支持客服提交公共常用语

支持客服将个人常用语提交至公共常用语,方便整个客服团队共同维护公共常用语,提升常用语维护相关的工作效率。

提交个人常用语至公共常用语:
  1. 进入常用语页面,将鼠标放在个人常用语上,点击提交按钮 [提交] 。
  2. 选择公共常用语分类,确认常用语的内容(可修改),填写提交理由,并点击“提交”按钮。


客服将个人常用语提交至公共常用语后,需要管理员在“管理员模式 > 审批管理”页面,对客服的常用语申请进行审批,审批通过后,该常用语展示在公共常用语中。 
 
001.png


支持客服主动发起视频邀请

与app、网页端客户聊天过程中,客服可以主动发起视频邀请,待客户接受视频邀请后,即可开始视频聊天。

客服发起视频聊天:
  1. 在会话页面,选择客户的会话,点击输入框上方的视频按钮 [发起视频邀请] 。
  2. 等待客户接受视频邀请。


在视频通话过程中,客服还可以邀请一名客服同事加入视频,或者与客户共享桌面。

注:“实时视频”功能为增值服务,如需开通,请提供租户ID并联系环信商务经理。 
 
002.png


管理员模式

新增审批管理功能


新增审批管理功能。支持客服提交申请,由管理员统一进行审批,增强管理员对客服团队的管理能力,加强团队协作。

目前,支持客服提交个人常用语至公共常用语,由管理员进行审批。审批通过后,自动将该常用语添加至公共常用语,供所有客服使用。后续会增加更多审批功能,敬请期待。

审批管理页面分类显示所有待审批、已通过、已拒绝的审批申请,点击任意待审批的申请,可查看申请详情,并对其进行审批(通过或拒绝)。

客服提交申请后,管理员会在消息中心收到提醒;管理员完成审批后,客服可在消息中心查看审批结果。 
 
003png.png


新增调度规则设置

会话调度指会话路由至技能组后,系统将会话分配给技能组内客服的过程。调度规则包含技能组优先级属性等,由管理员设置,用于控制会话调度时分配会话的先后顺序。

新增调度规则设置,支持管理员设置5个技能组的优先级顺序,对优先级高的技能组的会话进行优先调度。并且,在调度规则中设置了优先级的技能组比剩余的其他技能组优先级高。例如:客服A同时属于技能组B和技能组C,技能组B的优先级高,则优先将技能组B的会话分配给客服A。

设置并启用调度规则:
  1. 进入“管理员模式 > 设置 > 会话分配规则 > 调度规则”页签。
  2. 在“客服接待能力分配”栏目下,点击“设置技能组优先级”按钮。
  3. 添加优先等级,并设置技能组对应的优先顺序。
  4. 打开“客服接待能力分配”开关。


注:“调度规则”功能为标准版/旗舰版增值服务,如需开通,请提供租户ID并联系环信商务经理。 
 
004.png


支持根据客户信息路由会话

路由规则新增“客户信息指定”,目前支持按照客户标签将客户会话分配至不同的客服、技能组或机器人。该路由规则可用于优先接待VIP客户,为不同类别的客户提供有区别的客户服务等。

设置客户信息指定规则:
  1. 进入“管理员模式 > 设置 > 会话分配规则 > 路由规则”页签。
  2. 在“客户信息指定”栏目下,点击“添加客户信息设置”按钮。
  3. 填写规则名称,启用规则,添加客户标签,选择规则指定的机器人、技能组、客服,并保存。
  4. 重复步骤2、步骤3,创建多条客户信息指定规则。
  5. 点击客户信息指定规则右侧的排序按钮,调整规则之间的优先级顺序。


005.png


注:暂时不支持在客户信息指定规则中,将客户会话指定给未分组的客服。

设置完客户信息指定规则后,可在路由规则页签上下拖动各路由规则,调整各路由规则之间的优先级顺序。排在上方的路由规则的优先级高。 
 
支持筛选所有会话标签的叶节点

会话标签包含根节点、枝节点、叶节点三种类型。在“统计查询 > 工作量”页面选择根节点或枝节点时,会话数分布(按会话标签维度)显示该节点下所有叶节点标签的会话的总数。

新增“全选叶标签”按钮 [全选叶节点] ,支持一键选择所有会话标签的叶节点;以及“取消全选叶标签”按钮 [取消全选叶节点] ,支持一键取消选择所有会话标签的叶节点。方便企业查询叶节点标签对应的会话数分布情况。

在工作量页面,选择“筛选排序 > 指定标签”,点击“全选叶标签”按钮,选择所有会话的叶节点,并确认。会话数分布(按会话标签维度)将显示各个叶节点标签的会话数;导出报表中也包含各个叶节点标签的会话数。 
 
006.png


优化首次响应时长的计算方式

优化系统的首次响应时长的计算方式,更改为客服首条消息时间减去第一位客服的接起时间,不再包含机器人接待的会话时长。 
 
Android客服工作台

当前版本:V3.6

新功能/优化:
  • 新增告警记录功能
  • 支持显示表单消息


iOS客服工作台

当前版本:V3.0.1

新功能/优化:
  • 支持显示表单消息


iOS SDK访客端

当前版本:V1.1.6

新功能/优化:
  • 支持显示客服输入状态(增值服务)


Web插件访客端

当前版本:V47.21.1

新功能/优化:
  • 支持三方视频通话(增值服务)
  • 支持自定义满意度评价提示语


环信移动客服更新日志http://docs.easemob.com/cs/releasenote/5.30

环信移动客服登陆地址http://kefu.easemob.com/  
继续阅读 »
本次更新的主要内容为:支持客服将个人常用语提交至公共常用语,方便整个客服团队共同维护公共常用语,提升常用语维护相关的工作效率。优化实时视频功能,支持客服在会话过程中主动发起视频邀请。
客服模式

支持客服提交公共常用语

支持客服将个人常用语提交至公共常用语,方便整个客服团队共同维护公共常用语,提升常用语维护相关的工作效率。

提交个人常用语至公共常用语:
  1. 进入常用语页面,将鼠标放在个人常用语上,点击提交按钮 [提交] 。
  2. 选择公共常用语分类,确认常用语的内容(可修改),填写提交理由,并点击“提交”按钮。


客服将个人常用语提交至公共常用语后,需要管理员在“管理员模式 > 审批管理”页面,对客服的常用语申请进行审批,审批通过后,该常用语展示在公共常用语中。 
 
001.png


支持客服主动发起视频邀请

与app、网页端客户聊天过程中,客服可以主动发起视频邀请,待客户接受视频邀请后,即可开始视频聊天。

客服发起视频聊天:
  1. 在会话页面,选择客户的会话,点击输入框上方的视频按钮 [发起视频邀请] 。
  2. 等待客户接受视频邀请。


在视频通话过程中,客服还可以邀请一名客服同事加入视频,或者与客户共享桌面。

注:“实时视频”功能为增值服务,如需开通,请提供租户ID并联系环信商务经理。 
 
002.png


管理员模式

新增审批管理功能


新增审批管理功能。支持客服提交申请,由管理员统一进行审批,增强管理员对客服团队的管理能力,加强团队协作。

目前,支持客服提交个人常用语至公共常用语,由管理员进行审批。审批通过后,自动将该常用语添加至公共常用语,供所有客服使用。后续会增加更多审批功能,敬请期待。

审批管理页面分类显示所有待审批、已通过、已拒绝的审批申请,点击任意待审批的申请,可查看申请详情,并对其进行审批(通过或拒绝)。

客服提交申请后,管理员会在消息中心收到提醒;管理员完成审批后,客服可在消息中心查看审批结果。 
 
003png.png


新增调度规则设置

会话调度指会话路由至技能组后,系统将会话分配给技能组内客服的过程。调度规则包含技能组优先级属性等,由管理员设置,用于控制会话调度时分配会话的先后顺序。

新增调度规则设置,支持管理员设置5个技能组的优先级顺序,对优先级高的技能组的会话进行优先调度。并且,在调度规则中设置了优先级的技能组比剩余的其他技能组优先级高。例如:客服A同时属于技能组B和技能组C,技能组B的优先级高,则优先将技能组B的会话分配给客服A。

设置并启用调度规则:
  1. 进入“管理员模式 > 设置 > 会话分配规则 > 调度规则”页签。
  2. 在“客服接待能力分配”栏目下,点击“设置技能组优先级”按钮。
  3. 添加优先等级,并设置技能组对应的优先顺序。
  4. 打开“客服接待能力分配”开关。


注:“调度规则”功能为标准版/旗舰版增值服务,如需开通,请提供租户ID并联系环信商务经理。 
 
004.png


支持根据客户信息路由会话

路由规则新增“客户信息指定”,目前支持按照客户标签将客户会话分配至不同的客服、技能组或机器人。该路由规则可用于优先接待VIP客户,为不同类别的客户提供有区别的客户服务等。

设置客户信息指定规则:
  1. 进入“管理员模式 > 设置 > 会话分配规则 > 路由规则”页签。
  2. 在“客户信息指定”栏目下,点击“添加客户信息设置”按钮。
  3. 填写规则名称,启用规则,添加客户标签,选择规则指定的机器人、技能组、客服,并保存。
  4. 重复步骤2、步骤3,创建多条客户信息指定规则。
  5. 点击客户信息指定规则右侧的排序按钮,调整规则之间的优先级顺序。


005.png


注:暂时不支持在客户信息指定规则中,将客户会话指定给未分组的客服。

设置完客户信息指定规则后,可在路由规则页签上下拖动各路由规则,调整各路由规则之间的优先级顺序。排在上方的路由规则的优先级高。 
 
支持筛选所有会话标签的叶节点

会话标签包含根节点、枝节点、叶节点三种类型。在“统计查询 > 工作量”页面选择根节点或枝节点时,会话数分布(按会话标签维度)显示该节点下所有叶节点标签的会话的总数。

新增“全选叶标签”按钮 [全选叶节点] ,支持一键选择所有会话标签的叶节点;以及“取消全选叶标签”按钮 [取消全选叶节点] ,支持一键取消选择所有会话标签的叶节点。方便企业查询叶节点标签对应的会话数分布情况。

在工作量页面,选择“筛选排序 > 指定标签”,点击“全选叶标签”按钮,选择所有会话的叶节点,并确认。会话数分布(按会话标签维度)将显示各个叶节点标签的会话数;导出报表中也包含各个叶节点标签的会话数。 
 
006.png


优化首次响应时长的计算方式

优化系统的首次响应时长的计算方式,更改为客服首条消息时间减去第一位客服的接起时间,不再包含机器人接待的会话时长。 
 
Android客服工作台

当前版本:V3.6

新功能/优化:
  • 新增告警记录功能
  • 支持显示表单消息


iOS客服工作台

当前版本:V3.0.1

新功能/优化:
  • 支持显示表单消息


iOS SDK访客端

当前版本:V1.1.6

新功能/优化:
  • 支持显示客服输入状态(增值服务)


Web插件访客端

当前版本:V47.21.1

新功能/优化:
  • 支持三方视频通话(增值服务)
  • 支持自定义满意度评价提示语


环信移动客服更新日志http://docs.easemob.com/cs/releasenote/5.30

环信移动客服登陆地址http://kefu.easemob.com/  
收起阅读 »

基于layim+环信webim的网页即时聊天 LITE-IM

什么是LITE-IM?
LITE-IM是一款基于 环信webim3.X 和 layim 开发而成的WEB即时通讯,并且完全的免费和开源 。LITE-IM使用 拥有高并发,长连接永不掉线的即时通讯的行业领头羊环信作为通信介质,再搭配上拥有丰富前端交互的layim,让你能够快速的搭建一个现代化的、高度稳定的web即时通讯。

LITE-IM不仅能够担当客户服务来使用,还可以用作你网站粘连客户、活跃社区的媒介,提升用户的使用率。当然LITE-IM还有许多有待完善之处。

 
目前已完成的功能有:

  1. 好友/群内的文字、表情、图片、文件 在线/离线消息发送和接收。
  2. 查看群员列表。 
  3. 面板内快速查找。 
  4. 面板右键自定义事件 
  5. 修改签名 
  6. 自定义上传背景皮肤 
  7. 搜索好友/群 
  8. 添加好友/群 
  9. 新建群 
  10. 消息盒子展示
  11. 查看/修改个人信息
  12. 实时获取好友在线状态
  13. 挤下线提醒
  14. 增删改 好友/好友分组
  15. 群管理(增删管理员/修改群名片/单个群员禁言解除禁言/踢人)



部分截图如下
 
好友聊天界面


自定义上传皮肤


群组


自定义右键


消息盒子


好友


 
 LITE-IM在线体验地址:test.guoshanchina.com

体验帐号:

用户名:911088 密码:123456

用户名:1570855 密码:123456

用户名:1570845 密码:123456

用户名:911058 密码:123456

用户名:910992 密码:123456

用户名:911067 密码:123456

用户名:911100 密码:123456

用户名:911085 密码:123456



 github源码:https://github.com/shmilylbelva/webim
继续阅读 »
什么是LITE-IM?
LITE-IM是一款基于 环信webim3.X 和 layim 开发而成的WEB即时通讯,并且完全的免费和开源 。LITE-IM使用 拥有高并发,长连接永不掉线的即时通讯的行业领头羊环信作为通信介质,再搭配上拥有丰富前端交互的layim,让你能够快速的搭建一个现代化的、高度稳定的web即时通讯。

LITE-IM不仅能够担当客户服务来使用,还可以用作你网站粘连客户、活跃社区的媒介,提升用户的使用率。当然LITE-IM还有许多有待完善之处。

 
目前已完成的功能有:

  1. 好友/群内的文字、表情、图片、文件 在线/离线消息发送和接收。
  2. 查看群员列表。 
  3. 面板内快速查找。 
  4. 面板右键自定义事件 
  5. 修改签名 
  6. 自定义上传背景皮肤 
  7. 搜索好友/群 
  8. 添加好友/群 
  9. 新建群 
  10. 消息盒子展示
  11. 查看/修改个人信息
  12. 实时获取好友在线状态
  13. 挤下线提醒
  14. 增删改 好友/好友分组
  15. 群管理(增删管理员/修改群名片/单个群员禁言解除禁言/踢人)



部分截图如下
 
好友聊天界面


自定义上传皮肤


群组


自定义右键


消息盒子


好友


 
 LITE-IM在线体验地址:test.guoshanchina.com

体验帐号:

用户名:911088 密码:123456

用户名:1570855 密码:123456

用户名:1570845 密码:123456

用户名:911058 密码:123456

用户名:910992 密码:123456

用户名:911067 密码:123456

用户名:911100 密码:123456

用户名:911085 密码:123456



 github源码:https://github.com/shmilylbelva/webim 收起阅读 »

环信CEO刘俊彦直播回放:环信如何重新定义客服软件?-环信公开课第18期

11月15日,环信联合选型宝举行了环信公开课第18期,环信CEO刘俊彦讲述客户互动云的全媒体化、智能化和营销化如何在企业落地?如何重新定义客服软件?包括APP、网站、微博、微信...客户正通过各种渠道与您发生连接,作为全媒体接入的核心渠道,环信即时通讯云演化的六大场景正在如何变革引领着一个崭新的即时通讯云+时代。


微信图片_20171121165556.jpg

不能当网红的CEO做不好产品现场


刘俊彦讲到在直播公开课中讲到:“随着全媒体客服的完善以及AI的逐渐成熟, 环信预测“云通讯+服务云+智能营销”将构成从用户服务到用户营销的完整闭环。因此,2017年 ,环信整合旗下即时通信云、移动客服、智能客服机器人和主动营销产品线,推出环信CEC (Customer Engagement Cloud),向企业提供从客户互动渠道,到客户服务,到精准客户营销 的客户互动全流程解决方案。”同时,刘俊彦认为:“全媒体客服已经从传统客户服务形态的终点转化成了SaaS客户互动形态的起点,随着2017年环信CEC(客户互动云)的发布,人工智能驱动的互动中心(AI-driven Engagement Center)即将来临,整个SaaS客服行业将被重构和赋能。”


TIM截图20171121171217.png

环信客户互动云:从用户互动渠道到客户服务再到用户营销的完整闭环


 
环信CEC(客户互动云)矩阵:
  1. 全渠道客户互动:全面支持网页、微信、微博、APP/IM、工单和呼叫中心等主流客户互动渠道。其中,环信业界领先的IM长连接技术支持千万级并发,保证消息必达,助力企业打造极致的移动端客户服务体验。所有渠道支持双向互动,如主动回呼,多渠道统一推送,基于用户行为的自动营销等,真正将服务通道与营销通道融合,实现客户中心从成本中心向利润中心的升级。
  2. 视频客服:实时双向视频客服,支持Android、iOS、Pad及主流PC和手机浏览器等多平台接入,低延迟,1080P高清,支持客户端和服务器端录制,可控灵活。
  3. 全渠道客服:环信移动客服作为业内广泛使用的客户中心系统,囊括多项行业主流大奖,拥有多项国际PCT专利和国内专利,深受客户好评。环信移动客服产品成熟可靠,功能完善,全面覆盖了全渠道接入管理,客户服务与客户互动管理,运营与运维管理,工单系统,现场管理,智能报表,质检等客户中心功能。
  4. 客户声音:环信客户声音是基于人工智能和大数据挖掘的客户体验透析产品。对来自多个渠道的非结构化客服会话数据进行自然语言解析,主题聚类和情感度建模,挖掘和分析热点话题,发现服务运营问题,寻找畅销或问题产品,洞察销售机会。客户声音系统可以帮助企业识别和改善客户旅程的各个阶段。
  5. 智能客服机器人:环信智能客服机器人不仅在常见的单轮对话能力上表现优异,预装多种行业知识库,还可以快速开发多轮对话,支持人机协作以便在复杂场景下对人工客服提供全面AI辅助支持。同时,环信智能客服机器人的自动学习能力极大的降低了机器人知识库的维护成本。
  6. 精准营销及自动化营销:大数据和AI驱动的营销功能,如自动化消息模板和自动化规则管理及A/B测试,营销计划管理,基于用户行为轨迹、用户画像和用户会话内容的自动化消息和访客CTA(Call To Action)等。

 环信公开课第18期视频回放地址:https://v.qq.com/x/page/a05077ko5ly.html 
 
环信客户互动云产品试用,公开课合作请添加公开课小助手

扫码(1).gif

 
继续阅读 »
11月15日,环信联合选型宝举行了环信公开课第18期,环信CEO刘俊彦讲述客户互动云的全媒体化、智能化和营销化如何在企业落地?如何重新定义客服软件?包括APP、网站、微博、微信...客户正通过各种渠道与您发生连接,作为全媒体接入的核心渠道,环信即时通讯云演化的六大场景正在如何变革引领着一个崭新的即时通讯云+时代。


微信图片_20171121165556.jpg

不能当网红的CEO做不好产品现场


刘俊彦讲到在直播公开课中讲到:“随着全媒体客服的完善以及AI的逐渐成熟, 环信预测“云通讯+服务云+智能营销”将构成从用户服务到用户营销的完整闭环。因此,2017年 ,环信整合旗下即时通信云、移动客服、智能客服机器人和主动营销产品线,推出环信CEC (Customer Engagement Cloud),向企业提供从客户互动渠道,到客户服务,到精准客户营销 的客户互动全流程解决方案。”同时,刘俊彦认为:“全媒体客服已经从传统客户服务形态的终点转化成了SaaS客户互动形态的起点,随着2017年环信CEC(客户互动云)的发布,人工智能驱动的互动中心(AI-driven Engagement Center)即将来临,整个SaaS客服行业将被重构和赋能。”


TIM截图20171121171217.png

环信客户互动云:从用户互动渠道到客户服务再到用户营销的完整闭环


 
环信CEC(客户互动云)矩阵:
  1. 全渠道客户互动:全面支持网页、微信、微博、APP/IM、工单和呼叫中心等主流客户互动渠道。其中,环信业界领先的IM长连接技术支持千万级并发,保证消息必达,助力企业打造极致的移动端客户服务体验。所有渠道支持双向互动,如主动回呼,多渠道统一推送,基于用户行为的自动营销等,真正将服务通道与营销通道融合,实现客户中心从成本中心向利润中心的升级。
  2. 视频客服:实时双向视频客服,支持Android、iOS、Pad及主流PC和手机浏览器等多平台接入,低延迟,1080P高清,支持客户端和服务器端录制,可控灵活。
  3. 全渠道客服:环信移动客服作为业内广泛使用的客户中心系统,囊括多项行业主流大奖,拥有多项国际PCT专利和国内专利,深受客户好评。环信移动客服产品成熟可靠,功能完善,全面覆盖了全渠道接入管理,客户服务与客户互动管理,运营与运维管理,工单系统,现场管理,智能报表,质检等客户中心功能。
  4. 客户声音:环信客户声音是基于人工智能和大数据挖掘的客户体验透析产品。对来自多个渠道的非结构化客服会话数据进行自然语言解析,主题聚类和情感度建模,挖掘和分析热点话题,发现服务运营问题,寻找畅销或问题产品,洞察销售机会。客户声音系统可以帮助企业识别和改善客户旅程的各个阶段。
  5. 智能客服机器人:环信智能客服机器人不仅在常见的单轮对话能力上表现优异,预装多种行业知识库,还可以快速开发多轮对话,支持人机协作以便在复杂场景下对人工客服提供全面AI辅助支持。同时,环信智能客服机器人的自动学习能力极大的降低了机器人知识库的维护成本。
  6. 精准营销及自动化营销:大数据和AI驱动的营销功能,如自动化消息模板和自动化规则管理及A/B测试,营销计划管理,基于用户行为轨迹、用户画像和用户会话内容的自动化消息和访客CTA(Call To Action)等。

 环信公开课第18期视频回放地址:https://v.qq.com/x/page/a05077ko5ly.html 
 
环信客户互动云产品试用,公开课合作请添加公开课小助手

扫码(1).gif

  收起阅读 »

虾米音乐代码注释“穷逼VIP”,程序员出面致歉“今后我老老实实写代码,正正经经写注释”

昨日晚间,虾米音乐Mac版客户端中关于VIP会员代码的注释的图片在网上疯传,原因是里面出现了所谓的“穷逼VIP(活动送的那种)”。
v2-7a509497cec7f78b44923441a95f6b23_hd.jpg

虾米音乐程序员在代码注释中赫然将虾米音乐搞活动赠送给用户的VIP称之为“穷逼VIP”。

为与同类型的应用(QQ音乐与网易云音乐等)竞争,虾米音乐经常会推出各种领取VIP的优惠活动,用户领取后享受到的VIP内容和包月付费VIP用户没什么不同,但有时间上的限制。
 
但无论是领取了还是没领取,感谢或者觉得无所谓的虾米音乐用户们不会想到,虾米音乐程序员会简单粗暴地将这类VIP称之为“穷逼VIP”,英文名是Beggar vip(乞丐VIP)。

11月19日晚间,媒体报道虾米音乐第一时间做了复盘,替换了有问题的应用包,彻底去除了不当用语,同时修复文件混淆失效的BUG。

11月20日,虾米音乐前程序员“八座”在知乎回应致歉,并指出注释代码是自己个人行为,本意并没有任何歧视意思,只是想吐槽一些活动规则的复杂,但在吐槽中,丧失了对客户的敬畏。
111-3.png

对于这次虾米音乐程序员的做法,心大的网友调侃表示,幸好没有使用虾米音乐,躲过了“穷逼VIP”。一些网友试图从程序员的角度出发,认为这只是程序员沉闷工作下的一种寻找乐趣的手段。愤怒的网友则指责,虾米以及背后的阿里巴巴优越感很强嘛,有种就别搞任何营销活动。
继续阅读 »
昨日晚间,虾米音乐Mac版客户端中关于VIP会员代码的注释的图片在网上疯传,原因是里面出现了所谓的“穷逼VIP(活动送的那种)”。
v2-7a509497cec7f78b44923441a95f6b23_hd.jpg

虾米音乐程序员在代码注释中赫然将虾米音乐搞活动赠送给用户的VIP称之为“穷逼VIP”。

为与同类型的应用(QQ音乐与网易云音乐等)竞争,虾米音乐经常会推出各种领取VIP的优惠活动,用户领取后享受到的VIP内容和包月付费VIP用户没什么不同,但有时间上的限制。
 
但无论是领取了还是没领取,感谢或者觉得无所谓的虾米音乐用户们不会想到,虾米音乐程序员会简单粗暴地将这类VIP称之为“穷逼VIP”,英文名是Beggar vip(乞丐VIP)。

11月19日晚间,媒体报道虾米音乐第一时间做了复盘,替换了有问题的应用包,彻底去除了不当用语,同时修复文件混淆失效的BUG。

11月20日,虾米音乐前程序员“八座”在知乎回应致歉,并指出注释代码是自己个人行为,本意并没有任何歧视意思,只是想吐槽一些活动规则的复杂,但在吐槽中,丧失了对客户的敬畏。
111-3.png

对于这次虾米音乐程序员的做法,心大的网友调侃表示,幸好没有使用虾米音乐,躲过了“穷逼VIP”。一些网友试图从程序员的角度出发,认为这只是程序员沉闷工作下的一种寻找乐趣的手段。愤怒的网友则指责,虾米以及背后的阿里巴巴优越感很强嘛,有种就别搞任何营销活动。 收起阅读 »

基于环信webIM提供的Demo改造

本效果图是基于webIM的demo版本修改,主要实现了以下功能
1.实现自动登录,到聊天窗口
    解决办法:是在页面自己写参数调用 Demo.conn.open(options) 方法

2.实现最近联系人列表渲染(因为我们没有好友概念,只要跟谁最近聊天了,就算是好友了)
    解决办法:在页面通过ajax调用后台restFul地址获取联系人,然后循环调用 Demo.conn.onTextMessage(msg)方法,将消息内容为空,在msg里面设置标识为初始化加载,这样就会出现在列表里面

3.实现联系人:头像、昵称 渲染
   解决办法:很简单就是在刚才上面的方法体里面调用完之后,你的列表就会出现好友列表,这时候你只需要根据环信用户id,直接基于jq替换即可

4.实现点击联系人 渲染历史聊天记录(在发送消息的时候将聊天记录保存在我们自己的数据库)
   解决办法:在你获取最近联系人这个方法时已经返回了聊天记录列表,你需要在(Demo.chatRecord.环信用户id.messages)这个数组里面把你的消息放在这个数据里面去,然后当用户点击联系人列表时你jq写一个(webim-contact-item)这个样式的click触发方法,在这个方法中你需要写把聊天记录从(Demo.chatRecord.环信用户id.messages) 循环取出来,包装成HTML然后在  $("#wrapper"+Demo.selected).append() 这些HTML即可

5.实现保存聊天
    解决办法:就是在 sendTxt里面调用我们的ajax方法保存
大致就这么多,个人不建议基于官方的webIM的Demo 去修改,这次踩过这个坑了

欢迎各位 集成的朋友来访,目前我这个算是解决,等过段时间我还是自己写一个吧,不打算基于他们的Demo去改造
在此欢迎去我的博客:   www.kaven.cn
继续阅读 »
本效果图是基于webIM的demo版本修改,主要实现了以下功能
1.实现自动登录,到聊天窗口
    解决办法:是在页面自己写参数调用 Demo.conn.open(options) 方法

2.实现最近联系人列表渲染(因为我们没有好友概念,只要跟谁最近聊天了,就算是好友了)
    解决办法:在页面通过ajax调用后台restFul地址获取联系人,然后循环调用 Demo.conn.onTextMessage(msg)方法,将消息内容为空,在msg里面设置标识为初始化加载,这样就会出现在列表里面

3.实现联系人:头像、昵称 渲染
   解决办法:很简单就是在刚才上面的方法体里面调用完之后,你的列表就会出现好友列表,这时候你只需要根据环信用户id,直接基于jq替换即可

4.实现点击联系人 渲染历史聊天记录(在发送消息的时候将聊天记录保存在我们自己的数据库)
   解决办法:在你获取最近联系人这个方法时已经返回了聊天记录列表,你需要在(Demo.chatRecord.环信用户id.messages)这个数组里面把你的消息放在这个数据里面去,然后当用户点击联系人列表时你jq写一个(webim-contact-item)这个样式的click触发方法,在这个方法中你需要写把聊天记录从(Demo.chatRecord.环信用户id.messages) 循环取出来,包装成HTML然后在  $("#wrapper"+Demo.selected).append() 这些HTML即可

5.实现保存聊天
    解决办法:就是在 sendTxt里面调用我们的ajax方法保存
大致就这么多,个人不建议基于官方的webIM的Demo 去修改,这次踩过这个坑了

欢迎各位 集成的朋友来访,目前我这个算是解决,等过段时间我还是自己写一个吧,不打算基于他们的Demo去改造
在此欢迎去我的博客:   www.kaven.cn 收起阅读 »

中国移动“一起创未来”互联网创客马拉松大赛

malasong.jpg

为鼓励移动互联网创新,中国移动举办“一起创未来”互联网创客马拉松大赛。
大赛面向开发者、高新企业、高校学生征集Android等优秀应用产品或创意方案。
优秀团队有机会获得高额赛事奖金、平台推广资源、资深导师指导、创业风投机会等丰厚激励。


大赛日程: 2017年12月2日截至报名。2017年12月5日进行总评审。
大赛共设六个系列专项奖,其中融合通信三个专项赛(智能短信、通话秀、负一屏应用)总奖金200多万;跨专项奖可同时获奖,奖金叠加。
  注:参赛作品必须使用中国移动互联网能力平台统一认证能力,鼓励创造性和前瞻性的开发思路。相关奖项如未达到评委评审要求,可轮空。详细信息请查看中移互联网马拉松创客大赛
继续阅读 »
malasong.jpg

为鼓励移动互联网创新,中国移动举办“一起创未来”互联网创客马拉松大赛。
大赛面向开发者、高新企业、高校学生征集Android等优秀应用产品或创意方案。
优秀团队有机会获得高额赛事奖金、平台推广资源、资深导师指导、创业风投机会等丰厚激励。


大赛日程: 2017年12月2日截至报名。2017年12月5日进行总评审。
大赛共设六个系列专项奖,其中融合通信三个专项赛(智能短信、通话秀、负一屏应用)总奖金200多万;跨专项奖可同时获奖,奖金叠加。
  注:参赛作品必须使用中国移动互联网能力平台统一认证能力,鼓励创造性和前瞻性的开发思路。相关奖项如未达到评委评审要求,可轮空。详细信息请查看中移互联网马拉松创客大赛 收起阅读 »