iOS 环信 集成 详细步骤图文

iOS 环信 集成 详细步骤图文

6
评论

【开源OA项目】基于环信IM开发完整的企业通讯解决方案-Dolores Dolores OA 开源项目

KevinGong 发表了文章 • 7445 次浏览 • 2017-06-26 10:53 • 来自相关话题

  

  前阵子钉钉在微信楼下刷了一波#创业很苦,坚持很酷#的广告,浓浓的“丧”文化风格文案受到了各界褒贬不一的评价,也引起了大家对OA办公系统的关注。
   对企业而言,初选OA办公系统是为了满足需求,解决当下问题,由于OA办公系统的在公司运作流程中扮演的重要性,安全与隐私等问题急需未雨绸缪,“可定制”、“可私有化部署”的OA办公系统成为了更多企业的首选。公司想自己开发一套IM系统应该从哪里开始呢? 企业通讯录怎么保持同步呢? 企业通讯录的权限管理应该怎么做?
   三个关于OA办公系统的究极问题,从开源的OA办公项目-Dolores(朵拉)诞生迎刃而解了。Dolores项目遵循Apache Licence 2.0 开源协议,可以直接拿来用,也可以修改代码来满足需要并作为开源或商业产品发布/销售。




关于Dolores?
Dolores是一套完整的企业通信解决方案,一个完整的企业沟通工具(以下简称企业IM),支持以下几个功能:IM消息服务、组织架构管理、工作流集成。
Dolores项目源码地址:https://github.com/DoloresTeam​ 
技术讨论群:641256202(QQ群)

整个解决方案都包括了什么?
企业通讯录的管理:部门/员工的增删改查通讯录全量更新:全量/增量更新 企业通讯录权限管理:基于RBAC权限管理模型企业即时通讯IM:企业通信对IM这块的可靠性要求高,选择了目前比较成熟的IM云服务厂商-环信
 
 
组织架构

企业通讯录可以说是企业沟通中最重的业务之一,能够提供员工各种服务的认证,获取员工的联系方式等。
 
组织架构-Server

服务端主要包括以下功能:
支持管理人员(例如HR)对部门和员工进行增删改查支持部门和员工自定义排序,自定义元信息存储权限管理员工通讯录视图 (员工根据自己的权限生成通讯录)通讯录增量更新 (鉴于移动端特殊的网络环境和设备,通讯录应该支持差量更新)集成 IM 用户系统

在这里我们主要讨论以下两个问题:
 
权限管理

  随着企业逐渐的发展,团队壮大为了更有效的沟通,以及保护公司内部的一些商业信息不被泄漏,我们应该为通讯录添加权限管理。

基于Role-based access control(RBAC)的权限管理模型

为了介绍此权限管理模型,我们先解释一下基本概念
角色:通常是指企业中某一个工作岗位,这个岗位具有特定的权利和职责。被赋予此角色的员工,将获得这种权利与职责权限:被赋予访问实体的权利。在本项目中是指访问部门和访问某一个或者某一类员工的权利用户-角色分配(User-Role Assignment URA):为某个用户指定一个或者多个角色,此员工将获得这些角色所具有权利的集合角色-权限分配(Role-Permission Assignment RPA):将权限分配给角色,一个角色可以包含多个权利。在本项目中是指多个访问部门和访问员工的权限

在用户和权限之间引入角色中介,将用户与权限的直接关系弱化为间接关系。|ˉˉˉ| |ˉˉ ˉ| |ˉˉˉˉ ˉˉ|
| User |---URA---> | Role |<---RPA---| Permission |
|______| |_______| |_____________|
    以角色为中介,首先创建访问每个部门和员工的访问权限,然后创建不同的角色,根据这些角色的职责不同分配不同的权限,建立角色-权限的关系以后,不同的角色将会有不同的权限。根据员工不同的岗位,将对应的角色分配给他们,建立用户-角色关系,这就是RBAC的主要思想。

一个员工可以用户多个角色,一个角色可以用于多个访问权限。RBAC 极大的简化了员工的授权管理。

   由于企业的部门和员工数量很多,在创建权限时管理员不可能去设置每一个权限可以访问的每一个部门和每一个员工。所以本项目将功能和指责类似的部门和员工看作是同一类型,在创建部门和员工的时候为每一个部门和员工分配固有属性type,管理员在设置权限规则的时候只需要指定可访问的部门类型和员工即可。

增量更新

   鉴于移动终端计算资源有限,如网络,存储,电量等,所以通讯录的更新技术应该保证尽量少的资源。另外由于通讯录的特殊性,通讯录的变化需要能实时通知到受影响的在线员工。

基于版本号与变更日志的增量更新模型

   客户端第一次登陆系统以后,我们根据当前登录角色生成对应的通讯录视图,并以当前时间戳作为版本号,返回给客户端。客户端后续通过此版本号增量更新通讯录。

版本号

   版本号有两种:一是客户端当前通讯录版本 c-version, 二是服务端通讯录每一次变化时的版本号s-version

变更日志

   在管理员修改权限规则,或者修改某个岗位的访问规则时会影响大面积员工的通讯录视图,此时如果用增量更新会导致服务器流量异常,因此在这2中情况会清空原来的变更日志并且要求客户端进行一次全量更新。

   如果管理员新增了员工,服务端会根据被修改的员工或者部门type, 反推出所有受影响的员工,然后生成一条变更日志, 例如:{
"content" : [
{
"cn" : "Lucy.Liu",
"id" : "b4vlfg91scgi1dcju8v0",
"title" : "市场运营负责人",
"email" : [
"lucy.liu@dolores.store"
],
"priority" : "101111",
"name" : "刘小飞",
"telephoneNumber" : "18888888888"
}
],
"createTimestamp" : "20170614063303Z",
"category" : "member",
"action" : "add"
}
客户端在请求增量更新的时候,通过当前登陆ID与版本号,可查找出所有与自己相关的变更日志,然后在客户端数据库中应用这些变更,即可完成同步。

组织架构-Client

   由于现在员工办公设备的多样性,客户端要根据自己公司的情况,覆盖的足够完整,常见的平台有 iOS Android windowsmac linux , 对于后三个平台可以用 Web APP 来覆盖,iOS&Android 用原生的app来提升用户体验。

客户端App主要包括以下功能:
会话列表优秀的聊天界面,历史记录组织机构全量/增量更新员工个人资料展示

客户端数据库设计

IM数据库设计
 
当前版本使用环信SDK
 
组织架构数据库设计

表设计

客户端组织架构较服务端简单,不关联用户Role,客户端本地存储Staff(员工)和Department(部门)信息:
一个部门可以包含相关子部门和部门员工。该部门员工和部门在视图上处于同级关系。员工隶属于部门,同一员工可以存在于多个部门。员工角色用title来表示。

用户在登录客户端成功后,会根据该用户信息创建用户对应的数据库文件,用户表(User)保存用户相关信息,关联该用户staff信息。

客户端组织架构同服务端逻辑。

工作流集成

(TODO)
 
如何使用Dolores

本项目现在已经完成了第一个测试版本,本小节将指导您如何安装使用。

后端数据库

鉴于通讯录对数据库操作的特点多度少写,以及部门之间的树状关系,我们选择LDAP协议来存取数据。

我们有独立的repo来帮助您完成数据库的安装与初始化。请移步这里

组织架构管理

Dolores 初始版本使用Golang实现,大家既可以下载各个平台的可执行包,也可以安装Go语言的开发环境自己编译。

我们有独立的repo来帮助您,运行后端服务。请移步这里

客户端

我们现在有提供一个iOS版的Demo。请移步这里

Done

如果您顺利的完成以上三步,访问 http://localhost:3280 (端口号根据自己的配置,可能会有差异),使用 username: admin, password: dolores 登陆后端管理页面,添加权限规则,添加角色,添加员工、部门,然后使用iOS客户端登陆,就可以愉快的开始聊天啦~
 
负载均衡

(TODO)

多机容灾

(TODO)

LICENSE Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
更多信息请前往github项目主页

 
这里我对每个repo做一个简单的介绍


Dolores: 项目简介, 整个项目的架构, 数据库设计等等 你想了解的一切都可以在这里看到
dolores-ios: iOS版demo,可以聊天查看组织架构
dolores-android: 哈哈 还没有,当然我们欢迎各路安卓大牛贡献安卓版demo
organization: 组织架构的创建管理、更新、审计等等核心的东西都在这里啦
dolores-server: 为客户端提供restfull api 与环信服务器集成
dolores-admin: 后台管理网站,用于管理部门员工。一个基于React的webapp还很基础,欢迎各位大牛pr.
dolores-ldap-init: 后台数据库的初始化工具,详情可以查看readme
easemob-resty:对环信rest api的封装,让调用环信api更简单
dolores-avatar:生成类似钉钉那样的默认头像


最后再说一点整个服务端是用go来写的,作者也是golang的初学者,如果代码哪里写的有问题或者架构有问题欢迎大家指正THE CALM BEFORE THE STORM.
暴风雨前的宁静
ONE MORE THING 最后附上Dolores项目LOGO
当时作者正在二刷 《西部世界》这部剧,所以选择了女主的名字dolores作为整个项目的名字,而这个logo则寓意剧中的host。 查看全部
  

  前阵子钉钉在微信楼下刷了一波#创业很苦,坚持很酷#的广告,浓浓的“丧”文化风格文案受到了各界褒贬不一的评价,也引起了大家对OA办公系统的关注。
   对企业而言,初选OA办公系统是为了满足需求,解决当下问题,由于OA办公系统的在公司运作流程中扮演的重要性,安全与隐私等问题急需未雨绸缪,“可定制”、“可私有化部署”的OA办公系统成为了更多企业的首选。
公司想自己开发一套IM系统应该从哪里开始呢? 企业通讯录怎么保持同步呢? 企业通讯录的权限管理应该怎么做?

   三个关于OA办公系统的究极问题,从开源的OA办公项目-Dolores(朵拉)诞生迎刃而解了。Dolores项目遵循Apache Licence 2.0 开源协议,可以直接拿来用,也可以修改代码来满足需要并作为开源或商业产品发布/销售。
OA广告图.jpg

关于Dolores?

Dolores是一套完整的企业通信解决方案,一个完整的企业沟通工具(以下简称企业IM),支持以下几个功能:IM消息服务、组织架构管理、工作流集成。


Dolores项目源码地址:https://github.com/DoloresTeam​ 
技术讨论群:641256202(QQ群)

整个解决方案都包括了什么?
  • 企业通讯录的管理:部门/员工的增删改查
  • 通讯录全量更新:全量/增量更新 
  • 企业通讯录权限管理:基于RBAC权限管理模型
  • 企业即时通讯IM:企业通信对IM这块的可靠性要求高,选择了目前比较成熟的IM云服务厂商-环信

 
 
组织架构

企业通讯录可以说是企业沟通中最重的业务之一,能够提供员工各种服务的认证,获取员工的联系方式等。
 
组织架构-Server

服务端主要包括以下功能:
  1. 支持管理人员(例如HR)对部门和员工进行增删改查
  2. 支持部门和员工自定义排序,自定义元信息存储
  3. 权限管理
  4. 员工通讯录视图 (员工根据自己的权限生成通讯录)
  5. 通讯录增量更新 (鉴于移动端特殊的网络环境和设备,通讯录应该支持差量更新)
  6. 集成 IM 用户系统


在这里我们主要讨论以下两个问题:
 
权限管理

  随着企业逐渐的发展,团队壮大为了更有效的沟通,以及保护公司内部的一些商业信息不被泄漏,我们应该为通讯录添加权限管理。

基于Role-based access control(RBAC)的权限管理模型

为了介绍此权限管理模型,我们先解释一下基本概念
  • 角色:通常是指企业中某一个工作岗位,这个岗位具有特定的权利和职责。被赋予此角色的员工,将获得这种权利与职责
  • 权限:被赋予访问实体的权利。在本项目中是指访问部门和访问某一个或者某一类员工的权利
  • 用户-角色分配(User-Role Assignment URA):为某个用户指定一个或者多个角色,此员工将获得这些角色所具有权利的集合
  • 角色-权限分配(Role-Permission Assignment RPA):将权限分配给角色,一个角色可以包含多个权利。在本项目中是指多个访问部门和访问员工的权限


在用户和权限之间引入角色中介,将用户与权限的直接关系弱化为间接关系。
|ˉˉˉ|           |ˉˉ ˉ|          |ˉˉˉˉ ˉˉ|  
| User |---URA---> | Role |<---RPA---| Permission |
|______| |_______| |_____________|

    以角色为中介,首先创建访问每个部门和员工的访问权限,然后创建不同的角色,根据这些角色的职责不同分配不同的权限,建立角色-权限的关系以后,不同的角色将会有不同的权限。根据员工不同的岗位,将对应的角色分配给他们,建立用户-角色关系,这就是RBAC的主要思想。

一个员工可以用户多个角色,一个角色可以用于多个访问权限。RBAC 极大的简化了员工的授权管理。

   由于企业的部门和员工数量很多,在创建权限时管理员不可能去设置每一个权限可以访问的每一个部门和每一个员工。所以本项目将功能和指责类似的部门和员工看作是同一类型,在创建部门和员工的时候为每一个部门和员工分配固有属性type,管理员在设置权限规则的时候只需要指定可访问的部门类型和员工即可。

增量更新

   鉴于移动终端计算资源有限,如网络,存储,电量等,所以通讯录的更新技术应该保证尽量少的资源。另外由于通讯录的特殊性,通讯录的变化需要能实时通知到受影响的在线员工。

基于版本号与变更日志的增量更新模型

   客户端第一次登陆系统以后,我们根据当前登录角色生成对应的通讯录视图,并以当前时间戳作为版本号,返回给客户端。客户端后续通过此版本号增量更新通讯录。

版本号

   版本号有两种:一是客户端当前通讯录版本 c-version, 二是服务端通讯录每一次变化时的版本号s-version

变更日志

   在管理员修改权限规则,或者修改某个岗位的访问规则时会影响大面积员工的通讯录视图,此时如果用增量更新会导致服务器流量异常,因此在这2中情况会清空原来的变更日志并且要求客户端进行一次全量更新。

   如果管理员新增了员工,服务端会根据被修改的员工或者部门type, 反推出所有受影响的员工,然后生成一条变更日志, 例如:
{
"content" : [
{
"cn" : "Lucy.Liu",
"id" : "b4vlfg91scgi1dcju8v0",
"title" : "市场运营负责人",
"email" : [
"lucy.liu@dolores.store"
],
"priority" : "101111",
"name" : "刘小飞",
"telephoneNumber" : "18888888888"
}
],
"createTimestamp" : "20170614063303Z",
"category" : "member",
"action" : "add"
}

客户端在请求增量更新的时候,通过当前登陆ID与版本号,可查找出所有与自己相关的变更日志,然后在客户端数据库中应用这些变更,即可完成同步。

组织架构-Client

   由于现在员工办公设备的多样性,客户端要根据自己公司的情况,覆盖的足够完整,常见的平台有 iOS Android windowsmac linux , 对于后三个平台可以用 Web APP 来覆盖,iOS&Android 用原生的app来提升用户体验。

客户端App主要包括以下功能:
  1. 会话列表
  2. 优秀的聊天界面,历史记录
  3. 组织机构全量/增量更新
  4. 员工个人资料展示


客户端数据库设计

IM数据库设计
 
当前版本使用环信SDK
 
组织架构数据库设计

表设计

客户端组织架构较服务端简单,不关联用户Role,客户端本地存储Staff(员工)和Department(部门)信息:
  • 一个部门可以包含相关子部门和部门员工。该部门员工和部门在视图上处于同级关系。
  • 员工隶属于部门,同一员工可以存在于多个部门。
  • 员工角色用title来表示。


用户在登录客户端成功后,会根据该用户信息创建用户对应的数据库文件,用户表(User)保存用户相关信息,关联该用户staff信息。

客户端组织架构同服务端逻辑。

工作流集成

(TODO)
 
如何使用Dolores

本项目现在已经完成了第一个测试版本,本小节将指导您如何安装使用。

后端数据库

鉴于通讯录对数据库操作的特点多度少写,以及部门之间的树状关系,我们选择LDAP协议来存取数据。

我们有独立的repo来帮助您完成数据库的安装与初始化。请移步这里

组织架构管理

Dolores 初始版本使用Golang实现,大家既可以下载各个平台的可执行包,也可以安装Go语言的开发环境自己编译。

我们有独立的repo来帮助您,运行后端服务。请移步这里

客户端

我们现在有提供一个iOS版的Demo。请移步这里

Done

如果您顺利的完成以上三步,访问 http://localhost:3280 (端口号根据自己的配置,可能会有差异),使用 username: admin, password: dolores 登陆后端管理页面,添加权限规则,添加角色,添加员工、部门,然后使用iOS客户端登陆,就可以愉快的开始聊天啦~
 
负载均衡

(TODO)

多机容灾

(TODO)

LICENSE
 Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

更多信息请前往github项目主页

 
这里我对每个repo做一个简单的介绍


Dolores: 项目简介, 整个项目的架构, 数据库设计等等 你想了解的一切都可以在这里看到
dolores-ios: iOS版demo,可以聊天查看组织架构
dolores-android: 哈哈 还没有,当然我们欢迎各路安卓大牛贡献安卓版demo
organization: 组织架构的创建管理、更新、审计等等核心的东西都在这里啦
dolores-server: 为客户端提供restfull api 与环信服务器集成
dolores-admin: 后台管理网站,用于管理部门员工。一个基于React的webapp还很基础,欢迎各位大牛pr.
dolores-ldap-init: 后台数据库的初始化工具,详情可以查看readme
easemob-resty:对环信rest api的封装,让调用环信api更简单
dolores-avatar:生成类似钉钉那样的默认头像


最后再说一点整个服务端是用go来写的,作者也是golang的初学者,如果代码哪里写的有问题或者架构有问题欢迎大家指正
THE CALM BEFORE THE STORM.
暴风雨前的宁静

ONE MORE THING 最后附上Dolores项目LOGO
当时作者正在二刷 《西部世界》这部剧,所以选择了女主的名字dolores作为整个项目的名字,而这个logo则寓意剧中的host。
687474703a2f2f6f7131696e636b76692e626b742e636c6f7564646e2e636f6d2f646f6c6f726573313032342e706e67.png
6
评论

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

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

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

 
Android篇

昵称头像篇

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

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

 
开源项目

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

【视频教程+源码】基于环信IM做一个仿微信APP-更新ing 郭永峰 高仿微信 仿微信 环信 XMPP

郭永峰 发表了文章 • 9708 次浏览 • 2017-05-16 15:29 • 来自相关话题

我只是一个普通人,做人要谦虚。
我不是大神,我也不是很厉害的。
天外有天,人外有人。
老师引入门,修行靠个人。
希望能帮助大家,谢谢。
    大家好,我是郭永峰(峰哥) | 一个普通大学计算机系毕业的大学生,曾就职于澳门遊澳集团有限公司,负责大型银联支付业务系统、跨国际短信业务系统(基于电信的SGIP)以及集团内部通讯系统 (负责android和openfire后台二次开发)的主要开发任务,担任项目负责人。13年就职于广州拓谷科技有限公司负责“酷蛙”车联网产品研发及汽车销售产品研发。14来年到17年2月份,就职于国内知名教育机构,负责教学研发及授课的工作。
 
本人现状况:
  
   在家录制教学视频(无收入),搞工作室,组建团队成立公司,如果大家觉得分享内容很喜欢,可以给我打点赏支持本人的工作室,二维码在文末,就不影响阅读了。

 
郭永峰IT教育工作室于2017年4月12日成立!
 
成立原因:

希望把近10年来从事IT互联网的知识分享给大家,包括Linux,WindowServer,Java,PHP,Android,iOS,H5等等等。
 

进入正题,本套课程基于环信IM教大家如何做一个类似微信的APP,只用于技术交流,请勿用于任何商业用途。
4月12号成立工作室,现在18号,过了一个星期一个星期录了5天的环信教程视频,我将放在网盘免费分享环信的教程视频主要是针对有开发经验者教程主要是使用环信来模仿微信来做一个即时通讯的案例课程主要是先讲socket基础 -> 环信 ->自定义协议希望这些教程视频能帮助大家,对即时通讯、socket和自定义协议有个较深入的了解同时能希望大家在面试时,在即时通讯这块不在陌生
  持续更新

第一阶段:即时通讯的了解和微信APP开发前的准备!

【视频教程+源码】基于环信IM做一个仿微信APP-01.即时通讯简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-02.XMPP简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-03.XMPP实现即时通信的准备工作(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-04.环信简介(了解) 

【视频教程+源码】基于环信IM做一个仿微信APP-05.集成环信的前提准备(掌握)
 
【视频教程+源码】基于环信IM做一个仿微信APP-06.环信SDK的版本的区别(掌握)

【视频教程+源码】基于环信IM做一个仿微信APP-07.微信-项目创建及代码目录结构规范(MVC)

【视频教程+源码】基于环信IM做一个仿微信APP-08.微信-集成环信SDK

【视频教程+源码】基于环信IM做一个仿微信APP-09.微信-登录界面排版

【视频教程+源码】基于环信IM做一个仿微信APP-10.微信-主界面搭建

【视频教程+源码】基于环信IM做一个仿微信APP-11.微信-注册功能

【视频教程+源码】基于环信IM做一个仿微信APP- 12.微信-登录功能

【视频教程+源码】基于环信IM做一个仿微信APP- 13.微信-自动登录

【视频教程+源码】基于环信IM做一个仿微信APP- 14.微信-主动退出
 
【视频教程+源码】基于环信IM做一个仿微信APP-15.微信-在其它设备登录
 
整个项目源码,git地址https://github.com/mayaole/fWeiXin

 微信打赏






支付宝打赏






谢谢大家的支持,个人微信号清扫描下面张图






 
郭永峰IT交流QQ群请加:596441895 查看全部
我只是一个普通人,做人要谦虚。
我不是大神,我也不是很厉害的。
天外有天,人外有人。
老师引入门,修行靠个人。
希望能帮助大家,谢谢。

    大家好,我是郭永峰(峰哥) | 一个普通大学计算机系毕业的大学生,曾就职于澳门遊澳集团有限公司,负责大型银联支付业务系统、跨国际短信业务系统(基于电信的SGIP)以及集团内部通讯系统 (负责android和openfire后台二次开发)的主要开发任务,担任项目负责人。13年就职于广州拓谷科技有限公司负责“酷蛙”车联网产品研发及汽车销售产品研发。14来年到17年2月份,就职于国内知名教育机构,负责教学研发及授课的工作。
 
本人现状况:
  
   在家录制教学视频(无收入),搞工作室,组建团队成立公司,如果大家觉得分享内容很喜欢,可以给我打点赏支持本人的工作室,二维码在文末,就不影响阅读了。

 
郭永峰IT教育工作室于2017年4月12日成立!
 
成立原因:

希望把近10年来从事IT互联网的知识分享给大家,包括Linux,WindowServer,Java,PHP,Android,iOS,H5等等等。
 

进入正题,本套课程基于环信IM教大家如何做一个类似微信的APP,只用于技术交流,请勿用于任何商业用途。
  1. 4月12号成立工作室,现在18号,过了一个星期
  2. 一个星期录了5天的环信教程视频,我将放在网盘免费分享
  3. 环信的教程视频主要是针对有开发经验者
  4. 教程主要是使用环信来模仿微信来做一个即时通讯的案例
  5. 课程主要是先讲socket基础 -> 环信 ->自定义协议
  6. 希望这些教程视频能帮助大家,对即时通讯、socket和自定义协议有个较深入的了解
  7. 同时能希望大家在面试时,在即时通讯这块不在陌生

  持续更新

第一阶段:即时通讯的了解和微信APP开发前的准备!

【视频教程+源码】基于环信IM做一个仿微信APP-01.即时通讯简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-02.XMPP简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-03.XMPP实现即时通信的准备工作(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-04.环信简介(了解) 

【视频教程+源码】基于环信IM做一个仿微信APP-05.集成环信的前提准备(掌握)
 
【视频教程+源码】基于环信IM做一个仿微信APP-06.环信SDK的版本的区别(掌握)

【视频教程+源码】基于环信IM做一个仿微信APP-07.微信-项目创建及代码目录结构规范(MVC)

【视频教程+源码】基于环信IM做一个仿微信APP-08.微信-集成环信SDK

【视频教程+源码】基于环信IM做一个仿微信APP-09.微信-登录界面排版

【视频教程+源码】基于环信IM做一个仿微信APP-10.微信-主界面搭建

【视频教程+源码】基于环信IM做一个仿微信APP-11.微信-注册功能

【视频教程+源码】基于环信IM做一个仿微信APP- 12.微信-登录功能

【视频教程+源码】基于环信IM做一个仿微信APP- 13.微信-自动登录

【视频教程+源码】基于环信IM做一个仿微信APP- 14.微信-主动退出
 
【视频教程+源码】基于环信IM做一个仿微信APP-15.微信-在其它设备登录
 
整个项目源码,git地址https://github.com/mayaole/fWeiXin

 微信打赏

微信.png


支付宝打赏

支付宝.png


谢谢大家的支持,个人微信号清扫描下面张图

个人.png


 
郭永峰IT交流QQ群请加:596441895
0
评论

iOS 环信 集成 详细步骤图文 iOS 环信 集成 详细步骤图文

神的传说 发表了文章 • 737 次浏览 • 2017-01-11 13:26 • 来自相关话题

环信的教程:

没有初始化SDK  

去AppDelegate里面初始化

 

密码

 

User not exist         ??????????

每一个应用都有自己的注册用户  去你的后台管理   去看你的注册的用户数   

为什么demo的可以跑起来????????

是在它的应用下注册的

 

怎么去注册用户  -注册用户

用户名字可以相同   不同的应用   

 

 

那个打印的loginInfo 是这个字典的也就是用户的登录信息

 

你会发现打印的loginInfo上面还有一坨恶心的东西,那个是环信SDK自己打印的日志信息

 

SEND   和      RECV    使用的是XMPP协议    所以 数据的格式是XML   一般的HTTP协议的话他就是JSON格式的

这个是app把客户端登录的信息发给环信服务器后打印出来的日志      是不是很烦

 

如何去在哪儿隐藏它的控制台的日志信息 ?????????

去初始化的时候把它隐藏  有一个otherConfig的东西   右键-jump to Define

进去瞅瞅--

复制它的key 给他设置为NO

这个时候它的控制台的日志信息就被屏蔽了

 

 

跟环信交互的所有类都有这个

[EaseMob sharedInstance].chatManager

 

 

注册的时候代码:


如果你把这onQueue改为nil的话他默认也是在主线程的

 

然后你在去环信的开发中心刷新IM用户 你会发现他多了一个

发送给的数据给服务器的时候还是XML格式,里面的SDK帮你封装了,不用你自己去接触

 

 

---自动登录------------------------------------

 

看到它的主界面只有三个tabbar

 进去 mainstoryboard里面 删除原始的viewcontroller  拖入一个 tabbarController     去掉原始的tabbar 的两个子控制器   记得给它的isinitial 那个选项钩上   然后拖入三个navigationcontroller(这个根据你的界面而定)

 

选中给每个的Item  的title属性可以更改

然后在登录成功中写上加载storyboard的方法

你会发现你已经跳转进去
如何实现自动登录?????????????????

  实现原理:把你的登录信息保存在沙盒中     程序启动时候发送登录请求

  只要你在第一次登录成功后发送环信自带登录的网络请求去实现、

环信自己帮你实现上面的东西

 

具体实现

在登录成功的下面写上

[[EaseMob sharedInstance].chatManager  setIsAutoLoginEnabled:YES]

然后去在AppDelegte里面把他的沙盒路径拿到
然后再控制台你可以看到这些信息,其中的账号密码信息你会发现他被加密了,有没有?
如何监听是否是已经处于登录状态了这个地方有个代理  环信的代理方法

在AppDelegate方法里面进去 在启动方法里面写
你会发现它的那个啥没有完成界面的跳转    但是控制台却是带那个登陆成功了
这个时候我们还缺一步骤  之前我们在自动登录时候我们调用的是set方法

这个时候我们要实现它的 get方法     写在监听登录状态的下面

  //如果登录过直接来到主界面
    if([[EaseMob sharedInstance].chatManager isAutoLoginEnabled]){

        self.window.rootViewController = [UIStoryboard storyboardWithName:@"Main" bundle:nil].instantiateInitialViewController;

    }

    
=------------自动连接--------------------------

 

网络通不通的时候类似微信那种网络不通的实现

去那个main.storyboard里面把那会话的导航控制器跳转的那个类继承改为你自己创建的那个UItableViewController

 

1.在会话里面监听的网络的状态  环信的有很多个代理

去那个.m文件里面去实现
点击那个EMChatManagerDelegate 里面去实现 EMChatManagerUtilDelegate里面的这个方法就OK了

- (void)didConnectionStateChanged:(EMConnectionState)connectionState;
在真机上面测试的时候 网络连接成功不代表客户端和服务器端连接成功

 

 

还有自动连接的状态的监听 也是加上他的代理方法就行了


--------添加好友请求-----------------------------

1.是用环信的思想

 所有的网络请求   [EaseMob sharedInstance].chatManager 由这个管理器发起的

 

2.所有结果(自动登录 自动连接)通过代理来回调完成

[EaseMob sharedInstance].chatManager的addDelegate来完成

 

3.EMChatManagerBuddyDelegate 这个代理实现了对用户的基本操作

1.添加好友      2.从本地获取好友      3.从服务器列表获取最新的好友     4.接受好友添加请求

5.删除好友       6.被好友从名单上面删除  

 

 

在navigation  的第二个控制器上面加上一个UIbarbarItem   选择自定义   然后+    

再去创建一个UIviewController     然后再去实现用个+号去拖一个线  

 

 可以在上面加上navigationItem 上改为添加好友

再去新建一个控制器AdressBooking 通讯录  这个类是继承于UIviewController
是用环信最简单的方法 ,把官方的Demo直接拿过来用   直接跟改它的Appdelegate里面的APPKey

这样你就收到了申请    注意   这是最简单的方式

 

 

还有一点 你要在每个控制器里面写上你环信的代理方法

这样就能保证你下面写的环信 的每一个方法会被自动调用了
代理方法:

代理的销毁

 

 

好友请求消息反馈写在什么地方   因为你进去那个会话的控制器里面了的话就会被销毁了。我们可以把它的好友请求写在会话控制器   这样他每个控制器都可以收到了  也没有必要写在AppDelegate里面 可以去尝试一下

 

 

 

 

 

 

 

 

 

 

---------现实好友界面列表------------------

1.新建一个tableViewcontroller  修改那个tableView的继承

 

2.给他的cell添加一个Identifier     
下面打印的就是他的好友列表

 

 

#pragma mark - Tableview datasource

 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return self.buddyList.count;

}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *ID = @"BuddyCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    //获取好友列表名称  EMBuddy是环信封装的好友模型

    EMBuddy *buddy = self.buddyList[indexPath.row];

    //显示头像 和名字

    cell.imageView.image = [UIImage imageNamed:@"chatListCellHead"];

    cell.textLabel.text = buddy.username;

    

    return cell;

}

 

注意一个bug在网速很慢的时候话或者用户的手速很快的情况下(遇到单身30年的手速)用户的时候      你会发现好友列表但是没有值的  因为它的好友列表是在你用户登录策划国内恭候才会有值 

 

buddyList是从本地获取的数据  本地有个数据库你可以去里面看看  

// buddyList 

 

如果删除了应用或者饿用户第一次登陆的时候 buddyList是没有数据记录的

就要从服务区获取好友列表纪录

 

 

在网络登陆之前我们去从服务器获取那个 好友列表并把它写到本地的数据库里面去,注意一下这个方法写在哪个地方 切记切记
----------------好友请求同意后的列表刷新----------------------------

 

当接收到后有的同意后要刷新好友的列表数据   去通讯录控制器监听
产生了一个问题?

我发送了请求   对方接受了   没有刷新好友列表

环信发送的话一定调用了

#pragma mark-好友列表的请求被更新,然而并没什么卵用

-(void)didUpdateBuddyList:(NSArray *)buddyList changedBuddies:(NSArray *)changedBuddies isAdd:(BOOL)isAdd{

//    NSLog(@"好友列表被更新%@", buddyList);

    NSLog(@"%@",buddyList);

    self.buddyList = buddyList;

    [self.tableView reloadData];

    

}

加上这句话就可以解决这个问题

 

 

 

 

============删除好友==========================

 

 

获取移除好友的名字

还有一种删除了是互相删除还是只是将一方的删除

 

#pragma mark--删除好友的代理方法

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(nonnull NSIndexPath *)indexPath {

    if(editingStyle == UITableViewCellEditingStyleDelete) {

        //获取要移除的好友的名字

        EMBuddy *buddy =self.buddyList[indexPath.row];

        NSString *deleteusername  = buddy.username;

        

        //删除好友

        [[EaseMob sharedInstance].chatManager removeBuddy:deleteusername removeFromRemote:YES error:nil];

    }

}

 

 

 

 

 

———--------被好友删除的监听-----------------------------

1.在会话里面:

//被好友删除

#pragma mark-监听被好友删除

-(void)didRemovedByBuddy:(NSString *)username {

    NSString *message = [username stringByAppendingString:@"把你删除"];

    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"好友删除提醒" message:message delegate:nil cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil];

    [alert show];

}

 

在同叙录里面:

//监听被删除去会话里面

#pragma mark-被好友删除了刷新一遍列表

-(void)didRemovedByBuddy:(NSString *)username {

    [self loadDataFromServer];

}

 

--------------退出登录--------------------------

 

选中table View 的然后给他选static cell

   2.然后连线去实现它的方法

 

-重点-------------聊天界面的实现----------------------------

 

1.拖入一个UIviewController 在上面在取拖入一个navagationBar 去设置他的标题

 

2.把cell的脱线  show

 

3.拖入一个View   拖到最下面    你会发现被tabbar 给盖住了   怎么去隐藏他呢?

   选中他   有个 Bottom Bar  改为None   

 

4.给这个View设置约束的时候注意  不要给她设置底部距Bottom  选择View

layout后  选择 Hidden Bottom Bar

 

5.往上面添加button    button也要设置约束  要他举例底部的位子不变    

否者的话  他会随着聊天的界面文字的的增加   而那个上升

 

还要加上一个textfield

 

通过代码监听键盘    如果底部
千万不要把键盘关闭了   不然神仙也救不了你

 

具体代码:

 

-(void)viewDidLoad {

    [super viewDidLoad];

    //1.监听键盘的弹出,把inputToolbar往上移

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(kbWillShow:) name:UIKeyboardWillShowNotification object:nil];

    

    

    

}

 

#pragma mark-键盘显示的时候会触发方法

-(void)kbWillShow:(NSNotification *)notification {

 //获取键盘的高度

    //1.获取键盘结束的位子

    CGRect kbEndFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];

    CGFloat kbHeight = kbEndFrame.size.height;

    

    //更改inputToolBar的底部约束

    self.inputToolBarBottonConstraint.constant = kbHeight;

    //添加动画

    [UIView animateWithDuration:0.25 animations:^{

        [self.view layoutIfNeeded];

    }];

}

 

//移除通知

 

-(void)dealloc {

    [[NSNotificationCenter defaultCenter] removeObserver:self];

}

 

///////////////////

再加上一个tableView在它的上面    如何实现在拖动tableview 的时候让键盘隐藏

 

或者去监听tableView滚动的方法  

 

tableView 有一个属性 Keyboard  Dismiss on drag

在键盘推出的时候 让inputToolBarView  恢复原位

也要监听他

 

 

 

 

-----------cell有三种类型的 左边  中间   右边 -------------------------

1.往那个tableView里面去添加cell的时候我们可以 在里面加上图片

 

思路:在你设置好了头像之后再去设置文本的时候怎么设置

UILabel 设置背景图片的时候 我们可以先去给UILabel设置约束

再去设置那个背景图片,让他去拉伸

设置约束的时候注意头像要写死  但是lable只需要设置他的左边和  上面就行

 

如何加上测试数据:

1.自定一一个cell   在给他对用的类    和 对应的cell  绑定一个改类名

在。h文件里面给label加上一个属性 , 在给他的cell绑定一cell
最后别忘了在给tableview 右键往那个UIviewController上面加上数据源和代理

也就是自定义cell

 

------如何去让他显示的换行

1.吧label的Lines设置为0;

2.设置她的最大宽度:选择  Preferred width 这个选项242;

 

 

----最后给他设置那个背景图片

吧那个UIimage添加到那个Label上面 

如何给那个这个ImageView 和Label  设置左上角对其?????????????

选中他们两个,然后把选择设置约束右下角的正向第2个  然后把4个Edge选择对其

 

最后别忘了去吧label  设置为clear

 

怎么去把ImageView的背景图片拉伸???????

选择背景图片 第4个属性倒立的脚   有一个strecting属性  设置为0.5   0.5  0  0

那个时候你会发现它的那个啥的没有那个左边图片的角的属性,什么原因呢?

这是因为你的这个时候的Y值拉升的不够可以把他的Y方向上面改成 0.7

 

这个时候还缺最后一步,要把它的那个背景ImagView改动一下,让它在上下左右 都往外面 

拉伸一下??????//

可以选中它的那个约束,更改它的那个Constant    左边和上面的都是 加10     下边和右边是减10

 最后别忘了跟新约束

 

-----------发送方的cell排布----------------------

先拖入一tableViewCell 然后改他的名字    在去拖入一个Imageview  在去实现它的那个

5  5   35 35 

2.拖入一个Label   上面15 右边20   宽和高就不要添加了

 

3.如何让两个自定义的cell指向同一个的cell  新思想 :两个View公用一个cell

  连线的时候又一个选择   选择senderCell   再给SenderCell一个identifier标示符号

在渲染cell的方法中加入一个加载哪一个cell的判断

 

4.最后设置它的Lines = 0  和 那个Preferred Width的宽度  让它实现自动换行

 

5.添加一个ImageView然后再去设置它的背景图片和  那个边距的对其

 

6.更改Image的Stretching

 

7.最后去把ImageView 的各个边距都改一下 上 10   左 10    下 -10  右边  -15 最后跟新

 

8  重点----如何去根据label里面的文字的高度去自动计算那个文字的高度?????

1.实现它的给他添加了一个测试的数据源方法

9--重点----还有一个问题  怎么去更改的它的自动计算那个行高呢??????

cell的高度取决于label文字的高度和它的字体的大小决定的、

思想: 去获取那个cell里面的label的高度再去加上一个固定的高度就是cell的高度了

怎么去获取那个label的高度呢???

上面的额头像距上为5 加上那个上面label距离上面的10的高度 再加上label自己      的高度self.label.hight +下面的那个10,再去加上那个固定的高度就是cell的高度了

 

 

10.--重点----我们专门搞一个计算高度的属性(他是一个返回cell的方法,然后去返回cell高度的方法里面去给他完成一下赋值的操作,最后去实现)

  //还少了一步 ,一定要加上去设置那个label的数据

    self.chatCellTool.messageLabel.text = self.dataSources[indexPath.row];

    return [self.chatCellTool cellHeight];

 

 

/** 计算高度的cell的属性*/

 @property (nonatomic,strong)UXZYChatCell *chatCellTool;

 

   //给计算cell高度的对象完成一个赋值

    //他返回的是一个cell 这个cell只是在那个返回高度的方法里面去用到了,其他的地方没有用到

记得最好把它的方法static NSString *Indentifier = @"ReceiveCell";写在那个cell的.h文件中

tableview记得再拖一次线  为什么任何一个的Identifier:都可以呢?????

因为你在返回高度的方法里面都是一样的执行的,不获去细分你是哪一个cell的方法 so。。。

    self.chatCellTool = [self.tableView dequeueReusableCellWithIdentifier:SenderCell];

 

 

--------------发送聊天消息---------------------

1.首先要做的是把那个 textView的发送框改成send属性 第四个选项里面的有一个

  Return Key 选项 改成那个Send选项

 

2.怎么去发送按钮的事件呢?????

1.把那个textView 的代理的线连上   2.然后去那个tableView里面的那个去遵守textView代理

 

在textView的方法里面去监听他最后的字符有没有换行,如果有换行的字符的话我就代表说他是发送sender的按钮]

 

3.怎么去发送文字呢???????

#pragma mark-UITextView的代理

-(void)textViewDidChange:(UITextView *)textView {

    if([textView.text hasSuffix:@"\n"] ) {

        NSLog(@"这是一个发送事件");

        //发送文字

        [self sendMessage:textView.text];

        

        //清空文字

        textView.text = nil;

    

    }

}

 

-(void)sendMessage:(NSString *)text {

    //创建一个消息对象实例

    EMMessage *msgObj = [[EMMessage alloc]initWithReceiver:nil bodies:nil];

    //发送消息

    [[EaseMob sharedInstance].chatManager asyncSendMessage:msgObj progress:nil prepare:^(EMMessage *message, EMError *error) {

        NSLog(@"消息准备发送");

    } onQueue:nil completion:^(EMMessage *message, EMError *error) {

        NSLog(@"消息完成发送");

    } onQueue:nil];

    

}

还缺少一个参数  就是把消息发送给谁? 我们就缺少一个参数传递

initWithReceiver:要去拿到那个参数好友列表的参数 EMBuddy 

#warning 每一种消息类型对象不同的消息体

    //EMTextMessageBody

    //EMVoiceMessageBody

    //EMVideoMessageBody

   // EMLocationMessageBody

   // EMImageMessageBody

    

    //创建一个聊天的文本对象

    EMChatText *chatText = [[EMChatText alloc]initWithText:text];

    //创建一个文本消息体

    EMTextMessageBody *textBody = [[EMTextMessageBody alloc]initWithChatObject:chatText];

    

    //创建一个消息对象实例   bodies是一个数组

    EMMessage *msgObj = [[EMMessage alloc]initWithReceiver:self.buddy.username bodies:@[textBody]];

    //发送消息

    

    [[EaseMob sharedInstance].chatManager asyncSendMessage:msgObj progress:nil prepare:^(EMMessage *message, EMError *error) {

        NSLog(@"消息准备发送");

    } onQueue:nil completion:^(EMMessage *message, EMError *error) {

        NSLog(@"消息完成发送");

    } onQueue:nil];

 

注意点  : 加上一个return;去测试

把选中的好友列表正向传递进去

最后别忘了把那个return打开;

    

 

--------------显示好友的名字---------------------

1.在那个聊天的控制器的viewdidload里面写上

self.titlte = self.buddy.username

 

——————-------加载本地的聊天数据--------------------

有封装好的东西,先去内存的会话列表中去获取会话  如果没有找到就去数据库中去获取会话

没有找到就会出发现的会话

 

#pragma mark-加载本地的聊天数据 

-(void)loadLocalChatrecords {

    //获取本地聊天记录 会话对象

   EMConversation *conversation = [[EaseMob sharedInstance].chatManager conversationForChatter:self.buddy.username conversationType: eConversationTypeChat];

    //加载当前来哦天用户所有的聊天记录

    NSArray *messages = [conversation loadAllMessages];

    

    for(id obj in messages) {

        NSLog(@"%@",[obj class]);

    }

    

    [self.dataSources addObject:messages];

    

}

 

  [self.dataSources addObject:messages];加上了就报错了,她的原因是什么呢?

  tableView:heightForRowAtIndexPath 错了

 

跳进设置高度的方法里面去 去吧里面改动一下

    //改进后的cell高度的获取

    //1.获取消息的模型 这样代码风格不好我们可以去cell的属性里面去创建一个cell的模型

//    EMMessage *msg = self.dataSources[indexPath.row];

//    id body = msg.messageBodies[0];

//    if([body isKindOfClass:[EMTextMessageBody class]]) {//如果是文本消息

//        EMTextMessageBody *textBody = body;

//        cell.messageLabel.text = textBody;

//    }

 

最后是用一个set方法去代替他们

 

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    //1.获取消息的模型 这样代码风格不好我们可以去cell的属性里面去创建一个cell的模型

    EMMessage *msg = self.dataSources[indexPath.row];

    //改进后的cell高度的获取

//    id body = msg.messageBodies[0];

//    

//    if([body isKindOfClass:[EMTextMessageBody class]]) {//如果是文本消息

//        EMTextMessageBody *textBody = body;

//        cell.messageLabel.text = textBody;

//    }

    self.chatCellTool.message = msg;

    return [self.chatCellTool cellHeight];

    

    //还少了一步 ,一定要加上去设置那个label的数据

//    self.chatCellTool.messageLabel.text = self.dataSources[indexPath.row];

//    return [self.chatCellTool cellHeight];

}

最后别忘了去那个tableviewcell的模型里面去改,

 

————为了计算高度我们建立了一个模型——----------

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

     //改进后的cell高度的获取

    //1.获取消息的模型 这样代码风格不好我们可以去cell的属性里面去创建一个cell的模型

    EMMessage *msg = self.dataSources[indexPath.row];

    

    self.chatCellTool.message = msg;

    

    return [self.chatCellTool cellHeight];

}

重写了模型的set方法 ,然后去调用了他的set方法

 

最后别忘了在显示的时候去调用他渲染那个方法

我的这个msg是一个消息模型

msg.messageBodies[0]

这样才能拿到消息体

msg.messageBodies[0].text才正确

 

-------------

[Pasted Graphic.tiff]

----------这样还不对-------------------------

 

你会看到你发出去的消息会在左边能看到

如何让它只能在右边显示呢??????????/

EMmessage有两个属性 from   to

from是发送方也就是自己    from是好友的话自己就是接受方

所以我们得在现实渲染的方法里面去先去获取消息模型

然后再去做一个from的判断

 

    UXZYChatCell *cell = nil;

    //先去获取消息模型然后去在去判断是发送方还是接收方

    EMMessage *msg = self.dataSources[indexPath.row];

    if([msg.from isEqualToString:self.buddy.username]) {//自己接收方

       cell = [tableView dequeueReusableCellWithIdentifier:Indentifier];

    }else {

       cell = [tableView dequeueReusableCellWithIdentifier:SenderCell];

    }

 

--------怎么让你的消息立马显示-----------------------

去这个方法里面 

-(void)sendMessage:(NSString *)text { }

 

msgObj是你自己创建一个消息对象实例   bodies是一个数组

 EMMessage *msgObj = [[EMMessage alloc]initWithReceiver:self.buddy.username bodies:@[textBody]];

    //把消息添加到数据源 再刷新表格

    [self.dataSources addObject:msgObj];

    [self.tableView reloadData];

 

------怎么让你的消息自己滚动到最上面的一行----

   

    //4.把消息显示在顶部

    [self scrollToBottom];

}

 

-(void)scrollToBottom {

    //获取最后一行

    if(self.dataSources.count == 0){

        return;

    }

    NSIndexPath *lastIndex = [NSIndexPath indexPathForRow:self.dataSources.count-1 inSection:0];

    

    

    [self.tableView scrollToRowAtIndexPath:lastIndex atScrollPosition:UITableViewScrollPositionBottom animated:YES];

}

 

—————仔细的你到这一步了发没发现你那个你发出去的消息子啊框里面都会多出一行---

原因:是你在点击发送的时候他换了一下行,换行字符只展占用一个字节

如何去清除那个换行的字符,在发消息的放里面去实现

        text = [text substringToIndex:text.length-1];

 

 

-----------怎么去监听消息的回复--------------------

1.设置代理方法  并遵循它的 代理方法

2.有一个那个mesage的方法去实现一下

 

 

 

 

------对输入框的完善,即在你输入的时候那个输入框的高速会自动增加-------------------------

1.得定义输入框的一个最小的高度和最大的高度

2.textView是继承于UIscrollView   scrollView有一个属性 contensize 属性

    这个是计算那个做一个判断 不同情况下面的高度

 

3.我们再去拿到那个的InputView 的高度的约束  再去连线使它成为一个属性  然后像之前一样去约束它,找到他,然后给他连线 使它成为一个属性

 

    //获取contentsize的高度

    CGFloat contentHeight = textView.contentSize.height;

    if (contentHeight <minHeight) {

        textViewH = minHeight;

    }else if (contentHeight >maxHeight) {

        textViewH = maxHeight;

    }else {

        textViewH = contentHeight;

    }

    

    self.inputToolBarHeightConstrains.constant = 5 + 8 + textViewH;

 

4.还是有一个问题,就是在你输入完了一之后发送了   之后textView还是有一个换行的空格

所以还得有一个在发送完了后的判断语句

if([textView.text hasSuffix:@"\n"] ) {

        NSLog(@"这是一个发送事件");

        //发送文字

        [self sendMessage:textView.text];

        

        //清空文字

        textView.text = nil;

        

//        发送时textView的高速为最小的高度

        textViewH = minHeight;

    

    }

    self.inputToolBarHeightConstrains.constant = 5 + 8 + textViewH;

 

5.设置textView的背景图片  在SB中去设置 拖入一个IMageView 然后把它拿到那个textView的上面去   然后改透明  设置背景图片    把图片拉伸  streching  别忘了给背景图片加约束 不然的话他会随着那个的高度的增加他不会随着拉伸   最后去加个动画

 

6.——————---发送完了后发现光标不见了 发大模拟器看在左上角???

原因???scrollView有一个contentOffset.y的值会随着你的那个的光标的contensize的而向上拖动而拖送

NSStringFromCGSize(textView.contentSet)可以打印出来看看

contentOffset一开始为(0,0)之后它的y值为正数了,为什么呢,因为他要显示的下面的文字内容的话它的那个轴必须下移动 所以为正 

如何解决  哪次发送完了 让它的contentset恢复到原位

 

 

环信遇到的bug1:真机上面不能跑  模拟器可以

[Pasted Graphic_1.tiff]

 

把那个bitcode 设置为NO  bitcode是被编译程序的一种中间形式的代码。包含bitcode配置的程序将会在App store上被编译和链接

默认是yes   

 

 

storyboard作为控制器的复习

 

1.拖入一导航控制器 ,更改尺寸    去掉后一个

2.拖入一个viewControler  然后去把它的那个root viewcontroller  设置一下

 

3.创建一个控制器UIviewcontroller     第三个选项 class里面更改继承关系   

 

 

4.拖线 连线        1.去改掉main        2。去那个第4个 is initial  View Controller 的钩上

 

 

登录提供了三种方法

 

 

1.同步     2.block的异步      3.代理的回调

 

注释的方法提示在图表

方式一:/// 点在图标

方式二: 

 /*!

 *   @brief 点在图标

 */ 查看全部
环信的教程:

没有初始化SDK  

去AppDelegate里面初始化

 

密码

 

User not exist         ??????????

每一个应用都有自己的注册用户  去你的后台管理   去看你的注册的用户数   

为什么demo的可以跑起来????????

是在它的应用下注册的

 

怎么去注册用户  -注册用户

用户名字可以相同   不同的应用   

 

 

那个打印的loginInfo 是这个字典的也就是用户的登录信息

 

你会发现打印的loginInfo上面还有一坨恶心的东西,那个是环信SDK自己打印的日志信息

 

SEND   和      RECV    使用的是XMPP协议    所以 数据的格式是XML   一般的HTTP协议的话他就是JSON格式的

这个是app把客户端登录的信息发给环信服务器后打印出来的日志      是不是很烦

 

如何去在哪儿隐藏它的控制台的日志信息 ?????????

去初始化的时候把它隐藏  有一个otherConfig的东西   右键-jump to Define

进去瞅瞅--

复制它的key 给他设置为NO

这个时候它的控制台的日志信息就被屏蔽了

 

 

跟环信交互的所有类都有这个

[EaseMob sharedInstance].chatManager

 

 

注册的时候代码:


如果你把这onQueue改为nil的话他默认也是在主线程的

 

然后你在去环信的开发中心刷新IM用户 你会发现他多了一个

发送给的数据给服务器的时候还是XML格式,里面的SDK帮你封装了,不用你自己去接触

 

 

---自动登录------------------------------------

 

看到它的主界面只有三个tabbar

 进去 mainstoryboard里面 删除原始的viewcontroller  拖入一个 tabbarController     去掉原始的tabbar 的两个子控制器   记得给它的isinitial 那个选项钩上   然后拖入三个navigationcontroller(这个根据你的界面而定)

 

选中给每个的Item  的title属性可以更改

然后在登录成功中写上加载storyboard的方法

你会发现你已经跳转进去
如何实现自动登录?????????????????

  实现原理:把你的登录信息保存在沙盒中     程序启动时候发送登录请求

  只要你在第一次登录成功后发送环信自带登录的网络请求去实现、

环信自己帮你实现上面的东西

 

具体实现

在登录成功的下面写上

[[EaseMob sharedInstance].chatManager  setIsAutoLoginEnabled:YES]

然后去在AppDelegte里面把他的沙盒路径拿到
然后再控制台你可以看到这些信息,其中的账号密码信息你会发现他被加密了,有没有?
如何监听是否是已经处于登录状态了这个地方有个代理  环信的代理方法

在AppDelegate方法里面进去 在启动方法里面写
你会发现它的那个啥没有完成界面的跳转    但是控制台却是带那个登陆成功了
这个时候我们还缺一步骤  之前我们在自动登录时候我们调用的是set方法

这个时候我们要实现它的 get方法     写在监听登录状态的下面

  //如果登录过直接来到主界面
    if([[EaseMob sharedInstance].chatManager isAutoLoginEnabled]){

        self.window.rootViewController = [UIStoryboard storyboardWithName:@"Main" bundle:nil].instantiateInitialViewController;

    }

    
=------------自动连接--------------------------

 

网络通不通的时候类似微信那种网络不通的实现

去那个main.storyboard里面把那会话的导航控制器跳转的那个类继承改为你自己创建的那个UItableViewController

 

1.在会话里面监听的网络的状态  环信的有很多个代理

去那个.m文件里面去实现
点击那个EMChatManagerDelegate 里面去实现 EMChatManagerUtilDelegate里面的这个方法就OK了

- (void)didConnectionStateChanged:(EMConnectionState)connectionState;
在真机上面测试的时候 网络连接成功不代表客户端和服务器端连接成功

 

 

还有自动连接的状态的监听 也是加上他的代理方法就行了


--------添加好友请求-----------------------------

1.是用环信的思想

 所有的网络请求   [EaseMob sharedInstance].chatManager 由这个管理器发起的

 

2.所有结果(自动登录 自动连接)通过代理来回调完成

[EaseMob sharedInstance].chatManager的addDelegate来完成

 

3.EMChatManagerBuddyDelegate 这个代理实现了对用户的基本操作

1.添加好友      2.从本地获取好友      3.从服务器列表获取最新的好友     4.接受好友添加请求

5.删除好友       6.被好友从名单上面删除  

 

 

在navigation  的第二个控制器上面加上一个UIbarbarItem   选择自定义   然后+    

再去创建一个UIviewController     然后再去实现用个+号去拖一个线  

 

 可以在上面加上navigationItem 上改为添加好友

再去新建一个控制器AdressBooking 通讯录  这个类是继承于UIviewController
是用环信最简单的方法 ,把官方的Demo直接拿过来用   直接跟改它的Appdelegate里面的APPKey

这样你就收到了申请    注意   这是最简单的方式

 

 

还有一点 你要在每个控制器里面写上你环信的代理方法

这样就能保证你下面写的环信 的每一个方法会被自动调用了
代理方法:

代理的销毁

 

 

好友请求消息反馈写在什么地方   因为你进去那个会话的控制器里面了的话就会被销毁了。我们可以把它的好友请求写在会话控制器   这样他每个控制器都可以收到了  也没有必要写在AppDelegate里面 可以去尝试一下

 

 

 

 

 

 

 

 

 

 

---------现实好友界面列表------------------

1.新建一个tableViewcontroller  修改那个tableView的继承

 

2.给他的cell添加一个Identifier     
下面打印的就是他的好友列表

 

 

#pragma mark - Tableview datasource

 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return self.buddyList.count;

}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *ID = @"BuddyCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    //获取好友列表名称  EMBuddy是环信封装的好友模型

    EMBuddy *buddy = self.buddyList[indexPath.row];

    //显示头像 和名字

    cell.imageView.image = [UIImage imageNamed:@"chatListCellHead"];

    cell.textLabel.text = buddy.username;

    

    return cell;

}

 

注意一个bug在网速很慢的时候话或者用户的手速很快的情况下(遇到单身30年的手速)用户的时候      你会发现好友列表但是没有值的  因为它的好友列表是在你用户登录策划国内恭候才会有值 

 

buddyList是从本地获取的数据  本地有个数据库你可以去里面看看  

// buddyList 

 

如果删除了应用或者饿用户第一次登陆的时候 buddyList是没有数据记录的

就要从服务区获取好友列表纪录

 

 

在网络登陆之前我们去从服务器获取那个 好友列表并把它写到本地的数据库里面去,注意一下这个方法写在哪个地方 切记切记
----------------好友请求同意后的列表刷新----------------------------

 

当接收到后有的同意后要刷新好友的列表数据   去通讯录控制器监听
产生了一个问题?

我发送了请求   对方接受了   没有刷新好友列表

环信发送的话一定调用了

#pragma mark-好友列表的请求被更新,然而并没什么卵用

-(void)didUpdateBuddyList:(NSArray *)buddyList changedBuddies:(NSArray *)changedBuddies isAdd:(BOOL)isAdd{

//    NSLog(@"好友列表被更新%@", buddyList);

    NSLog(@"%@",buddyList);

    self.buddyList = buddyList;

    [self.tableView reloadData];

    

}

加上这句话就可以解决这个问题

 

 

 

 

============删除好友==========================

 

 

获取移除好友的名字

还有一种删除了是互相删除还是只是将一方的删除

 

#pragma mark--删除好友的代理方法

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(nonnull NSIndexPath *)indexPath {

    if(editingStyle == UITableViewCellEditingStyleDelete) {

        //获取要移除的好友的名字

        EMBuddy *buddy =self.buddyList[indexPath.row];

        NSString *deleteusername  = buddy.username;

        

        //删除好友

        [[EaseMob sharedInstance].chatManager removeBuddy:deleteusername removeFromRemote:YES error:nil];

    }

}

 

 

 

 

 

———--------被好友删除的监听-----------------------------

1.在会话里面:

//被好友删除

#pragma mark-监听被好友删除

-(void)didRemovedByBuddy:(NSString *)username {

    NSString *message = [username stringByAppendingString:@"把你删除"];

    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"好友删除提醒" message:message delegate:nil cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil];

    [alert show];

}

 

在同叙录里面:

//监听被删除去会话里面

#pragma mark-被好友删除了刷新一遍列表

-(void)didRemovedByBuddy:(NSString *)username {

    [self loadDataFromServer];

}

 

--------------退出登录--------------------------

 

选中table View 的然后给他选static cell

   2.然后连线去实现它的方法

 

-重点-------------聊天界面的实现----------------------------

 

1.拖入一个UIviewController 在上面在取拖入一个navagationBar 去设置他的标题

 

2.把cell的脱线  show

 

3.拖入一个View   拖到最下面    你会发现被tabbar 给盖住了   怎么去隐藏他呢?

   选中他   有个 Bottom Bar  改为None   

 

4.给这个View设置约束的时候注意  不要给她设置底部距Bottom  选择View

layout后  选择 Hidden Bottom Bar

 

5.往上面添加button    button也要设置约束  要他举例底部的位子不变    

否者的话  他会随着聊天的界面文字的的增加   而那个上升

 

还要加上一个textfield

 

通过代码监听键盘    如果底部
千万不要把键盘关闭了   不然神仙也救不了你

 

具体代码:

 

-(void)viewDidLoad {

    [super viewDidLoad];

    //1.监听键盘的弹出,把inputToolbar往上移

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(kbWillShow:) name:UIKeyboardWillShowNotification object:nil];

    

    

    

}

 

#pragma mark-键盘显示的时候会触发方法

-(void)kbWillShow:(NSNotification *)notification {

 //获取键盘的高度

    //1.获取键盘结束的位子

    CGRect kbEndFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];

    CGFloat kbHeight = kbEndFrame.size.height;

    

    //更改inputToolBar的底部约束

    self.inputToolBarBottonConstraint.constant = kbHeight;

    //添加动画

    [UIView animateWithDuration:0.25 animations:^{

        [self.view layoutIfNeeded];

    }];

}

 

//移除通知

 

-(void)dealloc {

    [[NSNotificationCenter defaultCenter] removeObserver:self];

}

 

///////////////////

再加上一个tableView在它的上面    如何实现在拖动tableview 的时候让键盘隐藏

 

或者去监听tableView滚动的方法  

 

tableView 有一个属性 Keyboard  Dismiss on drag

在键盘推出的时候 让inputToolBarView  恢复原位

也要监听他

 

 

 

 

-----------cell有三种类型的 左边  中间   右边 -------------------------

1.往那个tableView里面去添加cell的时候我们可以 在里面加上图片

 

思路:在你设置好了头像之后再去设置文本的时候怎么设置

UILabel 设置背景图片的时候 我们可以先去给UILabel设置约束

再去设置那个背景图片,让他去拉伸

设置约束的时候注意头像要写死  但是lable只需要设置他的左边和  上面就行

 

如何加上测试数据:

1.自定一一个cell   在给他对用的类    和 对应的cell  绑定一个改类名

在。h文件里面给label加上一个属性 , 在给他的cell绑定一cell
最后别忘了在给tableview 右键往那个UIviewController上面加上数据源和代理

也就是自定义cell

 

------如何去让他显示的换行

1.吧label的Lines设置为0;

2.设置她的最大宽度:选择  Preferred width 这个选项242;

 

 

----最后给他设置那个背景图片

吧那个UIimage添加到那个Label上面 

如何给那个这个ImageView 和Label  设置左上角对其?????????????

选中他们两个,然后把选择设置约束右下角的正向第2个  然后把4个Edge选择对其

 

最后别忘了去吧label  设置为clear

 

怎么去把ImageView的背景图片拉伸???????

选择背景图片 第4个属性倒立的脚   有一个strecting属性  设置为0.5   0.5  0  0

那个时候你会发现它的那个啥的没有那个左边图片的角的属性,什么原因呢?

这是因为你的这个时候的Y值拉升的不够可以把他的Y方向上面改成 0.7

 

这个时候还缺最后一步,要把它的那个背景ImagView改动一下,让它在上下左右 都往外面 

拉伸一下??????//

可以选中它的那个约束,更改它的那个Constant    左边和上面的都是 加10     下边和右边是减10

 最后别忘了跟新约束

 

-----------发送方的cell排布----------------------

先拖入一tableViewCell 然后改他的名字    在去拖入一个Imageview  在去实现它的那个

5  5   35 35 

2.拖入一个Label   上面15 右边20   宽和高就不要添加了

 

3.如何让两个自定义的cell指向同一个的cell  新思想 :两个View公用一个cell

  连线的时候又一个选择   选择senderCell   再给SenderCell一个identifier标示符号

在渲染cell的方法中加入一个加载哪一个cell的判断

 

4.最后设置它的Lines = 0  和 那个Preferred Width的宽度  让它实现自动换行

 

5.添加一个ImageView然后再去设置它的背景图片和  那个边距的对其

 

6.更改Image的Stretching

 

7.最后去把ImageView 的各个边距都改一下 上 10   左 10    下 -10  右边  -15 最后跟新

 

8  重点----如何去根据label里面的文字的高度去自动计算那个文字的高度?????

1.实现它的给他添加了一个测试的数据源方法

9--重点----还有一个问题  怎么去更改的它的自动计算那个行高呢??????

cell的高度取决于label文字的高度和它的字体的大小决定的、

思想: 去获取那个cell里面的label的高度再去加上一个固定的高度就是cell的高度了

怎么去获取那个label的高度呢???

上面的额头像距上为5 加上那个上面label距离上面的10的高度 再加上label自己      的高度self.label.hight +下面的那个10,再去加上那个固定的高度就是cell的高度了

 

 

10.--重点----我们专门搞一个计算高度的属性(他是一个返回cell的方法,然后去返回cell高度的方法里面去给他完成一下赋值的操作,最后去实现)

  //还少了一步 ,一定要加上去设置那个label的数据

    self.chatCellTool.messageLabel.text = self.dataSources[indexPath.row];

    return [self.chatCellTool cellHeight];

 

 

/** 计算高度的cell的属性*/

 @property (nonatomic,strong)UXZYChatCell *chatCellTool;

 

   //给计算cell高度的对象完成一个赋值

    //他返回的是一个cell 这个cell只是在那个返回高度的方法里面去用到了,其他的地方没有用到

记得最好把它的方法static NSString *Indentifier = @"ReceiveCell";写在那个cell的.h文件中

tableview记得再拖一次线  为什么任何一个的Identifier:都可以呢?????

因为你在返回高度的方法里面都是一样的执行的,不获去细分你是哪一个cell的方法 so。。。

    self.chatCellTool = [self.tableView dequeueReusableCellWithIdentifier:SenderCell];

 

 

--------------发送聊天消息---------------------

1.首先要做的是把那个 textView的发送框改成send属性 第四个选项里面的有一个

  Return Key 选项 改成那个Send选项

 

2.怎么去发送按钮的事件呢?????

1.把那个textView 的代理的线连上   2.然后去那个tableView里面的那个去遵守textView代理

 

在textView的方法里面去监听他最后的字符有没有换行,如果有换行的字符的话我就代表说他是发送sender的按钮]

 

3.怎么去发送文字呢???????

#pragma mark-UITextView的代理

-(void)textViewDidChange:(UITextView *)textView {

    if([textView.text hasSuffix:@"\n"] ) {

        NSLog(@"这是一个发送事件");

        //发送文字

        [self sendMessage:textView.text];

        

        //清空文字

        textView.text = nil;

    

    }

}

 

-(void)sendMessage:(NSString *)text {

    //创建一个消息对象实例

    EMMessage *msgObj = [[EMMessage alloc]initWithReceiver:nil bodies:nil];

    //发送消息

    [[EaseMob sharedInstance].chatManager asyncSendMessage:msgObj progress:nil prepare:^(EMMessage *message, EMError *error) {

        NSLog(@"消息准备发送");

    } onQueue:nil completion:^(EMMessage *message, EMError *error) {

        NSLog(@"消息完成发送");

    } onQueue:nil];

    

}

还缺少一个参数  就是把消息发送给谁? 我们就缺少一个参数传递

initWithReceiver:要去拿到那个参数好友列表的参数 EMBuddy 

#warning 每一种消息类型对象不同的消息体

    //EMTextMessageBody

    //EMVoiceMessageBody

    //EMVideoMessageBody

   // EMLocationMessageBody

   // EMImageMessageBody

    

    //创建一个聊天的文本对象

    EMChatText *chatText = [[EMChatText alloc]initWithText:text];

    //创建一个文本消息体

    EMTextMessageBody *textBody = [[EMTextMessageBody alloc]initWithChatObject:chatText];

    

    //创建一个消息对象实例   bodies是一个数组

    EMMessage *msgObj = [[EMMessage alloc]initWithReceiver:self.buddy.username bodies:@[textBody]];

    //发送消息

    

    [[EaseMob sharedInstance].chatManager asyncSendMessage:msgObj progress:nil prepare:^(EMMessage *message, EMError *error) {

        NSLog(@"消息准备发送");

    } onQueue:nil completion:^(EMMessage *message, EMError *error) {

        NSLog(@"消息完成发送");

    } onQueue:nil];

 

注意点  : 加上一个return;去测试

把选中的好友列表正向传递进去

最后别忘了把那个return打开;

    

 

--------------显示好友的名字---------------------

1.在那个聊天的控制器的viewdidload里面写上

self.titlte = self.buddy.username

 

——————-------加载本地的聊天数据--------------------

有封装好的东西,先去内存的会话列表中去获取会话  如果没有找到就去数据库中去获取会话

没有找到就会出发现的会话

 

#pragma mark-加载本地的聊天数据 

-(void)loadLocalChatrecords {

    //获取本地聊天记录 会话对象

   EMConversation *conversation = [[EaseMob sharedInstance].chatManager conversationForChatter:self.buddy.username conversationType: eConversationTypeChat];

    //加载当前来哦天用户所有的聊天记录

    NSArray *messages = [conversation loadAllMessages];

    

    for(id obj in messages) {

        NSLog(@"%@",[obj class]);

    }

    

    [self.dataSources addObject:messages];

    

}

 

  [self.dataSources addObject:messages];加上了就报错了,她的原因是什么呢?

  tableView:heightForRowAtIndexPath 错了

 

跳进设置高度的方法里面去 去吧里面改动一下

    //改进后的cell高度的获取

    //1.获取消息的模型 这样代码风格不好我们可以去cell的属性里面去创建一个cell的模型

//    EMMessage *msg = self.dataSources[indexPath.row];

//    id body = msg.messageBodies[0];

//    if([body isKindOfClass:[EMTextMessageBody class]]) {//如果是文本消息

//        EMTextMessageBody *textBody = body;

//        cell.messageLabel.text = textBody;

//    }

 

最后是用一个set方法去代替他们

 

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    //1.获取消息的模型 这样代码风格不好我们可以去cell的属性里面去创建一个cell的模型

    EMMessage *msg = self.dataSources[indexPath.row];

    //改进后的cell高度的获取

//    id body = msg.messageBodies[0];

//    

//    if([body isKindOfClass:[EMTextMessageBody class]]) {//如果是文本消息

//        EMTextMessageBody *textBody = body;

//        cell.messageLabel.text = textBody;

//    }

    self.chatCellTool.message = msg;

    return [self.chatCellTool cellHeight];

    

    //还少了一步 ,一定要加上去设置那个label的数据

//    self.chatCellTool.messageLabel.text = self.dataSources[indexPath.row];

//    return [self.chatCellTool cellHeight];

}

最后别忘了去那个tableviewcell的模型里面去改,

 

————为了计算高度我们建立了一个模型——----------

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

     //改进后的cell高度的获取

    //1.获取消息的模型 这样代码风格不好我们可以去cell的属性里面去创建一个cell的模型

    EMMessage *msg = self.dataSources[indexPath.row];

    

    self.chatCellTool.message = msg;

    

    return [self.chatCellTool cellHeight];

}

重写了模型的set方法 ,然后去调用了他的set方法

 

最后别忘了在显示的时候去调用他渲染那个方法

我的这个msg是一个消息模型

msg.messageBodies[0]

这样才能拿到消息体

msg.messageBodies[0].text才正确

 

-------------

[Pasted Graphic.tiff]

----------这样还不对-------------------------

 

你会看到你发出去的消息会在左边能看到

如何让它只能在右边显示呢??????????/

EMmessage有两个属性 from   to

from是发送方也就是自己    from是好友的话自己就是接受方

所以我们得在现实渲染的方法里面去先去获取消息模型

然后再去做一个from的判断

 

    UXZYChatCell *cell = nil;

    //先去获取消息模型然后去在去判断是发送方还是接收方

    EMMessage *msg = self.dataSources[indexPath.row];

    if([msg.from isEqualToString:self.buddy.username]) {//自己接收方

       cell = [tableView dequeueReusableCellWithIdentifier:Indentifier];

    }else {

       cell = [tableView dequeueReusableCellWithIdentifier:SenderCell];

    }

 

--------怎么让你的消息立马显示-----------------------

去这个方法里面 

-(void)sendMessage:(NSString *)text { }

 

msgObj是你自己创建一个消息对象实例   bodies是一个数组

 EMMessage *msgObj = [[EMMessage alloc]initWithReceiver:self.buddy.username bodies:@[textBody]];

    //把消息添加到数据源 再刷新表格

    [self.dataSources addObject:msgObj];

    [self.tableView reloadData];

 

------怎么让你的消息自己滚动到最上面的一行----

   

    //4.把消息显示在顶部

    [self scrollToBottom];

}

 

-(void)scrollToBottom {

    //获取最后一行

    if(self.dataSources.count == 0){

        return;

    }

    NSIndexPath *lastIndex = [NSIndexPath indexPathForRow:self.dataSources.count-1 inSection:0];

    

    

    [self.tableView scrollToRowAtIndexPath:lastIndex atScrollPosition:UITableViewScrollPositionBottom animated:YES];

}

 

—————仔细的你到这一步了发没发现你那个你发出去的消息子啊框里面都会多出一行---

原因:是你在点击发送的时候他换了一下行,换行字符只展占用一个字节

如何去清除那个换行的字符,在发消息的放里面去实现

        text = [text substringToIndex:text.length-1];

 

 

-----------怎么去监听消息的回复--------------------

1.设置代理方法  并遵循它的 代理方法

2.有一个那个mesage的方法去实现一下

 

 

 

 

------对输入框的完善,即在你输入的时候那个输入框的高速会自动增加-------------------------

1.得定义输入框的一个最小的高度和最大的高度

2.textView是继承于UIscrollView   scrollView有一个属性 contensize 属性

    这个是计算那个做一个判断 不同情况下面的高度

 

3.我们再去拿到那个的InputView 的高度的约束  再去连线使它成为一个属性  然后像之前一样去约束它,找到他,然后给他连线 使它成为一个属性

 

    //获取contentsize的高度

    CGFloat contentHeight = textView.contentSize.height;

    if (contentHeight <minHeight) {

        textViewH = minHeight;

    }else if (contentHeight >maxHeight) {

        textViewH = maxHeight;

    }else {

        textViewH = contentHeight;

    }

    

    self.inputToolBarHeightConstrains.constant = 5 + 8 + textViewH;

 

4.还是有一个问题,就是在你输入完了一之后发送了   之后textView还是有一个换行的空格

所以还得有一个在发送完了后的判断语句

if([textView.text hasSuffix:@"\n"] ) {

        NSLog(@"这是一个发送事件");

        //发送文字

        [self sendMessage:textView.text];

        

        //清空文字

        textView.text = nil;

        

//        发送时textView的高速为最小的高度

        textViewH = minHeight;

    

    }

    self.inputToolBarHeightConstrains.constant = 5 + 8 + textViewH;

 

5.设置textView的背景图片  在SB中去设置 拖入一个IMageView 然后把它拿到那个textView的上面去   然后改透明  设置背景图片    把图片拉伸  streching  别忘了给背景图片加约束 不然的话他会随着那个的高度的增加他不会随着拉伸   最后去加个动画

 

6.——————---发送完了后发现光标不见了 发大模拟器看在左上角???

原因???scrollView有一个contentOffset.y的值会随着你的那个的光标的contensize的而向上拖动而拖送

NSStringFromCGSize(textView.contentSet)可以打印出来看看

contentOffset一开始为(0,0)之后它的y值为正数了,为什么呢,因为他要显示的下面的文字内容的话它的那个轴必须下移动 所以为正 

如何解决  哪次发送完了 让它的contentset恢复到原位

 

 

环信遇到的bug1:真机上面不能跑  模拟器可以

[Pasted Graphic_1.tiff]

 

把那个bitcode 设置为NO  bitcode是被编译程序的一种中间形式的代码。包含bitcode配置的程序将会在App store上被编译和链接

默认是yes   

 

 

storyboard作为控制器的复习

 

1.拖入一导航控制器 ,更改尺寸    去掉后一个

2.拖入一个viewControler  然后去把它的那个root viewcontroller  设置一下

 

3.创建一个控制器UIviewcontroller     第三个选项 class里面更改继承关系   

 

 

4.拖线 连线        1.去改掉main        2。去那个第4个 is initial  View Controller 的钩上

 

 

登录提供了三种方法

 

 

1.同步     2.block的异步      3.代理的回调

 

注释的方法提示在图表

方式一:/// 点在图标

方式二: 

 /*!

 *   @brief 点在图标

 */
6
评论

【开源OA项目】基于环信IM开发完整的企业通讯解决方案-Dolores Dolores OA 开源项目

KevinGong 发表了文章 • 7445 次浏览 • 2017-06-26 10:53 • 来自相关话题

  

  前阵子钉钉在微信楼下刷了一波#创业很苦,坚持很酷#的广告,浓浓的“丧”文化风格文案受到了各界褒贬不一的评价,也引起了大家对OA办公系统的关注。
   对企业而言,初选OA办公系统是为了满足需求,解决当下问题,由于OA办公系统的在公司运作流程中扮演的重要性,安全与隐私等问题急需未雨绸缪,“可定制”、“可私有化部署”的OA办公系统成为了更多企业的首选。公司想自己开发一套IM系统应该从哪里开始呢? 企业通讯录怎么保持同步呢? 企业通讯录的权限管理应该怎么做?
   三个关于OA办公系统的究极问题,从开源的OA办公项目-Dolores(朵拉)诞生迎刃而解了。Dolores项目遵循Apache Licence 2.0 开源协议,可以直接拿来用,也可以修改代码来满足需要并作为开源或商业产品发布/销售。




关于Dolores?
Dolores是一套完整的企业通信解决方案,一个完整的企业沟通工具(以下简称企业IM),支持以下几个功能:IM消息服务、组织架构管理、工作流集成。
Dolores项目源码地址:https://github.com/DoloresTeam​ 
技术讨论群:641256202(QQ群)

整个解决方案都包括了什么?
企业通讯录的管理:部门/员工的增删改查通讯录全量更新:全量/增量更新 企业通讯录权限管理:基于RBAC权限管理模型企业即时通讯IM:企业通信对IM这块的可靠性要求高,选择了目前比较成熟的IM云服务厂商-环信
 
 
组织架构

企业通讯录可以说是企业沟通中最重的业务之一,能够提供员工各种服务的认证,获取员工的联系方式等。
 
组织架构-Server

服务端主要包括以下功能:
支持管理人员(例如HR)对部门和员工进行增删改查支持部门和员工自定义排序,自定义元信息存储权限管理员工通讯录视图 (员工根据自己的权限生成通讯录)通讯录增量更新 (鉴于移动端特殊的网络环境和设备,通讯录应该支持差量更新)集成 IM 用户系统

在这里我们主要讨论以下两个问题:
 
权限管理

  随着企业逐渐的发展,团队壮大为了更有效的沟通,以及保护公司内部的一些商业信息不被泄漏,我们应该为通讯录添加权限管理。

基于Role-based access control(RBAC)的权限管理模型

为了介绍此权限管理模型,我们先解释一下基本概念
角色:通常是指企业中某一个工作岗位,这个岗位具有特定的权利和职责。被赋予此角色的员工,将获得这种权利与职责权限:被赋予访问实体的权利。在本项目中是指访问部门和访问某一个或者某一类员工的权利用户-角色分配(User-Role Assignment URA):为某个用户指定一个或者多个角色,此员工将获得这些角色所具有权利的集合角色-权限分配(Role-Permission Assignment RPA):将权限分配给角色,一个角色可以包含多个权利。在本项目中是指多个访问部门和访问员工的权限

在用户和权限之间引入角色中介,将用户与权限的直接关系弱化为间接关系。|ˉˉˉ| |ˉˉ ˉ| |ˉˉˉˉ ˉˉ|
| User |---URA---> | Role |<---RPA---| Permission |
|______| |_______| |_____________|
    以角色为中介,首先创建访问每个部门和员工的访问权限,然后创建不同的角色,根据这些角色的职责不同分配不同的权限,建立角色-权限的关系以后,不同的角色将会有不同的权限。根据员工不同的岗位,将对应的角色分配给他们,建立用户-角色关系,这就是RBAC的主要思想。

一个员工可以用户多个角色,一个角色可以用于多个访问权限。RBAC 极大的简化了员工的授权管理。

   由于企业的部门和员工数量很多,在创建权限时管理员不可能去设置每一个权限可以访问的每一个部门和每一个员工。所以本项目将功能和指责类似的部门和员工看作是同一类型,在创建部门和员工的时候为每一个部门和员工分配固有属性type,管理员在设置权限规则的时候只需要指定可访问的部门类型和员工即可。

增量更新

   鉴于移动终端计算资源有限,如网络,存储,电量等,所以通讯录的更新技术应该保证尽量少的资源。另外由于通讯录的特殊性,通讯录的变化需要能实时通知到受影响的在线员工。

基于版本号与变更日志的增量更新模型

   客户端第一次登陆系统以后,我们根据当前登录角色生成对应的通讯录视图,并以当前时间戳作为版本号,返回给客户端。客户端后续通过此版本号增量更新通讯录。

版本号

   版本号有两种:一是客户端当前通讯录版本 c-version, 二是服务端通讯录每一次变化时的版本号s-version

变更日志

   在管理员修改权限规则,或者修改某个岗位的访问规则时会影响大面积员工的通讯录视图,此时如果用增量更新会导致服务器流量异常,因此在这2中情况会清空原来的变更日志并且要求客户端进行一次全量更新。

   如果管理员新增了员工,服务端会根据被修改的员工或者部门type, 反推出所有受影响的员工,然后生成一条变更日志, 例如:{
"content" : [
{
"cn" : "Lucy.Liu",
"id" : "b4vlfg91scgi1dcju8v0",
"title" : "市场运营负责人",
"email" : [
"lucy.liu@dolores.store"
],
"priority" : "101111",
"name" : "刘小飞",
"telephoneNumber" : "18888888888"
}
],
"createTimestamp" : "20170614063303Z",
"category" : "member",
"action" : "add"
}
客户端在请求增量更新的时候,通过当前登陆ID与版本号,可查找出所有与自己相关的变更日志,然后在客户端数据库中应用这些变更,即可完成同步。

组织架构-Client

   由于现在员工办公设备的多样性,客户端要根据自己公司的情况,覆盖的足够完整,常见的平台有 iOS Android windowsmac linux , 对于后三个平台可以用 Web APP 来覆盖,iOS&Android 用原生的app来提升用户体验。

客户端App主要包括以下功能:
会话列表优秀的聊天界面,历史记录组织机构全量/增量更新员工个人资料展示

客户端数据库设计

IM数据库设计
 
当前版本使用环信SDK
 
组织架构数据库设计

表设计

客户端组织架构较服务端简单,不关联用户Role,客户端本地存储Staff(员工)和Department(部门)信息:
一个部门可以包含相关子部门和部门员工。该部门员工和部门在视图上处于同级关系。员工隶属于部门,同一员工可以存在于多个部门。员工角色用title来表示。

用户在登录客户端成功后,会根据该用户信息创建用户对应的数据库文件,用户表(User)保存用户相关信息,关联该用户staff信息。

客户端组织架构同服务端逻辑。

工作流集成

(TODO)
 
如何使用Dolores

本项目现在已经完成了第一个测试版本,本小节将指导您如何安装使用。

后端数据库

鉴于通讯录对数据库操作的特点多度少写,以及部门之间的树状关系,我们选择LDAP协议来存取数据。

我们有独立的repo来帮助您完成数据库的安装与初始化。请移步这里

组织架构管理

Dolores 初始版本使用Golang实现,大家既可以下载各个平台的可执行包,也可以安装Go语言的开发环境自己编译。

我们有独立的repo来帮助您,运行后端服务。请移步这里

客户端

我们现在有提供一个iOS版的Demo。请移步这里

Done

如果您顺利的完成以上三步,访问 http://localhost:3280 (端口号根据自己的配置,可能会有差异),使用 username: admin, password: dolores 登陆后端管理页面,添加权限规则,添加角色,添加员工、部门,然后使用iOS客户端登陆,就可以愉快的开始聊天啦~
 
负载均衡

(TODO)

多机容灾

(TODO)

LICENSE Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
更多信息请前往github项目主页

 
这里我对每个repo做一个简单的介绍


Dolores: 项目简介, 整个项目的架构, 数据库设计等等 你想了解的一切都可以在这里看到
dolores-ios: iOS版demo,可以聊天查看组织架构
dolores-android: 哈哈 还没有,当然我们欢迎各路安卓大牛贡献安卓版demo
organization: 组织架构的创建管理、更新、审计等等核心的东西都在这里啦
dolores-server: 为客户端提供restfull api 与环信服务器集成
dolores-admin: 后台管理网站,用于管理部门员工。一个基于React的webapp还很基础,欢迎各位大牛pr.
dolores-ldap-init: 后台数据库的初始化工具,详情可以查看readme
easemob-resty:对环信rest api的封装,让调用环信api更简单
dolores-avatar:生成类似钉钉那样的默认头像


最后再说一点整个服务端是用go来写的,作者也是golang的初学者,如果代码哪里写的有问题或者架构有问题欢迎大家指正THE CALM BEFORE THE STORM.
暴风雨前的宁静
ONE MORE THING 最后附上Dolores项目LOGO
当时作者正在二刷 《西部世界》这部剧,所以选择了女主的名字dolores作为整个项目的名字,而这个logo则寓意剧中的host。 查看全部
  

  前阵子钉钉在微信楼下刷了一波#创业很苦,坚持很酷#的广告,浓浓的“丧”文化风格文案受到了各界褒贬不一的评价,也引起了大家对OA办公系统的关注。
   对企业而言,初选OA办公系统是为了满足需求,解决当下问题,由于OA办公系统的在公司运作流程中扮演的重要性,安全与隐私等问题急需未雨绸缪,“可定制”、“可私有化部署”的OA办公系统成为了更多企业的首选。
公司想自己开发一套IM系统应该从哪里开始呢? 企业通讯录怎么保持同步呢? 企业通讯录的权限管理应该怎么做?

   三个关于OA办公系统的究极问题,从开源的OA办公项目-Dolores(朵拉)诞生迎刃而解了。Dolores项目遵循Apache Licence 2.0 开源协议,可以直接拿来用,也可以修改代码来满足需要并作为开源或商业产品发布/销售。
OA广告图.jpg

关于Dolores?

Dolores是一套完整的企业通信解决方案,一个完整的企业沟通工具(以下简称企业IM),支持以下几个功能:IM消息服务、组织架构管理、工作流集成。


Dolores项目源码地址:https://github.com/DoloresTeam​ 
技术讨论群:641256202(QQ群)

整个解决方案都包括了什么?
  • 企业通讯录的管理:部门/员工的增删改查
  • 通讯录全量更新:全量/增量更新 
  • 企业通讯录权限管理:基于RBAC权限管理模型
  • 企业即时通讯IM:企业通信对IM这块的可靠性要求高,选择了目前比较成熟的IM云服务厂商-环信

 
 
组织架构

企业通讯录可以说是企业沟通中最重的业务之一,能够提供员工各种服务的认证,获取员工的联系方式等。
 
组织架构-Server

服务端主要包括以下功能:
  1. 支持管理人员(例如HR)对部门和员工进行增删改查
  2. 支持部门和员工自定义排序,自定义元信息存储
  3. 权限管理
  4. 员工通讯录视图 (员工根据自己的权限生成通讯录)
  5. 通讯录增量更新 (鉴于移动端特殊的网络环境和设备,通讯录应该支持差量更新)
  6. 集成 IM 用户系统


在这里我们主要讨论以下两个问题:
 
权限管理

  随着企业逐渐的发展,团队壮大为了更有效的沟通,以及保护公司内部的一些商业信息不被泄漏,我们应该为通讯录添加权限管理。

基于Role-based access control(RBAC)的权限管理模型

为了介绍此权限管理模型,我们先解释一下基本概念
  • 角色:通常是指企业中某一个工作岗位,这个岗位具有特定的权利和职责。被赋予此角色的员工,将获得这种权利与职责
  • 权限:被赋予访问实体的权利。在本项目中是指访问部门和访问某一个或者某一类员工的权利
  • 用户-角色分配(User-Role Assignment URA):为某个用户指定一个或者多个角色,此员工将获得这些角色所具有权利的集合
  • 角色-权限分配(Role-Permission Assignment RPA):将权限分配给角色,一个角色可以包含多个权利。在本项目中是指多个访问部门和访问员工的权限


在用户和权限之间引入角色中介,将用户与权限的直接关系弱化为间接关系。
|ˉˉˉ|           |ˉˉ ˉ|          |ˉˉˉˉ ˉˉ|  
| User |---URA---> | Role |<---RPA---| Permission |
|______| |_______| |_____________|

    以角色为中介,首先创建访问每个部门和员工的访问权限,然后创建不同的角色,根据这些角色的职责不同分配不同的权限,建立角色-权限的关系以后,不同的角色将会有不同的权限。根据员工不同的岗位,将对应的角色分配给他们,建立用户-角色关系,这就是RBAC的主要思想。

一个员工可以用户多个角色,一个角色可以用于多个访问权限。RBAC 极大的简化了员工的授权管理。

   由于企业的部门和员工数量很多,在创建权限时管理员不可能去设置每一个权限可以访问的每一个部门和每一个员工。所以本项目将功能和指责类似的部门和员工看作是同一类型,在创建部门和员工的时候为每一个部门和员工分配固有属性type,管理员在设置权限规则的时候只需要指定可访问的部门类型和员工即可。

增量更新

   鉴于移动终端计算资源有限,如网络,存储,电量等,所以通讯录的更新技术应该保证尽量少的资源。另外由于通讯录的特殊性,通讯录的变化需要能实时通知到受影响的在线员工。

基于版本号与变更日志的增量更新模型

   客户端第一次登陆系统以后,我们根据当前登录角色生成对应的通讯录视图,并以当前时间戳作为版本号,返回给客户端。客户端后续通过此版本号增量更新通讯录。

版本号

   版本号有两种:一是客户端当前通讯录版本 c-version, 二是服务端通讯录每一次变化时的版本号s-version

变更日志

   在管理员修改权限规则,或者修改某个岗位的访问规则时会影响大面积员工的通讯录视图,此时如果用增量更新会导致服务器流量异常,因此在这2中情况会清空原来的变更日志并且要求客户端进行一次全量更新。

   如果管理员新增了员工,服务端会根据被修改的员工或者部门type, 反推出所有受影响的员工,然后生成一条变更日志, 例如:
{
"content" : [
{
"cn" : "Lucy.Liu",
"id" : "b4vlfg91scgi1dcju8v0",
"title" : "市场运营负责人",
"email" : [
"lucy.liu@dolores.store"
],
"priority" : "101111",
"name" : "刘小飞",
"telephoneNumber" : "18888888888"
}
],
"createTimestamp" : "20170614063303Z",
"category" : "member",
"action" : "add"
}

客户端在请求增量更新的时候,通过当前登陆ID与版本号,可查找出所有与自己相关的变更日志,然后在客户端数据库中应用这些变更,即可完成同步。

组织架构-Client

   由于现在员工办公设备的多样性,客户端要根据自己公司的情况,覆盖的足够完整,常见的平台有 iOS Android windowsmac linux , 对于后三个平台可以用 Web APP 来覆盖,iOS&Android 用原生的app来提升用户体验。

客户端App主要包括以下功能:
  1. 会话列表
  2. 优秀的聊天界面,历史记录
  3. 组织机构全量/增量更新
  4. 员工个人资料展示


客户端数据库设计

IM数据库设计
 
当前版本使用环信SDK
 
组织架构数据库设计

表设计

客户端组织架构较服务端简单,不关联用户Role,客户端本地存储Staff(员工)和Department(部门)信息:
  • 一个部门可以包含相关子部门和部门员工。该部门员工和部门在视图上处于同级关系。
  • 员工隶属于部门,同一员工可以存在于多个部门。
  • 员工角色用title来表示。


用户在登录客户端成功后,会根据该用户信息创建用户对应的数据库文件,用户表(User)保存用户相关信息,关联该用户staff信息。

客户端组织架构同服务端逻辑。

工作流集成

(TODO)
 
如何使用Dolores

本项目现在已经完成了第一个测试版本,本小节将指导您如何安装使用。

后端数据库

鉴于通讯录对数据库操作的特点多度少写,以及部门之间的树状关系,我们选择LDAP协议来存取数据。

我们有独立的repo来帮助您完成数据库的安装与初始化。请移步这里

组织架构管理

Dolores 初始版本使用Golang实现,大家既可以下载各个平台的可执行包,也可以安装Go语言的开发环境自己编译。

我们有独立的repo来帮助您,运行后端服务。请移步这里

客户端

我们现在有提供一个iOS版的Demo。请移步这里

Done

如果您顺利的完成以上三步,访问 http://localhost:3280 (端口号根据自己的配置,可能会有差异),使用 username: admin, password: dolores 登陆后端管理页面,添加权限规则,添加角色,添加员工、部门,然后使用iOS客户端登陆,就可以愉快的开始聊天啦~
 
负载均衡

(TODO)

多机容灾

(TODO)

LICENSE
 Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

更多信息请前往github项目主页

 
这里我对每个repo做一个简单的介绍


Dolores: 项目简介, 整个项目的架构, 数据库设计等等 你想了解的一切都可以在这里看到
dolores-ios: iOS版demo,可以聊天查看组织架构
dolores-android: 哈哈 还没有,当然我们欢迎各路安卓大牛贡献安卓版demo
organization: 组织架构的创建管理、更新、审计等等核心的东西都在这里啦
dolores-server: 为客户端提供restfull api 与环信服务器集成
dolores-admin: 后台管理网站,用于管理部门员工。一个基于React的webapp还很基础,欢迎各位大牛pr.
dolores-ldap-init: 后台数据库的初始化工具,详情可以查看readme
easemob-resty:对环信rest api的封装,让调用环信api更简单
dolores-avatar:生成类似钉钉那样的默认头像


最后再说一点整个服务端是用go来写的,作者也是golang的初学者,如果代码哪里写的有问题或者架构有问题欢迎大家指正
THE CALM BEFORE THE STORM.
暴风雨前的宁静

ONE MORE THING 最后附上Dolores项目LOGO
当时作者正在二刷 《西部世界》这部剧,所以选择了女主的名字dolores作为整个项目的名字,而这个logo则寓意剧中的host。
687474703a2f2f6f7131696e636b76692e626b742e636c6f7564646e2e636f6d2f646f6c6f726573313032342e706e67.png
6
评论

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

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

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

 
Android篇

昵称头像篇

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

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

 
开源项目

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

【视频教程+源码】基于环信IM做一个仿微信APP-更新ing 郭永峰 高仿微信 仿微信 环信 XMPP

郭永峰 发表了文章 • 9708 次浏览 • 2017-05-16 15:29 • 来自相关话题

我只是一个普通人,做人要谦虚。
我不是大神,我也不是很厉害的。
天外有天,人外有人。
老师引入门,修行靠个人。
希望能帮助大家,谢谢。
    大家好,我是郭永峰(峰哥) | 一个普通大学计算机系毕业的大学生,曾就职于澳门遊澳集团有限公司,负责大型银联支付业务系统、跨国际短信业务系统(基于电信的SGIP)以及集团内部通讯系统 (负责android和openfire后台二次开发)的主要开发任务,担任项目负责人。13年就职于广州拓谷科技有限公司负责“酷蛙”车联网产品研发及汽车销售产品研发。14来年到17年2月份,就职于国内知名教育机构,负责教学研发及授课的工作。
 
本人现状况:
  
   在家录制教学视频(无收入),搞工作室,组建团队成立公司,如果大家觉得分享内容很喜欢,可以给我打点赏支持本人的工作室,二维码在文末,就不影响阅读了。

 
郭永峰IT教育工作室于2017年4月12日成立!
 
成立原因:

希望把近10年来从事IT互联网的知识分享给大家,包括Linux,WindowServer,Java,PHP,Android,iOS,H5等等等。
 

进入正题,本套课程基于环信IM教大家如何做一个类似微信的APP,只用于技术交流,请勿用于任何商业用途。
4月12号成立工作室,现在18号,过了一个星期一个星期录了5天的环信教程视频,我将放在网盘免费分享环信的教程视频主要是针对有开发经验者教程主要是使用环信来模仿微信来做一个即时通讯的案例课程主要是先讲socket基础 -> 环信 ->自定义协议希望这些教程视频能帮助大家,对即时通讯、socket和自定义协议有个较深入的了解同时能希望大家在面试时,在即时通讯这块不在陌生
  持续更新

第一阶段:即时通讯的了解和微信APP开发前的准备!

【视频教程+源码】基于环信IM做一个仿微信APP-01.即时通讯简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-02.XMPP简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-03.XMPP实现即时通信的准备工作(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-04.环信简介(了解) 

【视频教程+源码】基于环信IM做一个仿微信APP-05.集成环信的前提准备(掌握)
 
【视频教程+源码】基于环信IM做一个仿微信APP-06.环信SDK的版本的区别(掌握)

【视频教程+源码】基于环信IM做一个仿微信APP-07.微信-项目创建及代码目录结构规范(MVC)

【视频教程+源码】基于环信IM做一个仿微信APP-08.微信-集成环信SDK

【视频教程+源码】基于环信IM做一个仿微信APP-09.微信-登录界面排版

【视频教程+源码】基于环信IM做一个仿微信APP-10.微信-主界面搭建

【视频教程+源码】基于环信IM做一个仿微信APP-11.微信-注册功能

【视频教程+源码】基于环信IM做一个仿微信APP- 12.微信-登录功能

【视频教程+源码】基于环信IM做一个仿微信APP- 13.微信-自动登录

【视频教程+源码】基于环信IM做一个仿微信APP- 14.微信-主动退出
 
【视频教程+源码】基于环信IM做一个仿微信APP-15.微信-在其它设备登录
 
整个项目源码,git地址https://github.com/mayaole/fWeiXin

 微信打赏






支付宝打赏






谢谢大家的支持,个人微信号清扫描下面张图






 
郭永峰IT交流QQ群请加:596441895 查看全部
我只是一个普通人,做人要谦虚。
我不是大神,我也不是很厉害的。
天外有天,人外有人。
老师引入门,修行靠个人。
希望能帮助大家,谢谢。

    大家好,我是郭永峰(峰哥) | 一个普通大学计算机系毕业的大学生,曾就职于澳门遊澳集团有限公司,负责大型银联支付业务系统、跨国际短信业务系统(基于电信的SGIP)以及集团内部通讯系统 (负责android和openfire后台二次开发)的主要开发任务,担任项目负责人。13年就职于广州拓谷科技有限公司负责“酷蛙”车联网产品研发及汽车销售产品研发。14来年到17年2月份,就职于国内知名教育机构,负责教学研发及授课的工作。
 
本人现状况:
  
   在家录制教学视频(无收入),搞工作室,组建团队成立公司,如果大家觉得分享内容很喜欢,可以给我打点赏支持本人的工作室,二维码在文末,就不影响阅读了。

 
郭永峰IT教育工作室于2017年4月12日成立!
 
成立原因:

希望把近10年来从事IT互联网的知识分享给大家,包括Linux,WindowServer,Java,PHP,Android,iOS,H5等等等。
 

进入正题,本套课程基于环信IM教大家如何做一个类似微信的APP,只用于技术交流,请勿用于任何商业用途。
  1. 4月12号成立工作室,现在18号,过了一个星期
  2. 一个星期录了5天的环信教程视频,我将放在网盘免费分享
  3. 环信的教程视频主要是针对有开发经验者
  4. 教程主要是使用环信来模仿微信来做一个即时通讯的案例
  5. 课程主要是先讲socket基础 -> 环信 ->自定义协议
  6. 希望这些教程视频能帮助大家,对即时通讯、socket和自定义协议有个较深入的了解
  7. 同时能希望大家在面试时,在即时通讯这块不在陌生

  持续更新

第一阶段:即时通讯的了解和微信APP开发前的准备!

【视频教程+源码】基于环信IM做一个仿微信APP-01.即时通讯简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-02.XMPP简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-03.XMPP实现即时通信的准备工作(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-04.环信简介(了解) 

【视频教程+源码】基于环信IM做一个仿微信APP-05.集成环信的前提准备(掌握)
 
【视频教程+源码】基于环信IM做一个仿微信APP-06.环信SDK的版本的区别(掌握)

【视频教程+源码】基于环信IM做一个仿微信APP-07.微信-项目创建及代码目录结构规范(MVC)

【视频教程+源码】基于环信IM做一个仿微信APP-08.微信-集成环信SDK

【视频教程+源码】基于环信IM做一个仿微信APP-09.微信-登录界面排版

【视频教程+源码】基于环信IM做一个仿微信APP-10.微信-主界面搭建

【视频教程+源码】基于环信IM做一个仿微信APP-11.微信-注册功能

【视频教程+源码】基于环信IM做一个仿微信APP- 12.微信-登录功能

【视频教程+源码】基于环信IM做一个仿微信APP- 13.微信-自动登录

【视频教程+源码】基于环信IM做一个仿微信APP- 14.微信-主动退出
 
【视频教程+源码】基于环信IM做一个仿微信APP-15.微信-在其它设备登录
 
整个项目源码,git地址https://github.com/mayaole/fWeiXin

 微信打赏

微信.png


支付宝打赏

支付宝.png


谢谢大家的支持,个人微信号清扫描下面张图

个人.png


 
郭永峰IT交流QQ群请加:596441895
6
评论

【开源OA项目】基于环信IM开发完整的企业通讯解决方案-Dolores Dolores OA 开源项目

KevinGong 发表了文章 • 7445 次浏览 • 2017-06-26 10:53 • 来自相关话题

  

  前阵子钉钉在微信楼下刷了一波#创业很苦,坚持很酷#的广告,浓浓的“丧”文化风格文案受到了各界褒贬不一的评价,也引起了大家对OA办公系统的关注。
   对企业而言,初选OA办公系统是为了满足需求,解决当下问题,由于OA办公系统的在公司运作流程中扮演的重要性,安全与隐私等问题急需未雨绸缪,“可定制”、“可私有化部署”的OA办公系统成为了更多企业的首选。公司想自己开发一套IM系统应该从哪里开始呢? 企业通讯录怎么保持同步呢? 企业通讯录的权限管理应该怎么做?
   三个关于OA办公系统的究极问题,从开源的OA办公项目-Dolores(朵拉)诞生迎刃而解了。Dolores项目遵循Apache Licence 2.0 开源协议,可以直接拿来用,也可以修改代码来满足需要并作为开源或商业产品发布/销售。




关于Dolores?
Dolores是一套完整的企业通信解决方案,一个完整的企业沟通工具(以下简称企业IM),支持以下几个功能:IM消息服务、组织架构管理、工作流集成。
Dolores项目源码地址:https://github.com/DoloresTeam​ 
技术讨论群:641256202(QQ群)

整个解决方案都包括了什么?
企业通讯录的管理:部门/员工的增删改查通讯录全量更新:全量/增量更新 企业通讯录权限管理:基于RBAC权限管理模型企业即时通讯IM:企业通信对IM这块的可靠性要求高,选择了目前比较成熟的IM云服务厂商-环信
 
 
组织架构

企业通讯录可以说是企业沟通中最重的业务之一,能够提供员工各种服务的认证,获取员工的联系方式等。
 
组织架构-Server

服务端主要包括以下功能:
支持管理人员(例如HR)对部门和员工进行增删改查支持部门和员工自定义排序,自定义元信息存储权限管理员工通讯录视图 (员工根据自己的权限生成通讯录)通讯录增量更新 (鉴于移动端特殊的网络环境和设备,通讯录应该支持差量更新)集成 IM 用户系统

在这里我们主要讨论以下两个问题:
 
权限管理

  随着企业逐渐的发展,团队壮大为了更有效的沟通,以及保护公司内部的一些商业信息不被泄漏,我们应该为通讯录添加权限管理。

基于Role-based access control(RBAC)的权限管理模型

为了介绍此权限管理模型,我们先解释一下基本概念
角色:通常是指企业中某一个工作岗位,这个岗位具有特定的权利和职责。被赋予此角色的员工,将获得这种权利与职责权限:被赋予访问实体的权利。在本项目中是指访问部门和访问某一个或者某一类员工的权利用户-角色分配(User-Role Assignment URA):为某个用户指定一个或者多个角色,此员工将获得这些角色所具有权利的集合角色-权限分配(Role-Permission Assignment RPA):将权限分配给角色,一个角色可以包含多个权利。在本项目中是指多个访问部门和访问员工的权限

在用户和权限之间引入角色中介,将用户与权限的直接关系弱化为间接关系。|ˉˉˉ| |ˉˉ ˉ| |ˉˉˉˉ ˉˉ|
| User |---URA---> | Role |<---RPA---| Permission |
|______| |_______| |_____________|
    以角色为中介,首先创建访问每个部门和员工的访问权限,然后创建不同的角色,根据这些角色的职责不同分配不同的权限,建立角色-权限的关系以后,不同的角色将会有不同的权限。根据员工不同的岗位,将对应的角色分配给他们,建立用户-角色关系,这就是RBAC的主要思想。

一个员工可以用户多个角色,一个角色可以用于多个访问权限。RBAC 极大的简化了员工的授权管理。

   由于企业的部门和员工数量很多,在创建权限时管理员不可能去设置每一个权限可以访问的每一个部门和每一个员工。所以本项目将功能和指责类似的部门和员工看作是同一类型,在创建部门和员工的时候为每一个部门和员工分配固有属性type,管理员在设置权限规则的时候只需要指定可访问的部门类型和员工即可。

增量更新

   鉴于移动终端计算资源有限,如网络,存储,电量等,所以通讯录的更新技术应该保证尽量少的资源。另外由于通讯录的特殊性,通讯录的变化需要能实时通知到受影响的在线员工。

基于版本号与变更日志的增量更新模型

   客户端第一次登陆系统以后,我们根据当前登录角色生成对应的通讯录视图,并以当前时间戳作为版本号,返回给客户端。客户端后续通过此版本号增量更新通讯录。

版本号

   版本号有两种:一是客户端当前通讯录版本 c-version, 二是服务端通讯录每一次变化时的版本号s-version

变更日志

   在管理员修改权限规则,或者修改某个岗位的访问规则时会影响大面积员工的通讯录视图,此时如果用增量更新会导致服务器流量异常,因此在这2中情况会清空原来的变更日志并且要求客户端进行一次全量更新。

   如果管理员新增了员工,服务端会根据被修改的员工或者部门type, 反推出所有受影响的员工,然后生成一条变更日志, 例如:{
"content" : [
{
"cn" : "Lucy.Liu",
"id" : "b4vlfg91scgi1dcju8v0",
"title" : "市场运营负责人",
"email" : [
"lucy.liu@dolores.store"
],
"priority" : "101111",
"name" : "刘小飞",
"telephoneNumber" : "18888888888"
}
],
"createTimestamp" : "20170614063303Z",
"category" : "member",
"action" : "add"
}
客户端在请求增量更新的时候,通过当前登陆ID与版本号,可查找出所有与自己相关的变更日志,然后在客户端数据库中应用这些变更,即可完成同步。

组织架构-Client

   由于现在员工办公设备的多样性,客户端要根据自己公司的情况,覆盖的足够完整,常见的平台有 iOS Android windowsmac linux , 对于后三个平台可以用 Web APP 来覆盖,iOS&Android 用原生的app来提升用户体验。

客户端App主要包括以下功能:
会话列表优秀的聊天界面,历史记录组织机构全量/增量更新员工个人资料展示

客户端数据库设计

IM数据库设计
 
当前版本使用环信SDK
 
组织架构数据库设计

表设计

客户端组织架构较服务端简单,不关联用户Role,客户端本地存储Staff(员工)和Department(部门)信息:
一个部门可以包含相关子部门和部门员工。该部门员工和部门在视图上处于同级关系。员工隶属于部门,同一员工可以存在于多个部门。员工角色用title来表示。

用户在登录客户端成功后,会根据该用户信息创建用户对应的数据库文件,用户表(User)保存用户相关信息,关联该用户staff信息。

客户端组织架构同服务端逻辑。

工作流集成

(TODO)
 
如何使用Dolores

本项目现在已经完成了第一个测试版本,本小节将指导您如何安装使用。

后端数据库

鉴于通讯录对数据库操作的特点多度少写,以及部门之间的树状关系,我们选择LDAP协议来存取数据。

我们有独立的repo来帮助您完成数据库的安装与初始化。请移步这里

组织架构管理

Dolores 初始版本使用Golang实现,大家既可以下载各个平台的可执行包,也可以安装Go语言的开发环境自己编译。

我们有独立的repo来帮助您,运行后端服务。请移步这里

客户端

我们现在有提供一个iOS版的Demo。请移步这里

Done

如果您顺利的完成以上三步,访问 http://localhost:3280 (端口号根据自己的配置,可能会有差异),使用 username: admin, password: dolores 登陆后端管理页面,添加权限规则,添加角色,添加员工、部门,然后使用iOS客户端登陆,就可以愉快的开始聊天啦~
 
负载均衡

(TODO)

多机容灾

(TODO)

LICENSE Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
更多信息请前往github项目主页

 
这里我对每个repo做一个简单的介绍


Dolores: 项目简介, 整个项目的架构, 数据库设计等等 你想了解的一切都可以在这里看到
dolores-ios: iOS版demo,可以聊天查看组织架构
dolores-android: 哈哈 还没有,当然我们欢迎各路安卓大牛贡献安卓版demo
organization: 组织架构的创建管理、更新、审计等等核心的东西都在这里啦
dolores-server: 为客户端提供restfull api 与环信服务器集成
dolores-admin: 后台管理网站,用于管理部门员工。一个基于React的webapp还很基础,欢迎各位大牛pr.
dolores-ldap-init: 后台数据库的初始化工具,详情可以查看readme
easemob-resty:对环信rest api的封装,让调用环信api更简单
dolores-avatar:生成类似钉钉那样的默认头像


最后再说一点整个服务端是用go来写的,作者也是golang的初学者,如果代码哪里写的有问题或者架构有问题欢迎大家指正THE CALM BEFORE THE STORM.
暴风雨前的宁静
ONE MORE THING 最后附上Dolores项目LOGO
当时作者正在二刷 《西部世界》这部剧,所以选择了女主的名字dolores作为整个项目的名字,而这个logo则寓意剧中的host。 查看全部
  

  前阵子钉钉在微信楼下刷了一波#创业很苦,坚持很酷#的广告,浓浓的“丧”文化风格文案受到了各界褒贬不一的评价,也引起了大家对OA办公系统的关注。
   对企业而言,初选OA办公系统是为了满足需求,解决当下问题,由于OA办公系统的在公司运作流程中扮演的重要性,安全与隐私等问题急需未雨绸缪,“可定制”、“可私有化部署”的OA办公系统成为了更多企业的首选。
公司想自己开发一套IM系统应该从哪里开始呢? 企业通讯录怎么保持同步呢? 企业通讯录的权限管理应该怎么做?

   三个关于OA办公系统的究极问题,从开源的OA办公项目-Dolores(朵拉)诞生迎刃而解了。Dolores项目遵循Apache Licence 2.0 开源协议,可以直接拿来用,也可以修改代码来满足需要并作为开源或商业产品发布/销售。
OA广告图.jpg

关于Dolores?

Dolores是一套完整的企业通信解决方案,一个完整的企业沟通工具(以下简称企业IM),支持以下几个功能:IM消息服务、组织架构管理、工作流集成。


Dolores项目源码地址:https://github.com/DoloresTeam​ 
技术讨论群:641256202(QQ群)

整个解决方案都包括了什么?
  • 企业通讯录的管理:部门/员工的增删改查
  • 通讯录全量更新:全量/增量更新 
  • 企业通讯录权限管理:基于RBAC权限管理模型
  • 企业即时通讯IM:企业通信对IM这块的可靠性要求高,选择了目前比较成熟的IM云服务厂商-环信

 
 
组织架构

企业通讯录可以说是企业沟通中最重的业务之一,能够提供员工各种服务的认证,获取员工的联系方式等。
 
组织架构-Server

服务端主要包括以下功能:
  1. 支持管理人员(例如HR)对部门和员工进行增删改查
  2. 支持部门和员工自定义排序,自定义元信息存储
  3. 权限管理
  4. 员工通讯录视图 (员工根据自己的权限生成通讯录)
  5. 通讯录增量更新 (鉴于移动端特殊的网络环境和设备,通讯录应该支持差量更新)
  6. 集成 IM 用户系统


在这里我们主要讨论以下两个问题:
 
权限管理

  随着企业逐渐的发展,团队壮大为了更有效的沟通,以及保护公司内部的一些商业信息不被泄漏,我们应该为通讯录添加权限管理。

基于Role-based access control(RBAC)的权限管理模型

为了介绍此权限管理模型,我们先解释一下基本概念
  • 角色:通常是指企业中某一个工作岗位,这个岗位具有特定的权利和职责。被赋予此角色的员工,将获得这种权利与职责
  • 权限:被赋予访问实体的权利。在本项目中是指访问部门和访问某一个或者某一类员工的权利
  • 用户-角色分配(User-Role Assignment URA):为某个用户指定一个或者多个角色,此员工将获得这些角色所具有权利的集合
  • 角色-权限分配(Role-Permission Assignment RPA):将权限分配给角色,一个角色可以包含多个权利。在本项目中是指多个访问部门和访问员工的权限


在用户和权限之间引入角色中介,将用户与权限的直接关系弱化为间接关系。
|ˉˉˉ|           |ˉˉ ˉ|          |ˉˉˉˉ ˉˉ|  
| User |---URA---> | Role |<---RPA---| Permission |
|______| |_______| |_____________|

    以角色为中介,首先创建访问每个部门和员工的访问权限,然后创建不同的角色,根据这些角色的职责不同分配不同的权限,建立角色-权限的关系以后,不同的角色将会有不同的权限。根据员工不同的岗位,将对应的角色分配给他们,建立用户-角色关系,这就是RBAC的主要思想。

一个员工可以用户多个角色,一个角色可以用于多个访问权限。RBAC 极大的简化了员工的授权管理。

   由于企业的部门和员工数量很多,在创建权限时管理员不可能去设置每一个权限可以访问的每一个部门和每一个员工。所以本项目将功能和指责类似的部门和员工看作是同一类型,在创建部门和员工的时候为每一个部门和员工分配固有属性type,管理员在设置权限规则的时候只需要指定可访问的部门类型和员工即可。

增量更新

   鉴于移动终端计算资源有限,如网络,存储,电量等,所以通讯录的更新技术应该保证尽量少的资源。另外由于通讯录的特殊性,通讯录的变化需要能实时通知到受影响的在线员工。

基于版本号与变更日志的增量更新模型

   客户端第一次登陆系统以后,我们根据当前登录角色生成对应的通讯录视图,并以当前时间戳作为版本号,返回给客户端。客户端后续通过此版本号增量更新通讯录。

版本号

   版本号有两种:一是客户端当前通讯录版本 c-version, 二是服务端通讯录每一次变化时的版本号s-version

变更日志

   在管理员修改权限规则,或者修改某个岗位的访问规则时会影响大面积员工的通讯录视图,此时如果用增量更新会导致服务器流量异常,因此在这2中情况会清空原来的变更日志并且要求客户端进行一次全量更新。

   如果管理员新增了员工,服务端会根据被修改的员工或者部门type, 反推出所有受影响的员工,然后生成一条变更日志, 例如:
{
"content" : [
{
"cn" : "Lucy.Liu",
"id" : "b4vlfg91scgi1dcju8v0",
"title" : "市场运营负责人",
"email" : [
"lucy.liu@dolores.store"
],
"priority" : "101111",
"name" : "刘小飞",
"telephoneNumber" : "18888888888"
}
],
"createTimestamp" : "20170614063303Z",
"category" : "member",
"action" : "add"
}

客户端在请求增量更新的时候,通过当前登陆ID与版本号,可查找出所有与自己相关的变更日志,然后在客户端数据库中应用这些变更,即可完成同步。

组织架构-Client

   由于现在员工办公设备的多样性,客户端要根据自己公司的情况,覆盖的足够完整,常见的平台有 iOS Android windowsmac linux , 对于后三个平台可以用 Web APP 来覆盖,iOS&Android 用原生的app来提升用户体验。

客户端App主要包括以下功能:
  1. 会话列表
  2. 优秀的聊天界面,历史记录
  3. 组织机构全量/增量更新
  4. 员工个人资料展示


客户端数据库设计

IM数据库设计
 
当前版本使用环信SDK
 
组织架构数据库设计

表设计

客户端组织架构较服务端简单,不关联用户Role,客户端本地存储Staff(员工)和Department(部门)信息:
  • 一个部门可以包含相关子部门和部门员工。该部门员工和部门在视图上处于同级关系。
  • 员工隶属于部门,同一员工可以存在于多个部门。
  • 员工角色用title来表示。


用户在登录客户端成功后,会根据该用户信息创建用户对应的数据库文件,用户表(User)保存用户相关信息,关联该用户staff信息。

客户端组织架构同服务端逻辑。

工作流集成

(TODO)
 
如何使用Dolores

本项目现在已经完成了第一个测试版本,本小节将指导您如何安装使用。

后端数据库

鉴于通讯录对数据库操作的特点多度少写,以及部门之间的树状关系,我们选择LDAP协议来存取数据。

我们有独立的repo来帮助您完成数据库的安装与初始化。请移步这里

组织架构管理

Dolores 初始版本使用Golang实现,大家既可以下载各个平台的可执行包,也可以安装Go语言的开发环境自己编译。

我们有独立的repo来帮助您,运行后端服务。请移步这里

客户端

我们现在有提供一个iOS版的Demo。请移步这里

Done

如果您顺利的完成以上三步,访问 http://localhost:3280 (端口号根据自己的配置,可能会有差异),使用 username: admin, password: dolores 登陆后端管理页面,添加权限规则,添加角色,添加员工、部门,然后使用iOS客户端登陆,就可以愉快的开始聊天啦~
 
负载均衡

(TODO)

多机容灾

(TODO)

LICENSE
 Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

更多信息请前往github项目主页

 
这里我对每个repo做一个简单的介绍


Dolores: 项目简介, 整个项目的架构, 数据库设计等等 你想了解的一切都可以在这里看到
dolores-ios: iOS版demo,可以聊天查看组织架构
dolores-android: 哈哈 还没有,当然我们欢迎各路安卓大牛贡献安卓版demo
organization: 组织架构的创建管理、更新、审计等等核心的东西都在这里啦
dolores-server: 为客户端提供restfull api 与环信服务器集成
dolores-admin: 后台管理网站,用于管理部门员工。一个基于React的webapp还很基础,欢迎各位大牛pr.
dolores-ldap-init: 后台数据库的初始化工具,详情可以查看readme
easemob-resty:对环信rest api的封装,让调用环信api更简单
dolores-avatar:生成类似钉钉那样的默认头像


最后再说一点整个服务端是用go来写的,作者也是golang的初学者,如果代码哪里写的有问题或者架构有问题欢迎大家指正
THE CALM BEFORE THE STORM.
暴风雨前的宁静

ONE MORE THING 最后附上Dolores项目LOGO
当时作者正在二刷 《西部世界》这部剧,所以选择了女主的名字dolores作为整个项目的名字,而这个logo则寓意剧中的host。
687474703a2f2f6f7131696e636b76692e626b742e636c6f7564646e2e636f6d2f646f6c6f726573313032342e706e67.png
6
评论

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

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

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

 
Android篇

昵称头像篇

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

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

 
开源项目

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

【视频教程+源码】基于环信IM做一个仿微信APP-更新ing 郭永峰 高仿微信 仿微信 环信 XMPP

郭永峰 发表了文章 • 9708 次浏览 • 2017-05-16 15:29 • 来自相关话题

我只是一个普通人,做人要谦虚。
我不是大神,我也不是很厉害的。
天外有天,人外有人。
老师引入门,修行靠个人。
希望能帮助大家,谢谢。
    大家好,我是郭永峰(峰哥) | 一个普通大学计算机系毕业的大学生,曾就职于澳门遊澳集团有限公司,负责大型银联支付业务系统、跨国际短信业务系统(基于电信的SGIP)以及集团内部通讯系统 (负责android和openfire后台二次开发)的主要开发任务,担任项目负责人。13年就职于广州拓谷科技有限公司负责“酷蛙”车联网产品研发及汽车销售产品研发。14来年到17年2月份,就职于国内知名教育机构,负责教学研发及授课的工作。
 
本人现状况:
  
   在家录制教学视频(无收入),搞工作室,组建团队成立公司,如果大家觉得分享内容很喜欢,可以给我打点赏支持本人的工作室,二维码在文末,就不影响阅读了。

 
郭永峰IT教育工作室于2017年4月12日成立!
 
成立原因:

希望把近10年来从事IT互联网的知识分享给大家,包括Linux,WindowServer,Java,PHP,Android,iOS,H5等等等。
 

进入正题,本套课程基于环信IM教大家如何做一个类似微信的APP,只用于技术交流,请勿用于任何商业用途。
4月12号成立工作室,现在18号,过了一个星期一个星期录了5天的环信教程视频,我将放在网盘免费分享环信的教程视频主要是针对有开发经验者教程主要是使用环信来模仿微信来做一个即时通讯的案例课程主要是先讲socket基础 -> 环信 ->自定义协议希望这些教程视频能帮助大家,对即时通讯、socket和自定义协议有个较深入的了解同时能希望大家在面试时,在即时通讯这块不在陌生
  持续更新

第一阶段:即时通讯的了解和微信APP开发前的准备!

【视频教程+源码】基于环信IM做一个仿微信APP-01.即时通讯简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-02.XMPP简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-03.XMPP实现即时通信的准备工作(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-04.环信简介(了解) 

【视频教程+源码】基于环信IM做一个仿微信APP-05.集成环信的前提准备(掌握)
 
【视频教程+源码】基于环信IM做一个仿微信APP-06.环信SDK的版本的区别(掌握)

【视频教程+源码】基于环信IM做一个仿微信APP-07.微信-项目创建及代码目录结构规范(MVC)

【视频教程+源码】基于环信IM做一个仿微信APP-08.微信-集成环信SDK

【视频教程+源码】基于环信IM做一个仿微信APP-09.微信-登录界面排版

【视频教程+源码】基于环信IM做一个仿微信APP-10.微信-主界面搭建

【视频教程+源码】基于环信IM做一个仿微信APP-11.微信-注册功能

【视频教程+源码】基于环信IM做一个仿微信APP- 12.微信-登录功能

【视频教程+源码】基于环信IM做一个仿微信APP- 13.微信-自动登录

【视频教程+源码】基于环信IM做一个仿微信APP- 14.微信-主动退出
 
【视频教程+源码】基于环信IM做一个仿微信APP-15.微信-在其它设备登录
 
整个项目源码,git地址https://github.com/mayaole/fWeiXin

 微信打赏






支付宝打赏






谢谢大家的支持,个人微信号清扫描下面张图






 
郭永峰IT交流QQ群请加:596441895 查看全部
我只是一个普通人,做人要谦虚。
我不是大神,我也不是很厉害的。
天外有天,人外有人。
老师引入门,修行靠个人。
希望能帮助大家,谢谢。

    大家好,我是郭永峰(峰哥) | 一个普通大学计算机系毕业的大学生,曾就职于澳门遊澳集团有限公司,负责大型银联支付业务系统、跨国际短信业务系统(基于电信的SGIP)以及集团内部通讯系统 (负责android和openfire后台二次开发)的主要开发任务,担任项目负责人。13年就职于广州拓谷科技有限公司负责“酷蛙”车联网产品研发及汽车销售产品研发。14来年到17年2月份,就职于国内知名教育机构,负责教学研发及授课的工作。
 
本人现状况:
  
   在家录制教学视频(无收入),搞工作室,组建团队成立公司,如果大家觉得分享内容很喜欢,可以给我打点赏支持本人的工作室,二维码在文末,就不影响阅读了。

 
郭永峰IT教育工作室于2017年4月12日成立!
 
成立原因:

希望把近10年来从事IT互联网的知识分享给大家,包括Linux,WindowServer,Java,PHP,Android,iOS,H5等等等。
 

进入正题,本套课程基于环信IM教大家如何做一个类似微信的APP,只用于技术交流,请勿用于任何商业用途。
  1. 4月12号成立工作室,现在18号,过了一个星期
  2. 一个星期录了5天的环信教程视频,我将放在网盘免费分享
  3. 环信的教程视频主要是针对有开发经验者
  4. 教程主要是使用环信来模仿微信来做一个即时通讯的案例
  5. 课程主要是先讲socket基础 -> 环信 ->自定义协议
  6. 希望这些教程视频能帮助大家,对即时通讯、socket和自定义协议有个较深入的了解
  7. 同时能希望大家在面试时,在即时通讯这块不在陌生

  持续更新

第一阶段:即时通讯的了解和微信APP开发前的准备!

【视频教程+源码】基于环信IM做一个仿微信APP-01.即时通讯简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-02.XMPP简介(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-03.XMPP实现即时通信的准备工作(了解)

【视频教程+源码】基于环信IM做一个仿微信APP-04.环信简介(了解) 

【视频教程+源码】基于环信IM做一个仿微信APP-05.集成环信的前提准备(掌握)
 
【视频教程+源码】基于环信IM做一个仿微信APP-06.环信SDK的版本的区别(掌握)

【视频教程+源码】基于环信IM做一个仿微信APP-07.微信-项目创建及代码目录结构规范(MVC)

【视频教程+源码】基于环信IM做一个仿微信APP-08.微信-集成环信SDK

【视频教程+源码】基于环信IM做一个仿微信APP-09.微信-登录界面排版

【视频教程+源码】基于环信IM做一个仿微信APP-10.微信-主界面搭建

【视频教程+源码】基于环信IM做一个仿微信APP-11.微信-注册功能

【视频教程+源码】基于环信IM做一个仿微信APP- 12.微信-登录功能

【视频教程+源码】基于环信IM做一个仿微信APP- 13.微信-自动登录

【视频教程+源码】基于环信IM做一个仿微信APP- 14.微信-主动退出
 
【视频教程+源码】基于环信IM做一个仿微信APP-15.微信-在其它设备登录
 
整个项目源码,git地址https://github.com/mayaole/fWeiXin

 微信打赏

微信.png


支付宝打赏

支付宝.png


谢谢大家的支持,个人微信号清扫描下面张图

个人.png


 
郭永峰IT交流QQ群请加:596441895
0
评论

iOS 环信 集成 详细步骤图文 iOS 环信 集成 详细步骤图文

神的传说 发表了文章 • 737 次浏览 • 2017-01-11 13:26 • 来自相关话题

环信的教程:

没有初始化SDK  

去AppDelegate里面初始化

 

密码

 

User not exist         ??????????

每一个应用都有自己的注册用户  去你的后台管理   去看你的注册的用户数   

为什么demo的可以跑起来????????

是在它的应用下注册的

 

怎么去注册用户  -注册用户

用户名字可以相同   不同的应用   

 

 

那个打印的loginInfo 是这个字典的也就是用户的登录信息

 

你会发现打印的loginInfo上面还有一坨恶心的东西,那个是环信SDK自己打印的日志信息

 

SEND   和      RECV    使用的是XMPP协议    所以 数据的格式是XML   一般的HTTP协议的话他就是JSON格式的

这个是app把客户端登录的信息发给环信服务器后打印出来的日志      是不是很烦

 

如何去在哪儿隐藏它的控制台的日志信息 ?????????

去初始化的时候把它隐藏  有一个otherConfig的东西   右键-jump to Define

进去瞅瞅--

复制它的key 给他设置为NO

这个时候它的控制台的日志信息就被屏蔽了

 

 

跟环信交互的所有类都有这个

[EaseMob sharedInstance].chatManager

 

 

注册的时候代码:


如果你把这onQueue改为nil的话他默认也是在主线程的

 

然后你在去环信的开发中心刷新IM用户 你会发现他多了一个

发送给的数据给服务器的时候还是XML格式,里面的SDK帮你封装了,不用你自己去接触

 

 

---自动登录------------------------------------

 

看到它的主界面只有三个tabbar

 进去 mainstoryboard里面 删除原始的viewcontroller  拖入一个 tabbarController     去掉原始的tabbar 的两个子控制器   记得给它的isinitial 那个选项钩上   然后拖入三个navigationcontroller(这个根据你的界面而定)

 

选中给每个的Item  的title属性可以更改

然后在登录成功中写上加载storyboard的方法

你会发现你已经跳转进去
如何实现自动登录?????????????????

  实现原理:把你的登录信息保存在沙盒中     程序启动时候发送登录请求

  只要你在第一次登录成功后发送环信自带登录的网络请求去实现、

环信自己帮你实现上面的东西

 

具体实现

在登录成功的下面写上

[[EaseMob sharedInstance].chatManager  setIsAutoLoginEnabled:YES]

然后去在AppDelegte里面把他的沙盒路径拿到
然后再控制台你可以看到这些信息,其中的账号密码信息你会发现他被加密了,有没有?
如何监听是否是已经处于登录状态了这个地方有个代理  环信的代理方法

在AppDelegate方法里面进去 在启动方法里面写
你会发现它的那个啥没有完成界面的跳转    但是控制台却是带那个登陆成功了
这个时候我们还缺一步骤  之前我们在自动登录时候我们调用的是set方法

这个时候我们要实现它的 get方法     写在监听登录状态的下面

  //如果登录过直接来到主界面
    if([[EaseMob sharedInstance].chatManager isAutoLoginEnabled]){

        self.window.rootViewController = [UIStoryboard storyboardWithName:@"Main" bundle:nil].instantiateInitialViewController;

    }

    
=------------自动连接--------------------------

 

网络通不通的时候类似微信那种网络不通的实现

去那个main.storyboard里面把那会话的导航控制器跳转的那个类继承改为你自己创建的那个UItableViewController

 

1.在会话里面监听的网络的状态  环信的有很多个代理

去那个.m文件里面去实现
点击那个EMChatManagerDelegate 里面去实现 EMChatManagerUtilDelegate里面的这个方法就OK了

- (void)didConnectionStateChanged:(EMConnectionState)connectionState;
在真机上面测试的时候 网络连接成功不代表客户端和服务器端连接成功

 

 

还有自动连接的状态的监听 也是加上他的代理方法就行了


--------添加好友请求-----------------------------

1.是用环信的思想

 所有的网络请求   [EaseMob sharedInstance].chatManager 由这个管理器发起的

 

2.所有结果(自动登录 自动连接)通过代理来回调完成

[EaseMob sharedInstance].chatManager的addDelegate来完成

 

3.EMChatManagerBuddyDelegate 这个代理实现了对用户的基本操作

1.添加好友      2.从本地获取好友      3.从服务器列表获取最新的好友     4.接受好友添加请求

5.删除好友       6.被好友从名单上面删除  

 

 

在navigation  的第二个控制器上面加上一个UIbarbarItem   选择自定义   然后+    

再去创建一个UIviewController     然后再去实现用个+号去拖一个线  

 

 可以在上面加上navigationItem 上改为添加好友

再去新建一个控制器AdressBooking 通讯录  这个类是继承于UIviewController
是用环信最简单的方法 ,把官方的Demo直接拿过来用   直接跟改它的Appdelegate里面的APPKey

这样你就收到了申请    注意   这是最简单的方式

 

 

还有一点 你要在每个控制器里面写上你环信的代理方法

这样就能保证你下面写的环信 的每一个方法会被自动调用了
代理方法:

代理的销毁

 

 

好友请求消息反馈写在什么地方   因为你进去那个会话的控制器里面了的话就会被销毁了。我们可以把它的好友请求写在会话控制器   这样他每个控制器都可以收到了  也没有必要写在AppDelegate里面 可以去尝试一下

 

 

 

 

 

 

 

 

 

 

---------现实好友界面列表------------------

1.新建一个tableViewcontroller  修改那个tableView的继承

 

2.给他的cell添加一个Identifier     
下面打印的就是他的好友列表

 

 

#pragma mark - Tableview datasource

 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return self.buddyList.count;

}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *ID = @"BuddyCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    //获取好友列表名称  EMBuddy是环信封装的好友模型

    EMBuddy *buddy = self.buddyList[indexPath.row];

    //显示头像 和名字

    cell.imageView.image = [UIImage imageNamed:@"chatListCellHead"];

    cell.textLabel.text = buddy.username;

    

    return cell;

}

 

注意一个bug在网速很慢的时候话或者用户的手速很快的情况下(遇到单身30年的手速)用户的时候      你会发现好友列表但是没有值的  因为它的好友列表是在你用户登录策划国内恭候才会有值 

 

buddyList是从本地获取的数据  本地有个数据库你可以去里面看看  

// buddyList 

 

如果删除了应用或者饿用户第一次登陆的时候 buddyList是没有数据记录的

就要从服务区获取好友列表纪录

 

 

在网络登陆之前我们去从服务器获取那个 好友列表并把它写到本地的数据库里面去,注意一下这个方法写在哪个地方 切记切记
----------------好友请求同意后的列表刷新----------------------------

 

当接收到后有的同意后要刷新好友的列表数据   去通讯录控制器监听
产生了一个问题?

我发送了请求   对方接受了   没有刷新好友列表

环信发送的话一定调用了

#pragma mark-好友列表的请求被更新,然而并没什么卵用

-(void)didUpdateBuddyList:(NSArray *)buddyList changedBuddies:(NSArray *)changedBuddies isAdd:(BOOL)isAdd{

//    NSLog(@"好友列表被更新%@", buddyList);

    NSLog(@"%@",buddyList);

    self.buddyList = buddyList;

    [self.tableView reloadData];

    

}

加上这句话就可以解决这个问题

 

 

 

 

============删除好友==========================

 

 

获取移除好友的名字

还有一种删除了是互相删除还是只是将一方的删除

 

#pragma mark--删除好友的代理方法

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(nonnull NSIndexPath *)indexPath {

    if(editingStyle == UITableViewCellEditingStyleDelete) {

        //获取要移除的好友的名字

        EMBuddy *buddy =self.buddyList[indexPath.row];

        NSString *deleteusername  = buddy.username;

        

        //删除好友

        [[EaseMob sharedInstance].chatManager removeBuddy:deleteusername removeFromRemote:YES error:nil];

    }

}

 

 

 

 

 

———--------被好友删除的监听-----------------------------

1.在会话里面:

//被好友删除

#pragma mark-监听被好友删除

-(void)didRemovedByBuddy:(NSString *)username {

    NSString *message = [username stringByAppendingString:@"把你删除"];

    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"好友删除提醒" message:message delegate:nil cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil];

    [alert show];

}

 

在同叙录里面:

//监听被删除去会话里面

#pragma mark-被好友删除了刷新一遍列表

-(void)didRemovedByBuddy:(NSString *)username {

    [self loadDataFromServer];

}

 

--------------退出登录--------------------------

 

选中table View 的然后给他选static cell

   2.然后连线去实现它的方法

 

-重点-------------聊天界面的实现----------------------------

 

1.拖入一个UIviewController 在上面在取拖入一个navagationBar 去设置他的标题

 

2.把cell的脱线  show

 

3.拖入一个View   拖到最下面    你会发现被tabbar 给盖住了   怎么去隐藏他呢?

   选中他   有个 Bottom Bar  改为None   

 

4.给这个View设置约束的时候注意  不要给她设置底部距Bottom  选择View

layout后  选择 Hidden Bottom Bar

 

5.往上面添加button    button也要设置约束  要他举例底部的位子不变    

否者的话  他会随着聊天的界面文字的的增加   而那个上升

 

还要加上一个textfield

 

通过代码监听键盘    如果底部
千万不要把键盘关闭了   不然神仙也救不了你

 

具体代码:

 

-(void)viewDidLoad {

    [super viewDidLoad];

    //1.监听键盘的弹出,把inputToolbar往上移

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(kbWillShow:) name:UIKeyboardWillShowNotification object:nil];

    

    

    

}

 

#pragma mark-键盘显示的时候会触发方法

-(void)kbWillShow:(NSNotification *)notification {

 //获取键盘的高度

    //1.获取键盘结束的位子

    CGRect kbEndFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];

    CGFloat kbHeight = kbEndFrame.size.height;

    

    //更改inputToolBar的底部约束

    self.inputToolBarBottonConstraint.constant = kbHeight;

    //添加动画

    [UIView animateWithDuration:0.25 animations:^{

        [self.view layoutIfNeeded];

    }];

}

 

//移除通知

 

-(void)dealloc {

    [[NSNotificationCenter defaultCenter] removeObserver:self];

}

 

///////////////////

再加上一个tableView在它的上面    如何实现在拖动tableview 的时候让键盘隐藏

 

或者去监听tableView滚动的方法  

 

tableView 有一个属性 Keyboard  Dismiss on drag

在键盘推出的时候 让inputToolBarView  恢复原位

也要监听他

 

 

 

 

-----------cell有三种类型的 左边  中间   右边 -------------------------

1.往那个tableView里面去添加cell的时候我们可以 在里面加上图片

 

思路:在你设置好了头像之后再去设置文本的时候怎么设置

UILabel 设置背景图片的时候 我们可以先去给UILabel设置约束

再去设置那个背景图片,让他去拉伸

设置约束的时候注意头像要写死  但是lable只需要设置他的左边和  上面就行

 

如何加上测试数据:

1.自定一一个cell   在给他对用的类    和 对应的cell  绑定一个改类名

在。h文件里面给label加上一个属性 , 在给他的cell绑定一cell
最后别忘了在给tableview 右键往那个UIviewController上面加上数据源和代理

也就是自定义cell

 

------如何去让他显示的换行

1.吧label的Lines设置为0;

2.设置她的最大宽度:选择  Preferred width 这个选项242;

 

 

----最后给他设置那个背景图片

吧那个UIimage添加到那个Label上面 

如何给那个这个ImageView 和Label  设置左上角对其?????????????

选中他们两个,然后把选择设置约束右下角的正向第2个  然后把4个Edge选择对其

 

最后别忘了去吧label  设置为clear

 

怎么去把ImageView的背景图片拉伸???????

选择背景图片 第4个属性倒立的脚   有一个strecting属性  设置为0.5   0.5  0  0

那个时候你会发现它的那个啥的没有那个左边图片的角的属性,什么原因呢?

这是因为你的这个时候的Y值拉升的不够可以把他的Y方向上面改成 0.7

 

这个时候还缺最后一步,要把它的那个背景ImagView改动一下,让它在上下左右 都往外面 

拉伸一下??????//

可以选中它的那个约束,更改它的那个Constant    左边和上面的都是 加10     下边和右边是减10

 最后别忘了跟新约束

 

-----------发送方的cell排布----------------------

先拖入一tableViewCell 然后改他的名字    在去拖入一个Imageview  在去实现它的那个

5  5   35 35 

2.拖入一个Label   上面15 右边20   宽和高就不要添加了

 

3.如何让两个自定义的cell指向同一个的cell  新思想 :两个View公用一个cell

  连线的时候又一个选择   选择senderCell   再给SenderCell一个identifier标示符号

在渲染cell的方法中加入一个加载哪一个cell的判断

 

4.最后设置它的Lines = 0  和 那个Preferred Width的宽度  让它实现自动换行

 

5.添加一个ImageView然后再去设置它的背景图片和  那个边距的对其

 

6.更改Image的Stretching

 

7.最后去把ImageView 的各个边距都改一下 上 10   左 10    下 -10  右边  -15 最后跟新

 

8  重点----如何去根据label里面的文字的高度去自动计算那个文字的高度?????

1.实现它的给他添加了一个测试的数据源方法

9--重点----还有一个问题  怎么去更改的它的自动计算那个行高呢??????

cell的高度取决于label文字的高度和它的字体的大小决定的、

思想: 去获取那个cell里面的label的高度再去加上一个固定的高度就是cell的高度了

怎么去获取那个label的高度呢???

上面的额头像距上为5 加上那个上面label距离上面的10的高度 再加上label自己      的高度self.label.hight +下面的那个10,再去加上那个固定的高度就是cell的高度了

 

 

10.--重点----我们专门搞一个计算高度的属性(他是一个返回cell的方法,然后去返回cell高度的方法里面去给他完成一下赋值的操作,最后去实现)

  //还少了一步 ,一定要加上去设置那个label的数据

    self.chatCellTool.messageLabel.text = self.dataSources[indexPath.row];

    return [self.chatCellTool cellHeight];

 

 

/** 计算高度的cell的属性*/

 @property (nonatomic,strong)UXZYChatCell *chatCellTool;

 

   //给计算cell高度的对象完成一个赋值

    //他返回的是一个cell 这个cell只是在那个返回高度的方法里面去用到了,其他的地方没有用到

记得最好把它的方法static NSString *Indentifier = @"ReceiveCell";写在那个cell的.h文件中

tableview记得再拖一次线  为什么任何一个的Identifier:都可以呢?????

因为你在返回高度的方法里面都是一样的执行的,不获去细分你是哪一个cell的方法 so。。。

    self.chatCellTool = [self.tableView dequeueReusableCellWithIdentifier:SenderCell];

 

 

--------------发送聊天消息---------------------

1.首先要做的是把那个 textView的发送框改成send属性 第四个选项里面的有一个

  Return Key 选项 改成那个Send选项

 

2.怎么去发送按钮的事件呢?????

1.把那个textView 的代理的线连上   2.然后去那个tableView里面的那个去遵守textView代理

 

在textView的方法里面去监听他最后的字符有没有换行,如果有换行的字符的话我就代表说他是发送sender的按钮]

 

3.怎么去发送文字呢???????

#pragma mark-UITextView的代理

-(void)textViewDidChange:(UITextView *)textView {

    if([textView.text hasSuffix:@"\n"] ) {

        NSLog(@"这是一个发送事件");

        //发送文字

        [self sendMessage:textView.text];

        

        //清空文字

        textView.text = nil;

    

    }

}

 

-(void)sendMessage:(NSString *)text {

    //创建一个消息对象实例

    EMMessage *msgObj = [[EMMessage alloc]initWithReceiver:nil bodies:nil];

    //发送消息

    [[EaseMob sharedInstance].chatManager asyncSendMessage:msgObj progress:nil prepare:^(EMMessage *message, EMError *error) {

        NSLog(@"消息准备发送");

    } onQueue:nil completion:^(EMMessage *message, EMError *error) {

        NSLog(@"消息完成发送");

    } onQueue:nil];

    

}

还缺少一个参数  就是把消息发送给谁? 我们就缺少一个参数传递

initWithReceiver:要去拿到那个参数好友列表的参数 EMBuddy 

#warning 每一种消息类型对象不同的消息体

    //EMTextMessageBody

    //EMVoiceMessageBody

    //EMVideoMessageBody

   // EMLocationMessageBody

   // EMImageMessageBody

    

    //创建一个聊天的文本对象

    EMChatText *chatText = [[EMChatText alloc]initWithText:text];

    //创建一个文本消息体

    EMTextMessageBody *textBody = [[EMTextMessageBody alloc]initWithChatObject:chatText];

    

    //创建一个消息对象实例   bodies是一个数组

    EMMessage *msgObj = [[EMMessage alloc]initWithReceiver:self.buddy.username bodies:@[textBody]];

    //发送消息

    

    [[EaseMob sharedInstance].chatManager asyncSendMessage:msgObj progress:nil prepare:^(EMMessage *message, EMError *error) {

        NSLog(@"消息准备发送");

    } onQueue:nil completion:^(EMMessage *message, EMError *error) {

        NSLog(@"消息完成发送");

    } onQueue:nil];

 

注意点  : 加上一个return;去测试

把选中的好友列表正向传递进去

最后别忘了把那个return打开;

    

 

--------------显示好友的名字---------------------

1.在那个聊天的控制器的viewdidload里面写上

self.titlte = self.buddy.username

 

——————-------加载本地的聊天数据--------------------

有封装好的东西,先去内存的会话列表中去获取会话  如果没有找到就去数据库中去获取会话

没有找到就会出发现的会话

 

#pragma mark-加载本地的聊天数据 

-(void)loadLocalChatrecords {

    //获取本地聊天记录 会话对象

   EMConversation *conversation = [[EaseMob sharedInstance].chatManager conversationForChatter:self.buddy.username conversationType: eConversationTypeChat];

    //加载当前来哦天用户所有的聊天记录

    NSArray *messages = [conversation loadAllMessages];

    

    for(id obj in messages) {

        NSLog(@"%@",[obj class]);

    }

    

    [self.dataSources addObject:messages];

    

}

 

  [self.dataSources addObject:messages];加上了就报错了,她的原因是什么呢?

  tableView:heightForRowAtIndexPath 错了

 

跳进设置高度的方法里面去 去吧里面改动一下

    //改进后的cell高度的获取

    //1.获取消息的模型 这样代码风格不好我们可以去cell的属性里面去创建一个cell的模型

//    EMMessage *msg = self.dataSources[indexPath.row];

//    id body = msg.messageBodies[0];

//    if([body isKindOfClass:[EMTextMessageBody class]]) {//如果是文本消息

//        EMTextMessageBody *textBody = body;

//        cell.messageLabel.text = textBody;

//    }

 

最后是用一个set方法去代替他们

 

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    //1.获取消息的模型 这样代码风格不好我们可以去cell的属性里面去创建一个cell的模型

    EMMessage *msg = self.dataSources[indexPath.row];

    //改进后的cell高度的获取

//    id body = msg.messageBodies[0];

//    

//    if([body isKindOfClass:[EMTextMessageBody class]]) {//如果是文本消息

//        EMTextMessageBody *textBody = body;

//        cell.messageLabel.text = textBody;

//    }

    self.chatCellTool.message = msg;

    return [self.chatCellTool cellHeight];

    

    //还少了一步 ,一定要加上去设置那个label的数据

//    self.chatCellTool.messageLabel.text = self.dataSources[indexPath.row];

//    return [self.chatCellTool cellHeight];

}

最后别忘了去那个tableviewcell的模型里面去改,

 

————为了计算高度我们建立了一个模型——----------

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

     //改进后的cell高度的获取

    //1.获取消息的模型 这样代码风格不好我们可以去cell的属性里面去创建一个cell的模型

    EMMessage *msg = self.dataSources[indexPath.row];

    

    self.chatCellTool.message = msg;

    

    return [self.chatCellTool cellHeight];

}

重写了模型的set方法 ,然后去调用了他的set方法

 

最后别忘了在显示的时候去调用他渲染那个方法

我的这个msg是一个消息模型

msg.messageBodies[0]

这样才能拿到消息体

msg.messageBodies[0].text才正确

 

-------------

[Pasted Graphic.tiff]

----------这样还不对-------------------------

 

你会看到你发出去的消息会在左边能看到

如何让它只能在右边显示呢??????????/

EMmessage有两个属性 from   to

from是发送方也就是自己    from是好友的话自己就是接受方

所以我们得在现实渲染的方法里面去先去获取消息模型

然后再去做一个from的判断

 

    UXZYChatCell *cell = nil;

    //先去获取消息模型然后去在去判断是发送方还是接收方

    EMMessage *msg = self.dataSources[indexPath.row];

    if([msg.from isEqualToString:self.buddy.username]) {//自己接收方

       cell = [tableView dequeueReusableCellWithIdentifier:Indentifier];

    }else {

       cell = [tableView dequeueReusableCellWithIdentifier:SenderCell];

    }

 

--------怎么让你的消息立马显示-----------------------

去这个方法里面 

-(void)sendMessage:(NSString *)text { }

 

msgObj是你自己创建一个消息对象实例   bodies是一个数组

 EMMessage *msgObj = [[EMMessage alloc]initWithReceiver:self.buddy.username bodies:@[textBody]];

    //把消息添加到数据源 再刷新表格

    [self.dataSources addObject:msgObj];

    [self.tableView reloadData];

 

------怎么让你的消息自己滚动到最上面的一行----

   

    //4.把消息显示在顶部

    [self scrollToBottom];

}

 

-(void)scrollToBottom {

    //获取最后一行

    if(self.dataSources.count == 0){

        return;

    }

    NSIndexPath *lastIndex = [NSIndexPath indexPathForRow:self.dataSources.count-1 inSection:0];

    

    

    [self.tableView scrollToRowAtIndexPath:lastIndex atScrollPosition:UITableViewScrollPositionBottom animated:YES];

}

 

—————仔细的你到这一步了发没发现你那个你发出去的消息子啊框里面都会多出一行---

原因:是你在点击发送的时候他换了一下行,换行字符只展占用一个字节

如何去清除那个换行的字符,在发消息的放里面去实现

        text = [text substringToIndex:text.length-1];

 

 

-----------怎么去监听消息的回复--------------------

1.设置代理方法  并遵循它的 代理方法

2.有一个那个mesage的方法去实现一下

 

 

 

 

------对输入框的完善,即在你输入的时候那个输入框的高速会自动增加-------------------------

1.得定义输入框的一个最小的高度和最大的高度

2.textView是继承于UIscrollView   scrollView有一个属性 contensize 属性

    这个是计算那个做一个判断 不同情况下面的高度

 

3.我们再去拿到那个的InputView 的高度的约束  再去连线使它成为一个属性  然后像之前一样去约束它,找到他,然后给他连线 使它成为一个属性

 

    //获取contentsize的高度

    CGFloat contentHeight = textView.contentSize.height;

    if (contentHeight <minHeight) {

        textViewH = minHeight;

    }else if (contentHeight >maxHeight) {

        textViewH = maxHeight;

    }else {

        textViewH = contentHeight;

    }

    

    self.inputToolBarHeightConstrains.constant = 5 + 8 + textViewH;

 

4.还是有一个问题,就是在你输入完了一之后发送了   之后textView还是有一个换行的空格

所以还得有一个在发送完了后的判断语句

if([textView.text hasSuffix:@"\n"] ) {

        NSLog(@"这是一个发送事件");

        //发送文字

        [self sendMessage:textView.text];

        

        //清空文字

        textView.text = nil;

        

//        发送时textView的高速为最小的高度

        textViewH = minHeight;

    

    }

    self.inputToolBarHeightConstrains.constant = 5 + 8 + textViewH;

 

5.设置textView的背景图片  在SB中去设置 拖入一个IMageView 然后把它拿到那个textView的上面去   然后改透明  设置背景图片    把图片拉伸  streching  别忘了给背景图片加约束 不然的话他会随着那个的高度的增加他不会随着拉伸   最后去加个动画

 

6.——————---发送完了后发现光标不见了 发大模拟器看在左上角???

原因???scrollView有一个contentOffset.y的值会随着你的那个的光标的contensize的而向上拖动而拖送

NSStringFromCGSize(textView.contentSet)可以打印出来看看

contentOffset一开始为(0,0)之后它的y值为正数了,为什么呢,因为他要显示的下面的文字内容的话它的那个轴必须下移动 所以为正 

如何解决  哪次发送完了 让它的contentset恢复到原位

 

 

环信遇到的bug1:真机上面不能跑  模拟器可以

[Pasted Graphic_1.tiff]

 

把那个bitcode 设置为NO  bitcode是被编译程序的一种中间形式的代码。包含bitcode配置的程序将会在App store上被编译和链接

默认是yes   

 

 

storyboard作为控制器的复习

 

1.拖入一导航控制器 ,更改尺寸    去掉后一个

2.拖入一个viewControler  然后去把它的那个root viewcontroller  设置一下

 

3.创建一个控制器UIviewcontroller     第三个选项 class里面更改继承关系   

 

 

4.拖线 连线        1.去改掉main        2。去那个第4个 is initial  View Controller 的钩上

 

 

登录提供了三种方法

 

 

1.同步     2.block的异步      3.代理的回调

 

注释的方法提示在图表

方式一:/// 点在图标

方式二: 

 /*!

 *   @brief 点在图标

 */ 查看全部
环信的教程:

没有初始化SDK  

去AppDelegate里面初始化

 

密码

 

User not exist         ??????????

每一个应用都有自己的注册用户  去你的后台管理   去看你的注册的用户数   

为什么demo的可以跑起来????????

是在它的应用下注册的

 

怎么去注册用户  -注册用户

用户名字可以相同   不同的应用   

 

 

那个打印的loginInfo 是这个字典的也就是用户的登录信息

 

你会发现打印的loginInfo上面还有一坨恶心的东西,那个是环信SDK自己打印的日志信息

 

SEND   和      RECV    使用的是XMPP协议    所以 数据的格式是XML   一般的HTTP协议的话他就是JSON格式的

这个是app把客户端登录的信息发给环信服务器后打印出来的日志      是不是很烦

 

如何去在哪儿隐藏它的控制台的日志信息 ?????????

去初始化的时候把它隐藏  有一个otherConfig的东西   右键-jump to Define

进去瞅瞅--

复制它的key 给他设置为NO

这个时候它的控制台的日志信息就被屏蔽了

 

 

跟环信交互的所有类都有这个

[EaseMob sharedInstance].chatManager

 

 

注册的时候代码:


如果你把这onQueue改为nil的话他默认也是在主线程的

 

然后你在去环信的开发中心刷新IM用户 你会发现他多了一个

发送给的数据给服务器的时候还是XML格式,里面的SDK帮你封装了,不用你自己去接触

 

 

---自动登录------------------------------------

 

看到它的主界面只有三个tabbar

 进去 mainstoryboard里面 删除原始的viewcontroller  拖入一个 tabbarController     去掉原始的tabbar 的两个子控制器   记得给它的isinitial 那个选项钩上   然后拖入三个navigationcontroller(这个根据你的界面而定)

 

选中给每个的Item  的title属性可以更改

然后在登录成功中写上加载storyboard的方法

你会发现你已经跳转进去
如何实现自动登录?????????????????

  实现原理:把你的登录信息保存在沙盒中     程序启动时候发送登录请求

  只要你在第一次登录成功后发送环信自带登录的网络请求去实现、

环信自己帮你实现上面的东西

 

具体实现

在登录成功的下面写上

[[EaseMob sharedInstance].chatManager  setIsAutoLoginEnabled:YES]

然后去在AppDelegte里面把他的沙盒路径拿到
然后再控制台你可以看到这些信息,其中的账号密码信息你会发现他被加密了,有没有?
如何监听是否是已经处于登录状态了这个地方有个代理  环信的代理方法

在AppDelegate方法里面进去 在启动方法里面写
你会发现它的那个啥没有完成界面的跳转    但是控制台却是带那个登陆成功了
这个时候我们还缺一步骤  之前我们在自动登录时候我们调用的是set方法

这个时候我们要实现它的 get方法     写在监听登录状态的下面

  //如果登录过直接来到主界面
    if([[EaseMob sharedInstance].chatManager isAutoLoginEnabled]){

        self.window.rootViewController = [UIStoryboard storyboardWithName:@"Main" bundle:nil].instantiateInitialViewController;

    }

    
=------------自动连接--------------------------

 

网络通不通的时候类似微信那种网络不通的实现

去那个main.storyboard里面把那会话的导航控制器跳转的那个类继承改为你自己创建的那个UItableViewController

 

1.在会话里面监听的网络的状态  环信的有很多个代理

去那个.m文件里面去实现
点击那个EMChatManagerDelegate 里面去实现 EMChatManagerUtilDelegate里面的这个方法就OK了

- (void)didConnectionStateChanged:(EMConnectionState)connectionState;
在真机上面测试的时候 网络连接成功不代表客户端和服务器端连接成功

 

 

还有自动连接的状态的监听 也是加上他的代理方法就行了


--------添加好友请求-----------------------------

1.是用环信的思想

 所有的网络请求   [EaseMob sharedInstance].chatManager 由这个管理器发起的

 

2.所有结果(自动登录 自动连接)通过代理来回调完成

[EaseMob sharedInstance].chatManager的addDelegate来完成

 

3.EMChatManagerBuddyDelegate 这个代理实现了对用户的基本操作

1.添加好友      2.从本地获取好友      3.从服务器列表获取最新的好友     4.接受好友添加请求

5.删除好友       6.被好友从名单上面删除  

 

 

在navigation  的第二个控制器上面加上一个UIbarbarItem   选择自定义   然后+    

再去创建一个UIviewController     然后再去实现用个+号去拖一个线  

 

 可以在上面加上navigationItem 上改为添加好友

再去新建一个控制器AdressBooking 通讯录  这个类是继承于UIviewController
是用环信最简单的方法 ,把官方的Demo直接拿过来用   直接跟改它的Appdelegate里面的APPKey

这样你就收到了申请    注意   这是最简单的方式

 

 

还有一点 你要在每个控制器里面写上你环信的代理方法

这样就能保证你下面写的环信 的每一个方法会被自动调用了
代理方法:

代理的销毁

 

 

好友请求消息反馈写在什么地方   因为你进去那个会话的控制器里面了的话就会被销毁了。我们可以把它的好友请求写在会话控制器   这样他每个控制器都可以收到了  也没有必要写在AppDelegate里面 可以去尝试一下

 

 

 

 

 

 

 

 

 

 

---------现实好友界面列表------------------

1.新建一个tableViewcontroller  修改那个tableView的继承

 

2.给他的cell添加一个Identifier     
下面打印的就是他的好友列表

 

 

#pragma mark - Tableview datasource

 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return self.buddyList.count;

}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *ID = @"BuddyCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];

    //获取好友列表名称  EMBuddy是环信封装的好友模型

    EMBuddy *buddy = self.buddyList[indexPath.row];

    //显示头像 和名字

    cell.imageView.image = [UIImage imageNamed:@"chatListCellHead"];

    cell.textLabel.text = buddy.username;

    

    return cell;

}

 

注意一个bug在网速很慢的时候话或者用户的手速很快的情况下(遇到单身30年的手速)用户的时候      你会发现好友列表但是没有值的  因为它的好友列表是在你用户登录策划国内恭候才会有值 

 

buddyList是从本地获取的数据  本地有个数据库你可以去里面看看  

// buddyList 

 

如果删除了应用或者饿用户第一次登陆的时候 buddyList是没有数据记录的

就要从服务区获取好友列表纪录

 

 

在网络登陆之前我们去从服务器获取那个 好友列表并把它写到本地的数据库里面去,注意一下这个方法写在哪个地方 切记切记
----------------好友请求同意后的列表刷新----------------------------

 

当接收到后有的同意后要刷新好友的列表数据   去通讯录控制器监听
产生了一个问题?

我发送了请求   对方接受了   没有刷新好友列表

环信发送的话一定调用了

#pragma mark-好友列表的请求被更新,然而并没什么卵用

-(void)didUpdateBuddyList:(NSArray *)buddyList changedBuddies:(NSArray *)changedBuddies isAdd:(BOOL)isAdd{

//    NSLog(@"好友列表被更新%@", buddyList);

    NSLog(@"%@",buddyList);

    self.buddyList = buddyList;

    [self.tableView reloadData];

    

}

加上这句话就可以解决这个问题

 

 

 

 

============删除好友==========================

 

 

获取移除好友的名字

还有一种删除了是互相删除还是只是将一方的删除

 

#pragma mark--删除好友的代理方法

-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(nonnull NSIndexPath *)indexPath {

    if(editingStyle == UITableViewCellEditingStyleDelete) {

        //获取要移除的好友的名字

        EMBuddy *buddy =self.buddyList[indexPath.row];

        NSString *deleteusername  = buddy.username;

        

        //删除好友

        [[EaseMob sharedInstance].chatManager removeBuddy:deleteusername removeFromRemote:YES error:nil];

    }

}

 

 

 

 

 

———--------被好友删除的监听-----------------------------

1.在会话里面:

//被好友删除

#pragma mark-监听被好友删除

-(void)didRemovedByBuddy:(NSString *)username {

    NSString *message = [username stringByAppendingString:@"把你删除"];

    UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"好友删除提醒" message:message delegate:nil cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil];

    [alert show];

}

 

在同叙录里面:

//监听被删除去会话里面

#pragma mark-被好友删除了刷新一遍列表

-(void)didRemovedByBuddy:(NSString *)username {

    [self loadDataFromServer];

}

 

--------------退出登录--------------------------

 

选中table View 的然后给他选static cell

   2.然后连线去实现它的方法

 

-重点-------------聊天界面的实现----------------------------

 

1.拖入一个UIviewController 在上面在取拖入一个navagationBar 去设置他的标题

 

2.把cell的脱线  show

 

3.拖入一个View   拖到最下面    你会发现被tabbar 给盖住了   怎么去隐藏他呢?

   选中他   有个 Bottom Bar  改为None   

 

4.给这个View设置约束的时候注意  不要给她设置底部距Bottom  选择View

layout后  选择 Hidden Bottom Bar

 

5.往上面添加button    button也要设置约束  要他举例底部的位子不变    

否者的话  他会随着聊天的界面文字的的增加   而那个上升

 

还要加上一个textfield

 

通过代码监听键盘    如果底部
千万不要把键盘关闭了   不然神仙也救不了你

 

具体代码:

 

-(void)viewDidLoad {

    [super viewDidLoad];

    //1.监听键盘的弹出,把inputToolbar往上移

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(kbWillShow:) name:UIKeyboardWillShowNotification object:nil];

    

    

    

}

 

#pragma mark-键盘显示的时候会触发方法

-(void)kbWillShow:(NSNotification *)notification {

 //获取键盘的高度

    //1.获取键盘结束的位子

    CGRect kbEndFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];

    CGFloat kbHeight = kbEndFrame.size.height;

    

    //更改inputToolBar的底部约束

    self.inputToolBarBottonConstraint.constant = kbHeight;

    //添加动画

    [UIView animateWithDuration:0.25 animations:^{

        [self.view layoutIfNeeded];

    }];

}

 

//移除通知

 

-(void)dealloc {

    [[NSNotificationCenter defaultCenter] removeObserver:self];

}

 

///////////////////

再加上一个tableView在它的上面    如何实现在拖动tableview 的时候让键盘隐藏

 

或者去监听tableView滚动的方法  

 

tableView 有一个属性 Keyboard  Dismiss on drag

在键盘推出的时候 让inputToolBarView  恢复原位

也要监听他

 

 

 

 

-----------cell有三种类型的 左边  中间   右边 -------------------------

1.往那个tableView里面去添加cell的时候我们可以 在里面加上图片

 

思路:在你设置好了头像之后再去设置文本的时候怎么设置

UILabel 设置背景图片的时候 我们可以先去给UILabel设置约束

再去设置那个背景图片,让他去拉伸

设置约束的时候注意头像要写死  但是lable只需要设置他的左边和  上面就行

 

如何加上测试数据:

1.自定一一个cell   在给他对用的类    和 对应的cell  绑定一个改类名

在。h文件里面给label加上一个属性 , 在给他的cell绑定一cell
最后别忘了在给tableview 右键往那个UIviewController上面加上数据源和代理

也就是自定义cell

 

------如何去让他显示的换行

1.吧label的Lines设置为0;

2.设置她的最大宽度:选择  Preferred width 这个选项242;

 

 

----最后给他设置那个背景图片

吧那个UIimage添加到那个Label上面 

如何给那个这个ImageView 和Label  设置左上角对其?????????????

选中他们两个,然后把选择设置约束右下角的正向第2个  然后把4个Edge选择对其

 

最后别忘了去吧label  设置为clear

 

怎么去把ImageView的背景图片拉伸???????

选择背景图片 第4个属性倒立的脚   有一个strecting属性  设置为0.5   0.5  0  0

那个时候你会发现它的那个啥的没有那个左边图片的角的属性,什么原因呢?

这是因为你的这个时候的Y值拉升的不够可以把他的Y方向上面改成 0.7

 

这个时候还缺最后一步,要把它的那个背景ImagView改动一下,让它在上下左右 都往外面 

拉伸一下??????//

可以选中它的那个约束,更改它的那个Constant    左边和上面的都是 加10     下边和右边是减10

 最后别忘了跟新约束

 

-----------发送方的cell排布----------------------

先拖入一tableViewCell 然后改他的名字    在去拖入一个Imageview  在去实现它的那个

5  5   35 35 

2.拖入一个Label   上面15 右边20   宽和高就不要添加了

 

3.如何让两个自定义的cell指向同一个的cell  新思想 :两个View公用一个cell

  连线的时候又一个选择   选择senderCell   再给SenderCell一个identifier标示符号

在渲染cell的方法中加入一个加载哪一个cell的判断

 

4.最后设置它的Lines = 0  和 那个Preferred Width的宽度  让它实现自动换行

 

5.添加一个ImageView然后再去设置它的背景图片和  那个边距的对其

 

6.更改Image的Stretching

 

7.最后去把ImageView 的各个边距都改一下 上 10   左 10    下 -10  右边  -15 最后跟新

 

8  重点----如何去根据label里面的文字的高度去自动计算那个文字的高度?????

1.实现它的给他添加了一个测试的数据源方法

9--重点----还有一个问题  怎么去更改的它的自动计算那个行高呢??????

cell的高度取决于label文字的高度和它的字体的大小决定的、

思想: 去获取那个cell里面的label的高度再去加上一个固定的高度就是cell的高度了

怎么去获取那个label的高度呢???

上面的额头像距上为5 加上那个上面label距离上面的10的高度 再加上label自己      的高度self.label.hight +下面的那个10,再去加上那个固定的高度就是cell的高度了

 

 

10.--重点----我们专门搞一个计算高度的属性(他是一个返回cell的方法,然后去返回cell高度的方法里面去给他完成一下赋值的操作,最后去实现)

  //还少了一步 ,一定要加上去设置那个label的数据

    self.chatCellTool.messageLabel.text = self.dataSources[indexPath.row];

    return [self.chatCellTool cellHeight];

 

 

/** 计算高度的cell的属性*/

 @property (nonatomic,strong)UXZYChatCell *chatCellTool;

 

   //给计算cell高度的对象完成一个赋值

    //他返回的是一个cell 这个cell只是在那个返回高度的方法里面去用到了,其他的地方没有用到

记得最好把它的方法static NSString *Indentifier = @"ReceiveCell";写在那个cell的.h文件中

tableview记得再拖一次线  为什么任何一个的Identifier:都可以呢?????

因为你在返回高度的方法里面都是一样的执行的,不获去细分你是哪一个cell的方法 so。。。

    self.chatCellTool = [self.tableView dequeueReusableCellWithIdentifier:SenderCell];

 

 

--------------发送聊天消息---------------------

1.首先要做的是把那个 textView的发送框改成send属性 第四个选项里面的有一个

  Return Key 选项 改成那个Send选项

 

2.怎么去发送按钮的事件呢?????

1.把那个textView 的代理的线连上   2.然后去那个tableView里面的那个去遵守textView代理

 

在textView的方法里面去监听他最后的字符有没有换行,如果有换行的字符的话我就代表说他是发送sender的按钮]

 

3.怎么去发送文字呢???????

#pragma mark-UITextView的代理

-(void)textViewDidChange:(UITextView *)textView {

    if([textView.text hasSuffix:@"\n"] ) {

        NSLog(@"这是一个发送事件");

        //发送文字

        [self sendMessage:textView.text];

        

        //清空文字

        textView.text = nil;

    

    }

}

 

-(void)sendMessage:(NSString *)text {

    //创建一个消息对象实例

    EMMessage *msgObj = [[EMMessage alloc]initWithReceiver:nil bodies:nil];

    //发送消息

    [[EaseMob sharedInstance].chatManager asyncSendMessage:msgObj progress:nil prepare:^(EMMessage *message, EMError *error) {

        NSLog(@"消息准备发送");

    } onQueue:nil completion:^(EMMessage *message, EMError *error) {

        NSLog(@"消息完成发送");

    } onQueue:nil];

    

}

还缺少一个参数  就是把消息发送给谁? 我们就缺少一个参数传递

initWithReceiver:要去拿到那个参数好友列表的参数 EMBuddy 

#warning 每一种消息类型对象不同的消息体

    //EMTextMessageBody

    //EMVoiceMessageBody

    //EMVideoMessageBody

   // EMLocationMessageBody

   // EMImageMessageBody

    

    //创建一个聊天的文本对象

    EMChatText *chatText = [[EMChatText alloc]initWithText:text];

    //创建一个文本消息体

    EMTextMessageBody *textBody = [[EMTextMessageBody alloc]initWithChatObject:chatText];

    

    //创建一个消息对象实例   bodies是一个数组

    EMMessage *msgObj = [[EMMessage alloc]initWithReceiver:self.buddy.username bodies:@[textBody]];

    //发送消息

    

    [[EaseMob sharedInstance].chatManager asyncSendMessage:msgObj progress:nil prepare:^(EMMessage *message, EMError *error) {

        NSLog(@"消息准备发送");

    } onQueue:nil completion:^(EMMessage *message, EMError *error) {

        NSLog(@"消息完成发送");

    } onQueue:nil];

 

注意点  : 加上一个return;去测试

把选中的好友列表正向传递进去

最后别忘了把那个return打开;

    

 

--------------显示好友的名字---------------------

1.在那个聊天的控制器的viewdidload里面写上

self.titlte = self.buddy.username

 

——————-------加载本地的聊天数据--------------------

有封装好的东西,先去内存的会话列表中去获取会话  如果没有找到就去数据库中去获取会话

没有找到就会出发现的会话

 

#pragma mark-加载本地的聊天数据 

-(void)loadLocalChatrecords {

    //获取本地聊天记录 会话对象

   EMConversation *conversation = [[EaseMob sharedInstance].chatManager conversationForChatter:self.buddy.username conversationType: eConversationTypeChat];

    //加载当前来哦天用户所有的聊天记录

    NSArray *messages = [conversation loadAllMessages];

    

    for(id obj in messages) {

        NSLog(@"%@",[obj class]);

    }

    

    [self.dataSources addObject:messages];

    

}

 

  [self.dataSources addObject:messages];加上了就报错了,她的原因是什么呢?

  tableView:heightForRowAtIndexPath 错了

 

跳进设置高度的方法里面去 去吧里面改动一下

    //改进后的cell高度的获取

    //1.获取消息的模型 这样代码风格不好我们可以去cell的属性里面去创建一个cell的模型

//    EMMessage *msg = self.dataSources[indexPath.row];

//    id body = msg.messageBodies[0];

//    if([body isKindOfClass:[EMTextMessageBody class]]) {//如果是文本消息

//        EMTextMessageBody *textBody = body;

//        cell.messageLabel.text = textBody;

//    }

 

最后是用一个set方法去代替他们

 

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    //1.获取消息的模型 这样代码风格不好我们可以去cell的属性里面去创建一个cell的模型

    EMMessage *msg = self.dataSources[indexPath.row];

    //改进后的cell高度的获取

//    id body = msg.messageBodies[0];

//    

//    if([body isKindOfClass:[EMTextMessageBody class]]) {//如果是文本消息

//        EMTextMessageBody *textBody = body;

//        cell.messageLabel.text = textBody;

//    }

    self.chatCellTool.message = msg;

    return [self.chatCellTool cellHeight];

    

    //还少了一步 ,一定要加上去设置那个label的数据

//    self.chatCellTool.messageLabel.text = self.dataSources[indexPath.row];

//    return [self.chatCellTool cellHeight];

}

最后别忘了去那个tableviewcell的模型里面去改,

 

————为了计算高度我们建立了一个模型——----------

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

     //改进后的cell高度的获取

    //1.获取消息的模型 这样代码风格不好我们可以去cell的属性里面去创建一个cell的模型

    EMMessage *msg = self.dataSources[indexPath.row];

    

    self.chatCellTool.message = msg;

    

    return [self.chatCellTool cellHeight];

}

重写了模型的set方法 ,然后去调用了他的set方法

 

最后别忘了在显示的时候去调用他渲染那个方法

我的这个msg是一个消息模型

msg.messageBodies[0]

这样才能拿到消息体

msg.messageBodies[0].text才正确

 

-------------

[Pasted Graphic.tiff]

----------这样还不对-------------------------

 

你会看到你发出去的消息会在左边能看到

如何让它只能在右边显示呢??????????/

EMmessage有两个属性 from   to

from是发送方也就是自己    from是好友的话自己就是接受方

所以我们得在现实渲染的方法里面去先去获取消息模型

然后再去做一个from的判断

 

    UXZYChatCell *cell = nil;

    //先去获取消息模型然后去在去判断是发送方还是接收方

    EMMessage *msg = self.dataSources[indexPath.row];

    if([msg.from isEqualToString:self.buddy.username]) {//自己接收方

       cell = [tableView dequeueReusableCellWithIdentifier:Indentifier];

    }else {

       cell = [tableView dequeueReusableCellWithIdentifier:SenderCell];

    }

 

--------怎么让你的消息立马显示-----------------------

去这个方法里面 

-(void)sendMessage:(NSString *)text { }

 

msgObj是你自己创建一个消息对象实例   bodies是一个数组

 EMMessage *msgObj = [[EMMessage alloc]initWithReceiver:self.buddy.username bodies:@[textBody]];

    //把消息添加到数据源 再刷新表格

    [self.dataSources addObject:msgObj];

    [self.tableView reloadData];

 

------怎么让你的消息自己滚动到最上面的一行----

   

    //4.把消息显示在顶部

    [self scrollToBottom];

}

 

-(void)scrollToBottom {

    //获取最后一行

    if(self.dataSources.count == 0){

        return;

    }

    NSIndexPath *lastIndex = [NSIndexPath indexPathForRow:self.dataSources.count-1 inSection:0];

    

    

    [self.tableView scrollToRowAtIndexPath:lastIndex atScrollPosition:UITableViewScrollPositionBottom animated:YES];

}

 

—————仔细的你到这一步了发没发现你那个你发出去的消息子啊框里面都会多出一行---

原因:是你在点击发送的时候他换了一下行,换行字符只展占用一个字节

如何去清除那个换行的字符,在发消息的放里面去实现

        text = [text substringToIndex:text.length-1];

 

 

-----------怎么去监听消息的回复--------------------

1.设置代理方法  并遵循它的 代理方法

2.有一个那个mesage的方法去实现一下

 

 

 

 

------对输入框的完善,即在你输入的时候那个输入框的高速会自动增加-------------------------

1.得定义输入框的一个最小的高度和最大的高度

2.textView是继承于UIscrollView   scrollView有一个属性 contensize 属性

    这个是计算那个做一个判断 不同情况下面的高度

 

3.我们再去拿到那个的InputView 的高度的约束  再去连线使它成为一个属性  然后像之前一样去约束它,找到他,然后给他连线 使它成为一个属性

 

    //获取contentsize的高度

    CGFloat contentHeight = textView.contentSize.height;

    if (contentHeight <minHeight) {

        textViewH = minHeight;

    }else if (contentHeight >maxHeight) {

        textViewH = maxHeight;

    }else {

        textViewH = contentHeight;

    }

    

    self.inputToolBarHeightConstrains.constant = 5 + 8 + textViewH;

 

4.还是有一个问题,就是在你输入完了一之后发送了   之后textView还是有一个换行的空格

所以还得有一个在发送完了后的判断语句

if([textView.text hasSuffix:@"\n"] ) {

        NSLog(@"这是一个发送事件");

        //发送文字

        [self sendMessage:textView.text];

        

        //清空文字

        textView.text = nil;

        

//        发送时textView的高速为最小的高度

        textViewH = minHeight;

    

    }

    self.inputToolBarHeightConstrains.constant = 5 + 8 + textViewH;

 

5.设置textView的背景图片  在SB中去设置 拖入一个IMageView 然后把它拿到那个textView的上面去   然后改透明  设置背景图片    把图片拉伸  streching  别忘了给背景图片加约束 不然的话他会随着那个的高度的增加他不会随着拉伸   最后去加个动画

 

6.——————---发送完了后发现光标不见了 发大模拟器看在左上角???

原因???scrollView有一个contentOffset.y的值会随着你的那个的光标的contensize的而向上拖动而拖送

NSStringFromCGSize(textView.contentSet)可以打印出来看看

contentOffset一开始为(0,0)之后它的y值为正数了,为什么呢,因为他要显示的下面的文字内容的话它的那个轴必须下移动 所以为正 

如何解决  哪次发送完了 让它的contentset恢复到原位

 

 

环信遇到的bug1:真机上面不能跑  模拟器可以

[Pasted Graphic_1.tiff]

 

把那个bitcode 设置为NO  bitcode是被编译程序的一种中间形式的代码。包含bitcode配置的程序将会在App store上被编译和链接

默认是yes   

 

 

storyboard作为控制器的复习

 

1.拖入一导航控制器 ,更改尺寸    去掉后一个

2.拖入一个viewControler  然后去把它的那个root viewcontroller  设置一下

 

3.创建一个控制器UIviewcontroller     第三个选项 class里面更改继承关系   

 

 

4.拖线 连线        1.去改掉main        2。去那个第4个 is initial  View Controller 的钩上

 

 

登录提供了三种方法

 

 

1.同步     2.block的异步      3.代理的回调

 

注释的方法提示在图表

方式一:/// 点在图标

方式二: 

 /*!

 *   @brief 点在图标

 */