即时通怎么把自己烟台李政调到哪里去了群组里去

服务支持-网易即时通
网易即时通与普通聊天工具有什么区别?
(1)助管理:与普通的聊天工具相比,网易即时通分为管理端和客户端2大模块。管理端提供强大的组织架构通讯录管理、安全管理、工作群管理、登录IP管理等功能。让您的人员管理工作更加高效、放心。
(2)更安全:客户端通信采用先进的网络安全与加密技术,能有效防止黑客入侵。通信过程使用 RSA 和 RC4 加密传输内容,以保证信息通讯的安全。同时员工只能在公司允许的IP范围内与本公司人员进行通讯,有效防止泄露公司机密。
(3)适合企业:普通聊天以交友、娱乐为核心,而网易即时通以高效为设计核心,因此在功能选择、产品设计上均以提升办公效率为目标,具有操作化繁为简,视觉效果整洁舒适高端,辅助办公功能丰富等特点。
网易即时通与网易POPO有什么关系?
网易即时通基于POPO开发,继承了长达10年的即时通讯运营经验。但是在设计上,即时通坚持不“继承”POPO(POPO是网易旗下的大众免费即时通讯产品,与QQ属同类)。即时通的设计是深入研究了企业用户的使用环境及使用特征,专为企业用户进行设计。因此,即时通基于POPO开发,但与POPO截然不同。
网易即时通与网易企业邮有什么关系?
(1)网易即时通与网易企业邮深入合作,凡同时购买两个产品的企业,只要在企业邮管理后台进行组织架构管理,数据即同时同步即时通组织架构上。
(2)同时购买即时通和企业邮,即可享受打折及优惠。
(3)您也可以单独购买即时通或企业邮。
网易即时通的优势有哪些?
(1)网易品牌有保障:秉承着网易有态度、高品质、有坚持的精神,我们始终提供高效、安全有保障的专业企业服务。
(2)版本丰富,覆盖用户群体广。
(3)十年磨砺,系统安全稳定:专业、领先的产品研发团队,十年积累,确保产品稳定、品质一流,持续升级,让性价比不断提升。
(4)售前、售后服务完善。
(5)平台化发展路线明确,确保性价比不断提升。
(6)舒适美观,显而易见的高端上档次。
什么是“全程SSL”?
SSL(全称是Secure Sockets Layer)是为网络通信提供安全及数据完整性的一种安全协议。全程SSL指登录即时通管理后台和登录后的所有操作均使用SSL加密,高度保障了数据信息安全。
即时通目前推出了哪些版本?未来如何计划?
即时通目前已推出了Windows、iMac、iOS(iPad、iPhone)3大操作系统版本,支持简体中文、繁体中文、英文3种语言版本及内网独立部署版、公网免不部署版2大服务器版本。 近期还将推出Android版,更多版本会紧跟科技的发展及企业的需求不断增加。
从V2.0版开始为何要将界面架构推翻重建?
作为独立于POPO、QQ等普通聊天软件,从V2.0开始,我们重新定义了企业IM及其发展方向。为打造“以高效沟通为中心的办公平台”,整合企业员工的办公需求。而旧版的架构没有空间满足不断增加的办公应用。V2.0后采用新的架构,不仅打造了“平台化”发展的空间,还重组了操作逻辑,让操作化繁为简,更加高效。
Windows版兼容windows 8操作系统吗?
Windows版本即时通(包括3种语言版本、2大服务器版本)均全面兼容windows 8操作系统。
什么是公网免部署版和内网独立部署版?
网易即时通支持服务器托管在网易和本地独立部署2种方式。 公网免部署版即由网易公司统一提供服务器,企业只要能链接到互联网即可登录网易即时通。本地部署指服务器部署在企业本地,由企业自行维护。 内网独立部署版适合配备成熟IT部门的大中型企业,可以在本地自主配置服务器;公网版本适合中小型企业,由网易公司代为托管。
如何申请免费试用即时通?
您只要在即时通官网上填写并提交申请试用表,我们的销售人员就会尽快与您联系,以引导并协助您进行即时通的免费试用。 申请试用表格填写请到:
如何购买即时通?
登录网易即时通官网填写指定信息并提交至销售后台,经销商或销售人员会在信息提交后的尽快内与您联系,并助您开通服务。 购买即时通请到:
购买即时通需要准备什么资料?
您需要先拥有域名,此域名将作为您的即时通的后缀。
是否可以直接与网易签约购买?
网易不采用直销方式。您须直接与经销商签订合同,如目前没有经销商与您联系,欢迎您拨打400-咨询。
域名如何购买,价格多少?
域名可以从域名提供商购买,具体价格可以咨询域名提供商,如:中国万网、新网。同时,网易即时通经销商也有提供域名服务,经销商可以协助您购买域名。网易公司暂时不提供域名服务。
域名在其他公司注册的,可不可以购买网易即时通?
可以。只要域名没有过期并能够进行域名DNS解析,便可使用该域名开通网易即时通。
更改域名后,会对即时通的使用有什么影响?
更改域名后,不能再使用原域名登录网易即时通。新域名等同于新帐号,无法保存或加载原域名下的聊天记录或个人设置等信息。这虽然给更改域名的企业带来些许麻烦,但同时也避免了企业信息遭受他人。
可以使用域别名或帐号别名登录即时通吗?
对于网易企业邮定制版的客户,可能存在域别名或者帐号别名。即时通目前只支持主域名登录,暂时不支持域名别名和帐号别名登录。因此企业邮定制版的用户只能使用主域名登录网易即时通。
忘记密码怎么办?
当忘记密码时,需要告知企业的即时通组织架构管理员(行政、或部门经理等),由管理员在管理后台进行密码重置。
设置网易即时通的登录密码应该注意什么?
即时通的密码设置必须同时具备以下条件: a. 密码长度6~16位 b. 由英文字母a~z (区分大小写)、数字0~9、特殊字符至少两种组合组成 c. 不可与帐号相同
登录时提示408错误或10008错误怎么办?
(1)请先问询企业网管,确保用户网络能直接或使用代理访问到域名res.popo.163.com的80或443端口(内网版本请网管确认内网服务器部署是否正常)。 (2)请下载即时通网络检测工具双击运行后会生产一个network.log文件,将它和安装目录下Trace_Log.txt文档反馈给我们。 即时通网络监测工具下载:点击本链接下载
网络端口需要开放哪些才能使用即时通?
公网版用户,使用即时通需要开放的网络端口为以下11 个: TCP: 80 端口、443 端口、1821 端口、1822 端口、1823 端口、1824 端口 UDP: 6000 端口、6101 端口、6102 端口、6103 端口、6104 端口
为什么登录的时候会提示登录IP受限?
管理设置了登录IP限制,您所在的IP无法登录即时通。如果需开通请联系贵公司的管理员。
组织架构上可以隐藏个别帐号么?
(1)仅购买即时通的企业,可以在即时通管理后台一键隐藏指定帐号(如下图)
(2)同时购买企业邮的企业,帐号统一在企业邮后台进行管理,您可以在帐号编辑中选择“不可以共享”即可(如下图)
不需要常用部门列表,可以隐藏么?
可以。您只要在常用部门栏右侧下拉菜单中取消勾选“显示常用部门列表”即可(如下图)
组织架构上为什么可以显示昵称?
现今的企业办公沟通中,使用一些昵称或代号更容易记住同事,设置在搜索同事时,也首先想到了同事的昵称或代号。为了更好的助力企业高效沟通,即时通不仅支持员工设置昵称,还可通过搜索昵称来定位同事。
什么是组织架构?组织架构可自行设置吗?
网易网易即时通的组织架构反应了一个企业的部门组成架构,与管理后台的企业通讯录同步。组织架构不可自行设置,而是由管理员在管理后台进行设置。 如果贵公司同时购买了网易企业邮,那么网易即时通客户端的组织架构通讯录自动从贵公司所使用的网易企业邮管理后台自动同步。
什么是常用部门,如何添加\删除常用部门?
常用部门是为了方便企业员工收藏需要经常联系的常用部门而设的。 添加方法:鼠标移至组织架构中某部门名称上,右键弹出菜单中点击“添加到常用部门”。如果要删除某个常用部门,则在常用部门栏目下,选中某个部门,右键弹出菜单中点击“删除常用部门”。常用部门删除后,还可以通过组织架构中再次添加。
可以通过哪些信息搜索到联系人?
支持全局模糊搜索,您只要键入关键字,即时通会通过联系人姓名、昵称、帐号及工作群名称多维度来匹配联系人。
支持搜索工作群么?
支持。您可以键入群名称的部分关键字,即可搜索出指定工作群。
联系人列表有哪些用途?
(1)可将经常联系人同事加入到该列表,方便快速定位 (2)可根据业务、项目等将联系人进行分组,更方便工作联系 (3)实时显示联系人在线、忙碌、离开、离线四种状态 (4)联系人离职时,组织架构上已没有此人,但联系人列表中予以保存,以方便查阅历史消息
联系人右键菜单中的“创建快捷窗口”是什么意思?
当您在电脑上工作时(如撰写文档),可能会担心某个重要联系人的消息无法及时看到。这时您可以在联系人右键点击“创建快捷窗口”,这时会在桌面上显示联系人图标(即快捷窗口),您可以将该图标拖动到桌面任意处。当对方发来消息时,您可以通过“快捷窗口”的闪烁来及时发现新消息。
支持将重要的工作群置顶显示么?
支持。当您的工作群较多时,可以通过在列表中右键常用的群,在弹出菜单中选择“置顶工作群”,下次可以直接在群列表顶部找到该群(如下图)
1个工作群最多可以容纳多少人?
默认情况一个工作群最多可容纳1000人。如需要扩容,可联系客服申请免费扩容,最大可扩充至5000人。
群人数不到1000,再邀请却提示人数上限?
先前发出了入群邀请,未验证加入的成员也会占据群内名额,使得实际群内成员数超过了1000人。比如:原来的群人数有900人,新邀请了100人,但这100人并未验证加入,实际也会占用名额,导致人数到达上限。如果需要邀请其他人,可以将未验证加入的成员先移出该群。
什么是“工作群”?如何创建\解散工作群?
工作群是为了方便员工交流而提供的一种多人固定群组聊天功能。工作群的创建和解散只能由公司管理员在管理后台进行。
工作群右键菜单中的“创建快捷窗口”是什么意思?
当您在电脑上工作时(如撰写文档),可能会担心某个重要工作群的消息无法及时看到。这时您可以在工作群右键点击“创建快捷窗口”,这时会在桌面上显示工作群图标(即快捷窗口),您可以将该图标拖动到桌面任意处。当对方发来消息时,您可以通过“快捷窗口”的闪烁来及时发现新消息。
为什么我在忙碌状态下收不到其他人的消息?
网易即时通设置个人状态为忙碌时,默认采用了新消息不弹窗,只在主窗口显示未读消息列表的方式。您可以在系统配置-消息模式里自行配置修改。 如下图:系统是默认勾选“忙碌状态时,在主窗口自动显示未读消息列表”的,如不需要,请将勾选去掉。
网易即时通一条消息的上限是多少字符?
您可以一次最多发送5000个汉字,超过会有提示。
会话消息中的图片显示为红叉该怎么办?
(1)请先问询企业网管,确保消息双方的网络都能直接或使用代理访问到公网服务器的、udp 6000以上端口(内网版本请网管确认内网服务器部署是否正常)。 (2)消息双方的本地杀毒软件/防火墙可能对网络端口访问有限制。 (3)可能发送的图片太大,导致传输超时。 (4)在群里发送,可能接收者人数太多了,导致的传输超时。
邀请多人会话时,邀请界面上的人怎么变少了?
多人会话只能邀请在线成员加入,邀请界面上只显示在线成员,会比实际的人数少。
win7下无法直接拖动文件到对话窗口怎么办?
找到即时通启动程序,右键-属性,选择兼容性,在特权等级那里,将“以管理员身份运行此程序”的勾选去掉。
消息记录的安全性如何?
(1)消息记录采用领先的加密技术,以确保信息安全。 (2)支持消息记录自动备份,让消息记录永不丢失。 (3)升级过程自动备份消息记录
如何导入、导出消息记录?
点击即时通主界面下方的消息历史按钮,打开“即时通消息历史”界面。点击左上角的【导入】或【导出】,根据提示操作即可。 (1)如果导出后还需导入,请导出为“备份文件” (2)“导出全部”可导出与所有联系人的消息记录;“导出”仅可导出与当前选定联系人的消息记录。
应用面板展开后可看到两个不同的区域,它们的关系是什么?
应用面板分为“普通应用区”和“常用应用区”,所有的应用(包括系统自带应用)都可在两个区域中拖动切换位置。(如下图)
展开应用面板时,所有应用为什么看上去都浮起来了?
应用面板在展开时处于编辑状态,此时所有的应用可以编辑及拖动排序。应用图标“浮起来”暗示着“正处于编辑状态”。
为什么应用面板收起时,所有应用无法找到设置按钮也不能拖动排序?
应用面板收起时,处于非编辑状态,是不能对应用进行编辑和排序的。如果您想进行这两项操作,请展开应用面板(展开即进入编辑状态)后再进行编辑和排序。
自定义应用只能添加常用网页么?
目前只提供添加常用网页,但以后会根据企业需求逐渐增加类别。
支持未读邮件提醒么?
支持,但目前并不是实时提醒。即时通默认每10分钟检查一次是否有未读邮件。
为什么个人资料中部分信息无法修改?
帐号、真实姓名、企业名称、部门、职务、工号、邮箱是由企业邮管理员在管理后台设置的。若需修改,请联系您所在企业的具有即时通管理员权限的同事进行修改。
请写下你的反馈和期待:
公司规模:
联络方式:
已达最大输入字数限制
暂时无法提交,请稍后再试! 提交
即时通感谢您的反馈! 继续浏览群组、讨论组中 @ 功能介绍
群组、讨论组中 @ 功能介绍
产品功能介绍
从 2.6.8 版本开始,在群组、讨论组中实现了 @ 功能,可以通过 @ 指定的用户或 @ 所有用户,提醒被 @ 的人,有关于你的消息内容,融云在 &IMKit 中已经对 @ 功能进行封装,默认为关闭状态,开启方式请参见开发文档:iOS :Android:一、发启 @ 功能开启后可通过两种方式发起 @ 功能。1、会话界面中长按用户头后,会在消息输入框中显示被 @ 的用户,并在用户名后自动插入一个空格,如图:2、在消息输入框中,输入 @ 字符后,弹出成员选择界面(如图),选择你要 @ 的成员后,返回到会话界面,消息输入框中显示被&@ 的用户。注意:在输入框中,输入 @ 字符时,如果 @ 字符前为数字或英文字母时,则无法弹出群成员或讨论组成员的选择界面,你需要在数字或英文字母后,输入空格或其他字符后再 @ 用户。二、删除已选择的 @ 用户选择一个 @ 的用户后如 “@张三 ”,在点击退格键删除时,会将 “@张三 ”这个 @ 用户内容整个删除三、@ 消息推送内容发送 @ 消息后,被&@ 用户的通知栏、会话列表中会显示“[有人@我]”的状态提示,如图:注意:@ 消息推送会越过所有免打扰逻辑,给用户推送 Push 通知。四、会话列表展示,如图:五、@所有人功能通过设置 MentionInfo 中的 MentionedType 实现 @ 所有人的功能,详细请参考文档:iOS: Android:
3 位开发者认为此问题有帮助
我对此仍有疑问!客服:010-
集成三人即时通流程图
1、ITOSS集成三人即时通(Web Hook)
实时自动同步所有频道群组;设置故障报警发往指定频道。
3、协同运维处理解决
ITOSS自动发送故障报警到指定的频道群组聊天框中。
2、实时ITOSS故障告警
在群聊界面就可以查看报警详细情况,运维人员就故障问题讨论协同处理解决。
设置报警发送指定频道
例如:登陆本地ITOSS系统,点击&IT资源管理&主功能菜单,点&报警&选&报警规则&,然后设置报警,在报警设置中选择报警规则关联的资源,填写聊天室报警动作中的&聊天室地址&,最后点击获取地址后勾选聊天室报警,指定一个聊天室频道保存就设置好了。
接收报警群聊协同处理
例如:ITOSS在实时监测过程中,发现故障报警自动发送到三人即时通的&总部IT监测运维部&频道,然后IT运维人员就故障的详细情况各方进行沟通讨论、协同处理解决故障。
集成案例示例:非常适合IT运维部门使用
从手机端实例图中:
标识A实现了物联传感器发送报警与处理信息到单个的聊天频道群组;
标识B实现了群组沟通、协作来快速搭建业务应用网络。
Web端实例图中:
标识C定制的天气预报应用;
标识D是聊天信息框支持的&/&斜杠命令功能发送邮件邀请;
标识E是定制的监测IT故障报警信息发送到群组中,定制的IT监测详细状况以集成的&/&斜杠命令功能进行展示;
标识F实现了群组针对报警信息进行沟通,各方响应处理、参与讨论协作解决问题。
三人即时通介绍
三人即时通(https://www.3ren.group和https://www.3ren.com)是企业内部沟通、群聊、协作、共享的即时通讯平台,三人即时通部署在企业的防火墙后面,是一种私有云IM,可专属定制,支持与企业几十种业务应用对接或集成,实现企业自主、可控、安全、可靠的沟通协作,具有服务应用价值,更适合企业内使用。
三人即时通提高工作效率90%,安全性提升90%,100%适合企业内应用,驱动业务效益10倍。
三人即时通主要功能
消息功能: 支持Web网页、移动和PC端即时通讯、消息搜索、文件共享管理、一站式协同办公等功能。
私有云: 可部署在企业防火墙保护的局域网内部,建设企业私有云即时通讯平台。
多功能选择: 集成所有QQ的热门功能,以及兼容集成包括Webhooks等工具与服务,用户自定义主题、通讯录的导入等。
数据中心: 支持MySQL或PostgreSQL数据库,并可以进行数据库集群或者平滑递增硬件资源,以及后继按需求扩展业务应用的工具与服务等。
高级安全性:分权限管理、加密推送通知、IT策略安全高级访问控制。
企业规模: 支持企业大规模数千万级的用户应用,并具有消息高级同步和自动化的用户、角色管理,平台系统100%高稳定、高可用、高可靠。
三人即时通特点优势
部署到企业内网,是一款属于企业内部完全自主控制的私有化即时通讯平台,且单元频道、群组数量不限、功能不受限制。
在防火墙后面部署现代通信,将您的重要信息保持在IT控制之下,拥有您的数据,永远不会被锁定或泄露等隐患。
推出灵活,兼容的企业级解决方案。根据您的需求为您量身打造属于您的私有可控聊天、业务协作、业务应用工具集成的平台。
从单一用户的解决方案中为成千上万的用户提供横向扩展、业务整合应用与协作功能扩展,高可用性和高级性能监控扩展等。
人物互联互通与协同
三人即时通实现了&人-物&、&人-人&的互联互通与群聊。
人-物互联:物联网设备、服务器等报警信息发向指定的群聊频道。
人-人互联:群组成员讨论沟通协同解决问题。
售前咨询:
远程维护:
微信联系方式:即时通讯机制和集成步骤(转)_早过忘川_新浪博客
即时通讯机制和集成步骤(转)
说说融云即时通讯SDK理论篇(一)&
标签: 即时通讯、聊天、融云、sdk、iOS 分类: 即时通讯 版权声明:本文为博主原创文章,未经博主允许不得转载。
本人用过融云的1.4.4和2.2.4版本的SDK,分别用于对两款APP的即时通讯功能开发集成,主要用了IMKit类,功能为单聊(聊天室和群聊不涉及,理解了单聊,聊天室和群聊也就不攻而破),吐槽一下关于iOS端融云SDK集成资料很少,只能看融云官方的开发文档,由于开发文档的语言和关键词用的也比较官方比较专业化,我想要通俗易通,雅俗共赏的资料,没有!没有!真的没有!博客之类的资料只能找到安卓的文章,无奈只能iOS小屌丝看安卓大神写的关于融云集成的android代码,小伙伴们看的是很蛋疼。现在福利来了,iOS端的融云集成博客这边看,会不断更新,持续关注。想集成融云聊天功能的小伙伴不防先普及下理论知识,防止以后走弯路又或者总是问些不靠谱的问题,“我为什么不能聊天”,“为什么头像和名字出不来”等等一系列问题,文章中如果有错误的地方希望大家提出,本人会及时改正,避免误人子弟,高手勿喷,哈哈。。。
融云的SDK可以解决很多app中即时通讯的功能,无论是安卓还是iOS(web也可以,强大无比),都可以考虑用第三方去实现聊天的功能,而且现在app中集成聊天的功能很火很时髦,不是吗?收废品、旧家电的老板都恨不得为自己的APP加上即时通讯翅膀,让自己的app飞起来。废话少说,先来理解下融云的即时通讯机制,也就是理论部分。
融云不维护好友关系,只负责转发消息。不维护好友关系是什么意思?我用融云的SDK集成聊天,好友之间都可以进行聊天啊,怎么会不维护好友关系呢!?那么我们来理解下:“不维护好友关系,只负责转发消息”的意思是融云的服务器给我们转发消息,融云的SDK完成发送消息的功能(SDK中的方法实现,web后台也可以调用融云提供的接口发送消息),消息从一个人fromUserId(每个人都有一个id,后面会详细讲到)转发到另一个人toUserId那里,那么每个用户的好友关系和群组关系是要保存在自己公司的服务器的,这点就解释了上面的话,融云提供一个转发消息的平台(服务器和SDK以及接口等),因为要满足广大开发者的需求,所以不可能为没个开发者都维护这个好友关系和群组关系。举个栗子,用户A有100个好友,那么这个融云是不知道的,也不会关心用户A的好友关系,谁知道呢?我们开发者自己的后台要知道,我们自己的服务器要维护好友关系和群组关系,具体做法就是要用接口去建立好友关系,然后再用另外的一个接口去保存用户A的所有好友。这样的话,用户A登录之后就可以调用好友列表的接口拿到自己的所有好友,然后就可以为所欲为了,其实也就是和自己的好友发送消息了,发送消息的时候,不是走自己公司的服务器发送消息,注意,这里发送消息是走融云的服务器,怎么会走融云的服务器呢?奇怪,融云怎么知道我登录了呢?别急,下面会讲到token,以及connect连接融云服务器。消息的流向是这样的,从自己这里fromUserId(自己的id)走到融云的服务器,然后融云服务器转发到好友toUserId那里,因为消息体中含有很多的属性,消息体本身可以附带信息,比如targetId(就是toUserId,这里两者一样),extra附加信息,用于提供给开发者拓展功能,你想让消息带什么信息都可以带,但是大小有限制,一般带字符串或json数据,我用这个字段解决了好友头像的及时更新功能,这个字段的用法放开发篇章中细细讲解。
现在说说userId,用户的“身份证号码”。每个APP的注册用户都会被分配一个userId,就是用来区分用户的,就好像我们的身份证号码一样,不会重复,具有唯一性。那么再说说谁去分配用户A的userId呢?融云会分配吗?答案是NO。还是那句话融云只负责转发消息,分配userId这个任务还是要我们后台自己来搞,当用户A注册的时候,后台分配给A一个userId并且返回给前端开发人员使用,前端开发人员拿到A的userId之后,就要用这个A用户的唯一的userId去登录融云的服务器,当然不是任何人有个userId都可以随便连接融云的服务器的哦,大家都知道任何第三方公司都没有那么随便,不安全,会被攻击,是要Token验证的。有这个Token就让你连接,没有token的话,滚蛋。那么我们写demo,测试的话怎么办,token怎么获取?去融云强大的后台调试系统里面去拿token测试,登录融云的官网之后点击你创建的应用,然后找到IM服务中的API调试,第一个就是获取token。整个登录的流程是这样滴,开发者去融云官网注册个账号----&登录融云官网----&创建一个应用----&拿到融云分配给此应用的appkey----&app中代码先注册融云的appKey----&获取token获取token----&拿token去connect融云服务器。大概就是这样,但是开发过程中要注意以下几点:
(一)appkey包括正式上线的appkey和开发环境的appkey。现在的新SDK取消用appSecret,我们代码中用的是appkey,不是appSecret,所以暂时不要管appSecret,但是不要随便刷新这个秘钥,后果自负。
(二)token怎么获取,哪里去获取?token的获取是要自己公司的后台提供一个获取融云token的专门接口,自己的后台开发人员去看文档做接口,后台相关事情这里不做解答(一句话:去看融云开发文档)。获取到token后,就可以拿一个用户A的userId去连接融云的服务器了,融云的方法叫connectWithToken,connect成功了之后会返回登录人的userId,失败了会返回error的描述(一个枚举,详细的解释connect失败的原因)。具体看下面代码,注意,我的做法是每次都获取token,还有其他的处理token方式,具体的看融云开发指南,我这里提供一种解决方案。
(三)集成的步骤不要错了,一定要按照顺序。我举个栗子,有些开发者把项目用StoryBoard搭建起来之后,就马上想用聊天列表,想看到聊天列表,想看看聊天界面,这样有时候会崩溃,就跑来问我,怎么回事?我也很难回答你是怎么一回事。所以大家先把项目建立起来,然后按照步骤,一步一步的来,你都没注册appkey,也没有拿token,也没有connect。那么这样的崩溃让融云的技术或者是我去解决这样的bug,其实我们的内心也是崩溃的。
这句代码是注册appkey的,先看看,到开发篇里面还会有 [[RCIM sharedRCIM]
initWithAppKey:@"YourTestAppKey"];
下面的blok是用token去链接融云服务器。开发篇还会再提供,先初步了解下。
[[RCIMsharedRCIM]connectWithToken:YourToken success:^(NSString
*userId) {
[RCIMsharedRCIM].globalNavigationBarTintColor = [UIColorwhiteColor];
NSLog(@"login success with userId %@",userId);
[UserInfoModel loginUserinfo:model];
//同步好友列表
[self syncFriendList:^(NSMutableArray *friends,BOOL isSuccess) {
NSLog(@"%@",friends);
if (isSuccess) {
NSLog(@" success发送通知");
[[NSNotificationCenterdefaultCenter]postNotificationName:@"alreadyLogin" object:nil];//发送自定义通知(不是融云的),处理一些逻辑,比如什么各单位注意,我已登录,我已登录。
[RCIMClient sharedRCIMClient].currentUserInfo = [[RCUserInfoalloc]initWithUserId:userinfo.userIdname:userinfo.userNameportrait:userinfo.photophone:userinfo.phoneaddressInfo:userinfo.companyrealName:userinfo.realName];
} error:^(RCConnectErrorCode status) {
NSLog(@"status = %ld",(long)status);
} tokenIncorrect:^{
self.success =NO;
[MSUtil showTipsWithHUD:@"tokenIncorrect"];
连接成功了,继续看。要想和好友聊天,我们还要有好友,有了好友才能正常聊天,我的好友是保存在一个全局的数组里面的,app启动的时候,我网络请求自己的后台,拿到我们后台维护的好友数组,然后放数组里面,这样我全局可以拿到。另外,还要实现一个代理方法,这个代理叫做RCIMUserInfoDataSource(2.2.4版本的叫RCIMUserInfoDataSource,以前的老版本比较麻烦些,要实现两个代理
RCIMFriendsFetcherDelegate,RCIMUserInfoFetcherDelegagte
)这个代理方法是提供好友信息的,给谁提供好友信息?你和你的好友聊天,系统会自动走代理方法,去拿好友信息,所以那些说“我的好友头像和名字怎么出不来”的同学要注意了,遵守代理了吗?是不是你的代理没设置,是不是没实现代理方法,方法里面有没有问题,有没有配置好你的好友信息?不然好友头像和名字怎么会出不来呢!附上代理方法名字和实现
(void)getUserInfoWithUserId:(NSString)userId
completion:(void (^)(RCUserInfo))completion
NSLog(@"getUserInfoWithUserId ----- %@", userId);
if (userId == nil || [userId length] == 0 )
completion(nil);
if ([userIdisEqualToString:[RCIMsharedRCIM].currentUserInfo.userId]) {//自己
UserInfoModel *myselfInfo = [UserInfoModelcurrentUserinfo];
RCUserInfo *aUser = [[RCUserInfoalloc]initWithUserId:myselfInfo.userIdname:myselfInfo.realNameportrait:myselfInfo.photophone:myselfInfo.phoneaddressInfo:myselfInfo.companyrealName:myselfInfo.realName];
completion(aUser);
for (NSInteger i =0; i&[AppDelegateshareAppDelegate].friendsArray. i++) {//循环全局的好友数组,拿到userId相同的,比如,userId= 12的是老王,那么循环,找到数组中userId=12的,那么肯定就是老王啦。那么肯定就配置好老王的信息了,和老王聊天的时候,融云内部封装的方法就可以拿到老王的信息,这样老王的头像和名字就可以出来了
RCUserInfo *aUser = [AppDelegateshareAppDelegate].friendsArray[i];
if ([userId isEqualToString:aUser.userId]) {
completion(aUser);
最后开始发消息给好友,比如点击一个cell(或者一个页面的Button),拿到这个cell对应人的userId,拿到对方的userId后,就可以建立一个会话了,那么开始上代码
ConversationViewController *_conversationVC =
[[ConversationViewControlleralloc]init];
_conversationVC.conversationType =
ConversationType_PRIVATE;//单聊(也叫私聊),会话类型
_conversationVC.targetId =
[NSStringstringWithFormat:@"%@",model.data[@"id"]];//消息的目标id,对方的userId,就是上文说的toUserId
_conversationVC.userName =
[NSStringstringWithFormat:@"%@",model.data[@"agentTeamName"]];//会话对方的人名字
_conversationVC.title =
[NSStringstringWithFormat:@"%@",model.data[@"realName"]];//会话导航上的title
[self.navigationControllerpushViewController:_conversationVCanimated:YES];
ConversationViewController是开发者自己建立的VC,继承融云的RCConversationViewController类,继承之后,子类就可以用重写父类的方法了,想用什么就点进去找什么方法,如果你也不知道你需要什么方法,那么就跟着我的文章走,我将会介绍大部分融云API的使用场景。
好了,现在可以发送消息了,因为RCConversationViewController类已经实现了UI和功能。
理论篇到此结束。下面会有开发篇,谢谢。有问题在我的开发群里提问,群号.
----------------------华丽丽的分割线------------------------
----------------------华丽丽的分割线------------------------
----------------------华丽丽的分割线------------------------
----------------------华丽丽的分割线------------------------
----------------------华丽丽的分割线------------------------
----------------------华丽丽的分割线------------------------
说说融云即时通讯SDK开发篇(二)&
理论知识理解之后,就可以快速集成了。有多快?常常有开发者问,一天可以集成融云的聊天功能吗?我想说我现在一天都搞不定,你不用处理逻辑的吗?你仅仅是写个demo还是做项目啊?如果是写个demo,我1个小时可以集成聊天功能了。所以大家还是要按部就班的来,欲速测不达。
好了,不扯淡了,开始集成。
一,去融云官网(http://www.rongcloud.cn)下载SDK。补充一句最好用官网最新的SDK,千万不要倒退啊,最新的SDK比较完善,把以前旧版本的SDK的bug都修复了,当然肯定还有bug存在,但是已经比较少了,而且你也不一定就踩到雷了,如果踩到了,去给融云发工单,每个工单都会得到回答,大部分会令你满意的,不满意也没办法。好了,下载完之后找到SDK的文件夹,打开,然后自己在自己工程中建立一个新的文件夹比如我的就是RongCloud_SDK_2_2_4,这样清晰明了的看到了作用和版本号,再然后就是拖SDK进来工程中的文件夹RongCloud_SDK_2_2_4,除去release_notes_ios.txt不用拖进来,其他的都拖进来,不然你就拖了两个frameWork,后面开发中肯定你会叫,为什么我的表情😊
出不来,为什么我的是英文的,各种奇葩bug出现了,原因就在此,你要把emoji的plist文件和语言国际化的东东也一起拉进工程。记得点击copy选项。
二,添加frameWork,而且要全面。在第一步的基础上添加融云SDK的依赖库,都是系统的,官网有库列表,慢慢加。
AssetsLibrary.framework
AudioToolbox.framework
AVFoundation.framework
CFNetwork.framework
CoreAudio.framework
CoreGraphics.framework
CoreLocation.framework
CoreMedia.framework
CoreTelephony.framework
CoreVideo.framework
ImageIO.framework
libc++.tbd
libc++abi.tbd
libsqlite3.tbd
libstdc++.tbd
libxml2.tbd
MapKit.framework
OpenGLES.framework
QuartzCore.framework
SystemConfiguration.framework
UIKit.framework 三、到工程的设置选择中,系统setting,搜索到Other linker Flags
双击这一行,填写-ObjC,主意O和C是大写的,大小写敏感。(不加这个flag好像发消息会崩溃) 四、导入头文件
这个一般应该是在appdelegate里面倒入,因为程序入口,我们要初始化融云的appkey(理论篇有详细介绍,开发篇不再赘述)。
在这个方法中初始化
(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
,最好写一个方法专门放置融云的逻辑,initRongCloud方法放置融云的初始化
(void)initRongCloud{
这个好友数组friendArray,我放到appdelegate的.h中声名,程序任何地方可以通过appdelegate这个单例拿到,想哪里用就可以在哪里用。这个数组是存放我的全部好友信息的,里面放的是RCUserInfo,每个好友都是RCUserInfo的一个实例对象。
self.friendsArray = [[NSMutableArray alloc]init];
//测试环境 AppKey XXXXXAppKey AppSecret XXXXXXAppSecret
//正式上线环境 AppKey XXXXXAppKey AppSecret XXXXXAppKey
NSString *rongYunKey = @"yourAPPKey";
判断用正式appkey还是测试appkey,测试开发环境最好不要用正式的key哦,不要怪我没提醒。 if
([kNetwork_Host
isEqualToString:@"http://weixintest.ihk.cn
"]) {//正式环境用正式key,开发测试环境用测试的key
rongYunKey = @"your 正式appkey";
}else{ rongYunKey = @"your 测试appkey";
} //初始化appkey [[RCIM sharedRCIM] initWithAppKey:rongYunKey];
//初始化全局的单例RCDataManager(融云数据管理者),这个RCDataManager把所以融云有关数据的逻辑和代码分离了,方便该,也方便维护。这里把userInfoDatasource设置为RCDataManager。
[RCIM sharedRCIM].userInfoDataSource = [RCDataManager
shareManager];
[RCIM sharedRCIM].enableMessageAttachUserInfo = YES;
//登录融云(注意这里是第n次登录,n&1,第一次登录的逻辑在登录页面点击登录按钮的时候,一样调用这句话,因为逻辑全交给RCDataManager处理了,外部调用方法即可)
[[RCDataManager shareManager] loginRongCloud];
初始化完成后就是拿token,然后用一个人(当前用户啊)的userId去connect了,那么这个逻辑我没有把代码写在appdelegate,因为业务相同的逻辑应该分离出来,要不全部代码写appdelegate里面太乱,太难维护,我们把有关融云的逻辑抽离出来,放一个类RCDataManager中去管理,那么我的这个RCDataManager完成了什么功能,什么逻辑,具体怎么设计这个类,为什么要这样设计。下面详细介绍下怎么把融云的逻辑模块分离出来,写出高一点质量的代码。
RCDataManager是个单例类,主要功能就是登录融云,刷新好友列表,设置好友信息提供者代理等等,设置tabbar的角标等等。他的好处是把融云的逻辑分离出来,业务逻辑分离,方便维护工程,我们用的时候就一句代码就可以了,比如登录就这样
[[RCDataManager shareManager]
loginRongCloud];具体RCDataManager类的代码如下:
@interface RCDataManager : NSObject
RCIMUserInfoDataSource是融云的好友提供者代理,很重要,非常重要,及其重要,遵守之,实现之。
@property(nonatomic,assign)BOOL
+(RCDataManager *) shareM
(void)getUserInfoWithUserId:(NSString)userId
completion:(void (^)(RCUserInfo
-(BOOL)hasTheFriendWithUserId:(NSString *)userId;
-(void)loginRongC
//同步好友列表的方法,用此方法可以刷新到最新的好友列表,比如有新朋友了,那么就要同步一下 -(void)
syncFriendList:(void (^)(NSMutableArray * friends,BOOL
isSuccess))
-(void)refreshBadgeV
-(NSString *)currentNameWithUserId:(NSString *)userId;
-(RCUserInfo *)currentUserInfoWithUserId:(NSString *)userId;
再看实现文件里面的代码
import "RCDataManager.h"
@implementation RCDataManager{
NSMutableArray *dataS
(instancetype)init{
if (self = [super init]) {
[RCIM sharedRCIM].userInfoDataSource =
dataSoure = [[NSMutableArray alloc]init];
(RCDataManager *)shareManager{
static RCDataManager* manager =
static dispatch_once_
dispatch_once(&predicate, ^{
manager = [[[self class] alloc] init];
-(void)syncFriendList:(void (^)(NSMutableArray* friends,BOOL
isSuccess))completion
//这里是用户的身份,可能其他开发者不需要这个逻辑,不需要的话,就直接调用好友列表的接口,拿到好友列表的数组,做成RCUserInfo,然后add进去数组。就这简单!
UsersType type = [MSUtil checkUserType];
if (type==UsersTypeYouke) {//游客
//不能聊天
else if(type==UsersTypeSales){//销售
[Networking getMyClientsWithPage:@"1" pagesize:@"10000" success:^(NetworkModel *model) {
NSLog(@"%@",model.msg);
if ([model.data isKindOfClass:[NSString class]]) {
//LOGIN_CHECK_NO
NSLog(@"%@",model.data);
}else if ([model.data isKindOfClass:[NSDictionary class]]){
[dataSoure removeAllObjects];
for (NSDictionary *infoDic in model.data[@"rows"]) {
RCUserInfo *userInfo = [[RCUserInfo alloc]init];
userInfo.userId = [NSString stringWithFormat:@"%@",infoDic[@"id"]];
// if ([[NSString
stringWithFormat:@"%@",infoDic[@"salesNickName"]]
isEqualToString:@""]) {
// userInfo.name = [NSString
stringWithFormat:@"%@",infoDic[@"realName"]];
// userInfo.name = [NSString stringWithFormat:@"%@
%@",infoDic[@"realName"],infoDic[@"salesNickName"]];
userInfo.name = [[NSString stringWithFormat:@"%@",infoDic[@"realName"]] isEqualToString:@""]?[NSString stringWithFormat:@"%@",infoDic[@"loginName"]]:[NSStringstringWithFormat:@"%@",infoDic[@"realName"]];
userInfo.portraitUri = [NSString stringWithFormat:@"%@",infoDic[@"photo"]];
userInfo.phone = [NSString stringWithFormat:@"%@",infoDic[@"phone"]];
userInfo.addressInfo = [NSString stringWithFormat:@"%@",infoDic[@"company"]];
userInfo.realName = [NSString stringWithFormat:@"%@",infoDic[@"realName"]];
[dataSoure addObject:userInfo];
[AppDelegate shareAppDelegate].friendsArray = dataS
completion(model.data[@"rows"],[model.result isEqualToString:@"10000"]?YES:NO);
NSLog(@"好友列表 = %@",[AppDelegate shareAppDelegate].friendsArray);
if ([AppDelegate shareAppDelegate].friendsArray.count) {
NSLog(@"从服务器同步好友列表成功FFF");
[self loginRongCloud];
for (RCUserInfo *aUser in [AppDelegate shareAppDelegate].friendsArray) {
NSLog(@"name =%@ userId =%@",aUser.name ,aUser.userId);
} fail:^(NSError *error) {
NSLog(@"error= %@",error);
NSLog(@"从服务器同步好友列表失败 ~~~");
}else if(type==UsersTypeCustomer){//用户
[Networking getMyBrokerAppUsersWithPage:@"1" pagesize:@"10000" success:^(NetworkModel *model) {
if ([model.data isKindOfClass:[NSString class]]) {
}else if ([model.data isKindOfClass:[NSDictionary class]]){
[dataSoure removeAllObjects];
for (NSDictionary *infoDic in model.data[@"rows"]) {
RCUserInfo *userInfo = [[RCUserInfo alloc]init];
userInfo.userId = [NSString stringWithFormat:@"%@",infoDic[@"id"]];
userInfo.name = [[NSString stringWithFormat:@"%@",infoDic[@"salesNickName"]] isEqualToString:@""]?[NSString stringWithFormat:@"%@",infoDic[@"realName"]]:[NSStringstringWithFormat:@"%@",infoDic[@"salesNickName"]];
userInfo.portraitUri = [NSString stringWithFormat:@"%@",infoDic[@"photo"]];
userInfo.phone = [NSString stringWithFormat:@"%@",infoDic[@"phone"]];
userInfo.addressInfo = [NSString stringWithFormat:@"%@",infoDic[@"company"]];
userInfo.realName = [NSString stringWithFormat:@"%@",infoDic[@"realName"]];
[dataSoure addObject:userInfo];
[AppDelegate shareAppDelegate].friendsArray = dataS
NSLog(@"好友列表 = %@",[AppDelegate shareAppDelegate].friendsArray);
completion(model.data[@"rows"],[model.result isEqualToString:@"10000"]?YES:NO);
if ([AppDelegate shareAppDelegate].friendsArray.count) {
NSLog(@"从服务器同步好友列表成功FFF");
if ([RCIMClient sharedRCIMClient].currentUserInfo.userId) {
[self loginRongCloud];
for (RCUserInfo *aUser in [AppDelegate shareAppDelegate].friendsArray) {
NSLog(@"name = %@",aUser.name);
NSLog(@"name = %@",aUser.userId);
} fail:^(NSError *error) {
NSLog(@"error = %@",error);
NSLog(@"从服务器同步好友列表失败 ~~~");
//获取一个userId对应的好友对象,这个对象我们叫做RCUserInfo,这个是融云的类,我们看看源代码的.h里面怎么写
-(RCUserInfo *)currentUserInfoWithUserId:(NSString *)userId{
for (NSInteger i = 0; i&[AppDelegate shareAppDelegate].friendsArray. i++) {
RCUserInfo *aUser = [AppDelegate shareAppDelegate].friendsArray[i];
if ([userId isEqualToString:aUser.userId]) {
NSLog(@"current = %@",aUser.name);
这是RCUserInfo的.h
@interface RCUserInfo : NSObject&
@property(nonatomic, strong) NSString *userId;
@property(nonatomic, strong) NSString *
@property(nonatomic, strong) NSString *portraitU
(instancetype)initWithUserId:(NSString *)userId name:(NSString
*)username portrait:(NSString *)
这个类就一个model类,保存了一个人的用户信息,有三个,userId(唯一id),name名字,portraitUri头像地址url
string,类中提供了一个初始化方法,传三个参数就可以了,头像可以用nil,传nil就用默认头像。大家看看我的RCDataManager类中用到的RCUserInfo的初始化方法,是不是不一样,
RCUserInfo *aUser = [[RCUserInfo
alloc]initWithUserId:myselfInfo.userId
name:myselfInfo.realNameportrait:myselfInfo.photo
phone:myselfInfo.phone
addressInfo:myselfInfo.companyrealName:myselfInfo.realName];
我category了RCUserInfo添加了我要的属性进去,比如公司名字,地址,真是名字等等。在开发中如果觉得RCUserInfo类中的属性不够用,可能开发者还需要每个用户带有更多的属性,那么就可以用我的方法,这样一来,每个用户身上就绑定了很多的属性,想怎么用就怎么用。
那么紧接着我把RCUserInfo的给大家展示下,这个可能大部分开发者都有这个需求。我是之一,废话不说,直接上代码看.h
@interface RCUserInfo (Addition)
@property(nonatomic, strong) NSString *userId;
@property(nonatomic, strong) NSString *
@property(nonatomic, strong) NSString *portraitU
@property(nonatomic, strong) NSString *
@property(nonatomic, strong) NSString *addressI
@property(nonatomic, strong) NSString *realN
(instancetype)initWithUserId:(NSString *)userId name:(NSString
*)username portrait:(NSString *)portrait phone:(NSString *)phone
addressInfo:(NSString *)addressInfo realName:(NSString
再看RCUerInfo的category的.m文件。这里用了runtime的知识,不懂的请自行百度或者参考此链接http://www.cnblogs.com/wupher/archive//2845338.html
import "RCUserInfo+Addition.h"
@implementation RCUserInfo (Addition)
@dynamic addressI
(instancetype)initWithUserId:(NSString *)userId name:(NSString
*)username portrait:(NSString *)portrait phone:(NSString *)phone
addressInfo:(NSString *)addressInfo realName:(NSString
*)realName{
if (self = [super init]) {
self.userId
self.portraitUri
self.phone
self.addressInfo
self.realName
//添加属性扩展set方法
char* const PHONE = "PHONE";
char* const ADDRESSINFO = "ADDRESSINFO";
char* const REALNAME = "REALNAME";
-(void)setPhone:(NSString *)newPhone{
objc_setAssociatedObject(self,PHONE,newPhone,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
-(void)setAddressInfo:(NSString *)newAddressInfo{
objc_setAssociatedObject(self,ADDRESSINFO,newAddressInfo,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
-(void)setRealName:(NSString *)nweRealName{
objc_setAssociatedObject(self,REALNAME,nweRealName,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
//添加属性扩展get方法
-(NSString *)phone{
return objc_getAssociatedObject(self,PHONE);
-(NSString *)addressInfo{
return objc_getAssociatedObject(self,ADDRESSINFO);
-(NSString *)realName{
return objc_getAssociatedObject(self,REALNAME);
//获取一个userId的好友的名字
-(NSString *)currentNameWithUserId:(NSString *)userId{
for (NSInteger i = 0; i&[AppDelegate shareAppDelegate].friendsArray. i++) {
RCUserInfo *aUser = [AppDelegate shareAppDelegate].friendsArray[i];
if ([userId isEqualToString:aUser.userId]) {
NSLog(@"current = %@",aUser.name);
return aUser.
//这个代理方法很重要,好友信息的提供者,单例的时候,是一定要实现这个代理方法的,并把你的好友信息用一个for循环给completion。
pragma mark - RCIMUserInfoDataSource
(void)getUserInfoWithUserId:(NSString)userId
completion:(void (^)(RCUserInfo
))completion
NSLog(@"getUserInfoWithUserId ----- %@", userId);
if (userId == nil || [userId length] == 0 )
completion(nil);
if ([userId isEqualToString:[RCIM sharedRCIM].currentUserInfo.userId]) {
UserInfoModel *myselfInfo = [UserInfoModel currentUserinfo];
RCUserInfo *aUser = [[RCUserInfo alloc]initWithUserId:myselfInfo.userId name:myselfInfo.realNameportrait:myselfInfo.photo phone:myselfInfo.phone addressInfo:myselfInfo.companyrealName:myselfInfo.realName];
completion(aUser);
for (NSInteger i = 0; i&[AppDelegate shareAppDelegate].friendsArray. i++) {
RCUserInfo *aUser = [AppDelegate shareAppDelegate].friendsArray[i];
if ([userId isEqualToString:aUser.userId]) {
completion(aUser);
//登录融云
-(void)loginRongCloud{
UserInfoModel *userinfo = [UserInfoModel currentUserinfo];
if (userinfo.login==YES&&![userinfo.userId isEqualToString:@""]&&![RCIMClientsharedRCIMClient].currentUserInfo.userId) {
[Networking getAppUserTokenWithUserId:userinfo.userId name:userinfo.realNameportraitUri:userinfo.photo success:^(NetworkModel *model) {
if ([model.result isEqualToString:@"10000"]) {
NSLog(@"RCToken = %@",model.data);//model.data就是我们的token啦,有了他,我们才能进行下一步connect
self.success = YES;
[[RCIM sharedRCIM] connectWithToken:model.data success:^(NSString *userId) {
[RCIM sharedRCIM].globalNavigationBarTintColor = [UIColor whiteColor];
NSLog(@"login success with userId %@",userId);
[UserInfoModel loginUserinfo:model];
//同步好友列表
[self syncFriendList:^(NSMutableArray *friends, BOOL isSuccess) {
NSLog(@"%@",friends);
if (isSuccess) {
NSLog(@" success 发送通知");
[[NSNotificationCenter defaultCenter] postNotificationName:@"alreadyLogin"object:nil];
//登录成功,设置当前用户是XXX
[RCIMClient sharedRCIMClient].currentUserInfo = [[RCUserInfo alloc] initWithUserId:userinfo.userId name:userinfo.userName portrait:userinfo.photo phone:userinfo.phoneaddressInfo:userinfo.company realName:userinfo.realName];
[[RCDataManager shareManager] refreshBadgeValue];
} error:^(RCConnectErrorCode status) {
NSLog(@"status = %ld",(long)status);
} tokenIncorrect:^{
self.success = NO;
[MSUtil showTipsWithHUD:@"tokenIncorrect"];
} fail:^(NSError *error) {
NSLog(@"error %@",error);
self.success = NO;
//刷新角标
-(void)refreshBadgeValue{
dispatch_async(dispatch_get_main_queue(), ^{
int notReadMessage = [[UserInfoModel currentUserinfo].notReadMessage intValue];
NSInteger unreadMsgCount = (NSInteger)[[RCIMClient sharedRCIMClient] getUnreadCount:@[@(ConversationType_PRIVATE)]];
BaseNavigationController
*chatNav = [AppDelegate shareAppDelegate].rootTabbar.viewControllers[2];
if (unreadMsgCount == 0) {
chatNav.tabBarItem.badgeValue =
if (notReadMessage & 0) {
[UIApplication sharedApplication].applicationIconBadgeNumber = notReadM
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
chatNav.tabBarItem.badgeValue = [NSString stringWithFormat:@"%li",(long)unreadMsgCount];
if (notReadMessage & 0) {
[UIApplication sharedApplication].applicationIconBadgeNumber = unreadMsgCount + notReadM
[UIApplication sharedApplication].applicationIconBadgeNumber = unreadMsgC
//判断有没有这个好友
-(BOOL)hasTheFriendWithUserId:(NSString *)userId{
if ([AppDelegate shareAppDelegate].friendsArray.count) {
NSMutableArray *tempArray = [[NSMutableArray alloc]init];
for (RCUserInfo *aUserInfo in [AppDelegate shareAppDelegate].friendsArray) {
[tempArray addObject:aUserInfo.userId];
if ([tempArray containsObject:userId]) {
return YES;
return NO;
好,到此处,已经把融云的逻辑分离出来,并且登录了融云服务器。下一篇章该讲如何聊天,生成聊天列表,显示头像名字等。
持续关注,持续更新,谢谢。博主原创,不得转载,谢谢。
----------------------华丽丽的分割线------------------------
----------------------华丽丽的分割线------------------------
----------------------华丽丽的分割线------------------------
----------------------华丽丽的分割线------------------------
----------------------华丽丽的分割线------------------------
----------------------华丽丽的分割线------------------------
说说融云即时通讯SDK开发篇(三)
接着开发篇二的内容,我们已经把融云的逻辑分离出来,并且登录了融云服务器。此篇章讲如何聊天,生成聊天列表,显示头像名字等。
各个APP的界面UI设计的不同,每个开发者的需求也不同,但是万变不离其宗,我们抓住不变的地方,也就是共同之处。那么共同之处在哪里?就是我们要触发一个事件,比如点击了一个cell,或者点击了一个Button,又或者我们调用一个接口后台返回给我们一个人的信息,那么各个开发者触发这一系列的事件都是为了和某个人聊天,触发事件的时候,我们一定要拿到对应事件的这个人的信息(userInfo,包含很多字段,各个开发者需求不同,字段肯定就不同,但是userId一定有的,这个是相同之处)。举个栗子,比如进入一个tableView展示的列表,那么我们点击cell,动态的去取到每个cell对应到人的信息,然后就是在点击cell的事件里面配置我们ConversationViewController的属性了,那么代码在下面。
ConversationViewController *_conversationVC =
[[ConversationViewController alloc]init];
_conversationVC.conversationType = ConversationType_PRIVATE;
_conversationVC.targetId = [NSString
stringWithFormat:@"%@",model.data[@"id"]];
_conversationVC.userName = [NSString stringWithFormat:@"%@",model.data[@"agentTeamName"]];
_conversationVC.title = [NSString stringWithFormat:@"%@",model.data[@"realName"]];
[self.navigationController pushViewController:_conversationVC
animated:YES];
这里的ConversationViewController是我自己的VC继承RCConversationViewController,RCConversationViewController是用的融云写的UI,就是说这个RCConversationViewController里面的UI全部写好了,就很类似QQ聊天的界面,键盘啊,表情啊,发送图片啊,发送语音啊,一切的一切都搞定了。我们只需要配置一些属性,然后push就可以了。如果我们有自己的需求UI,我们也可以适当的在ConversationViewController基础上修改。(关于RCConversationViewController里面很多方法和属性,后续会慢慢涉及到,现在功能上没有涉及,所以先介绍到这里,后续讲解更高级的功能,就可以把更多的API给带出来,这样才有使用的场景,才更容易理解。)
那么每个app几乎都会有类似聊天列表的界面。描述一下,就是聊天之后会生成cell的,比如你点击了10个人的主页里面的聊天按钮,然后和这10个让聊过天,那么聊天列表就有10个cell自动生成(融云内部封装好的,理解为融云的机制,不要过分强求的分析是怎么回事。)。对应在融云这边的类就是RCConversationListViewController,注意,这个RCConversationListViewController我们也不能直接用啊,我们也要写一个自己的VC,那就是ChatViewController继承融云的RCConversationListViewController,这个ChatViewController就是我们自己写的聊天列表了,我们一旦有和某人聊天,那么自动会生成一个cell到这个vc里面,里面的机制大家不要去试图理解了,融云已经封装好了,一旦你和老王,前提你登录了融云服务器,并且老王是你的好友,那么你聊天后就可以回来这个vc看了,肯定出了一个cell,显示的是老王的名字和头像。那么下面我就把这个聊天列表VC的功能和API详细的介绍下,继续大尺度(没有人其他人愿意这么大尺度了,绝对的福利)的贴代码:
.h里面代码
#import "BaseViewController.h"
@interface ChatViewController :
RCConversationListViewController
@end 再看.m实现文件里面代码
import "ChatViewController.h"
import "RCCustomCell.h"
import "LoginViewController.h"
import "SpecialAgentViewController.h"
@interface ChatViewController (){ UIView *bgV UILabel
*desL UIImageView *defaultIV; UIView *firstShowV
UIImageView *headerIV; MBProgressHUD * UIImageView *aIV;
UILabel *aL }
@implementation ChatViewController
(void)dealloc { [[NSNotificationCenter defaultCenter]
removeObserver:self name:RCKitDispatchMessageNotification
object:nil]; }
(instancetype)init{ self = [super init]; if (self) {
[[UIApplication
sharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent];
[self setConversationAvatarStyle:RC_USER_AVATAR_CYCLE]; [self
setDisplayConversationTypes:@[@(ConversationType_PRIVATE)]];//这里是会话类型,我只用单聊,所以是ConversationType_PRIVATE,如果你的还有群聊,等,那么点进去,看到一个枚举,找到他们,需要什么类型就加什么类型
[RCIM sharedRCIM].receiveMessageDelegate =//这个是接收消息的监听代理
[RCIM sharedRCIM].connectionStatusDelegate =
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didReceiveMessageNotification:)name:RCKitDispatchMessageNotification
object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(removeLoginHud:) name:@"alreadyLogin"
object:nil]; hud = [[MBProgressHUD alloc]initWithView:self.view];
hud.square = YES; [self.view addSubview:hud];
(NSDate *)getCustomDateWithHour:(NSInteger)hour { //获取当前时间
NSDate *currentDate = [NSDate date]; NSCalendar *currentCalendar =
[[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar]; NSDateComponents
*currentComps = [[NSDateComponents alloc] init];
NSInteger unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit |
NSDayCalendarUnit | NSWeekdayCalendarUnit | NSHourCalendarUnit |
NSMinuteCalendarUnit | NSSecondCalendarU
currentComps = [currentCalendar components:unitFlags
fromDate:currentDate];
//设置当天的某个点 NSDateComponents *resultComps = [[NSDateComponents
alloc] init]; [resultComps setYear:[currentComps year]];
[resultComps setMonth:[currentComps month]]; [resultComps
setDay:[currentComps day]]; [resultComps setHour:hour];
NSCalendar *resultCalendar = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar]; return
[resultCalendar dateFromComponents:resultComps]; } // @param
message 收到的消息实体。 // @param nLeft 剩余消息数。 //
这里是融云的监听消息事件,这个代理会在每次接收到消息的时候走,所以我们可以在这个方法中处理逻辑了,我处理的逻辑有勿扰时段和头像的及时更新等等
-(void)onRCIMReceiveMessage:(RCMessage *)message left:(int)left
@property(nonatomic, assign) RCSentStatus sentS
@property(nonatomic, assign) long long sentT
@property(nonatomic, strong) NSString *
(instancetype)initWithType:(RCConversationType)conversationType
targetId:(NSString *)targetId
direction:(RCMessageDirection)messageDirection
messageId:(long)messageId content:(RCMessageContent *)
(instancetype)messageWithJSON:(NSDictionary *)jsonD
接着,别看晕喽,这个消息体是不是很多信息在里面,那么我需要的就是这个content字段,以及这个extra。我现在给出一个思路去解决好友头像更新之后,我不能马上看到好友的新头像问题。那么假设我和老王正在聊天,聊的很热乎,突然老王去设置里面更新了个头像,我还继续和老王聊天,我能看到老王的新头像吗?你猜猜,如果你深入的看了理论篇,并切理解了理论篇,你就很清楚的知道,我肯定是看不到老王的新头像的,为什么,因为我app启动的时候就把老王的信息保存到全局数组里面了,而且融云的聊天列表实际上是有缓存的,我猜测是用数据库存储的。所以我不从新启动app的情况下,我是不可能看到老王的新头像的。那么如何解决这个问题呢?
方案有两个:
第一个,谁更新了头像就要给他自己的所有好友发送通知消息,这个是融云官方给的方案,我感觉不是太好,这是简单粗暴的。比如老王有1000个好友,那么老王更新了头像,那么就要给这1000个好友发送一条通知信息,通知他的所有的好友,哎!注意了,赶紧更新我的最新信息,我已经更新信息了,那么1000个好友很多都不在线,你发了也是浪费流量,而且很多人,可能有999个人是不关心你更不更新头像的呀!老王你烦不烦,老是更新头像给我发消息。所以这个方法不是很好。
第二个,我觉得从消息入手,你老王更新了头像,你只要给我发送任何聊天消息我就能检测到你换了头像。怎么检测,那么我们来捋一捋这个逻辑,首先是老王和我在聊天,显示的是现在的头像,突然老王去换了头像,哎,我不知道啊,如果我给老王发消息,老王不理我我,我是拿不到老王的新头像的,那么一旦老王有回复我,就是老王有发一条任意类型的消息(消息有很多类型,语音消息,图片消息,地理位置消息等),我就从消息中获得老王的信息,信息中包含头像字段,那么就可以比较了,如果头像的url改变了,那么说明老王你更新了头像,我检测到了就马上刷新好友的最新信息并放全局数组中,并更新融云的缓存,这个缓存很重要,不更新缓存不行,不更新缓存就等于白做了,更新缓存的方法是
[[RCIM sharedRCIM] refreshUserInfoCache:theLastedInfo
withUserId:userInfoDic[@"sendUsersId"]];哇靠!这个方案好,让每条消息带有对方的信息,信息是个json的字符串,几乎可以忽略占用流量的大小,而且是最新的信息,不用给不聊天的好友发送通知信息了。好了,看下面代码。
我们用KVC拿到这个附加信息的字符串,是个json格式的字符串,一定要用KVC,不然你用.是拿不到的。Xcode后台调试,可以直接看到这些字段。那么我们需要在老王将要发送还没有发送的方法中去对消息做处理,做什么处理?就是加上老王的最新的信息啊!来看代码,者断代码是聊天界面的,不要搞混淆了(重写RCConversationViewController这个VC里面的方法)
(RCMessageContent *)willSendMessage:(RCMessageContent
*)messageCotent{
if ([RCIMClient sharedRCIMClient].currentUserInfo.userId)
{//如果登录了 NSDictionary *jsonDic = @{@"sendUsersId":[RCIMClient
sharedRCIMClient].currentUserInfo.userId,@"sendUsersName":self.userName,@"sendUsersPhoto":[UserInfoModel
currentUserinfo].photo}; NSError *parseError = NSData
*jsonData = [NSJSONSerialization dataWithJSONObject:jsonDic
options:NSJSONWritingPrettyPrinted
error:&parseError];
NSString *jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
if ([messageCotent isKindOfClass:[RCTextMessage class]]) {
RCTextMessage *textMessage = (RCTextMessage*)messageC
textMessage.extra = jsonS
}else if ([messageCotent isKindOfClass:[RCVoiceMessage class]]) {
RCVoiceMessage *voiceMessage = (RCVoiceMessage*)messageC
voiceMessage.extra = jsonS
}else if ([messageCotent isKindOfClass:[RCImageMessage class]]) {
RCImageMessage *imageMessage = (RCImageMessage*)messageC
imageMessage.extra = jsonS
return messageC }
以上的代码很简单,就是发送消息的前面,还没发送的时候,把自己(这时候就是老王自己)的信息,包装成JSONDic,然后在转成NSString,赋值给extra,这样对方就可以拿到我的信息了,就可以知道我的头像有没有更新了。
以下的代码就是解析JSON的过程,和上面交相呼应啊。对不对! NSString *extraString = [[message
valueForKey:@"content"] valueForKey:@"extra"];
if (extraString) { NSData *jsonData = [extraString
dataUsingEncoding:NSUTF8StringEncoding]; NSError * if
(jsonData) { 拿到字符串,转换称Data,然后转成我们经常用的字典。 NSDictionary *userInfoDic
= [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers error:&err];
NSLog(@"FFFFF%@",userInfoDic); if (userInfoDic) {
用RCDataManager的API直接拿到发送者老王的userInfo,然后下面就是比较头像的url是否一样了。
RCUserInfo *senderInfo = [[RCDataManager shareManager]
currentUserInfoWithUserId:userInfoDic[@"sendUsersId"]];
RCUserInfo *theLastedInfo = [[RCUserInfo alloc]initWithUserId:userInfoDic[@"sendUsersId"] name:userInfoDic[@"sendUsersName"] portrait:userInfoDic[@"sendUsersPhoto"] phone:senderInfo.phone addressInfo:senderInfo.addressInfo realName:senderInfo.realName];
if ([userInfoDic[@"sendUsersPhoto"] isEqualToString:senderInfo.portraitUri]) {
这里更新好友的最新列表
[[RCDataManager shareManager] syncFriendList:^(NSMutableArray *friends, BOOL isSuccess) {
if (isSuccess) {
这里更新融云缓存,不更新缓存是不行的,我已经实验过了
[[RCIM sharedRCIM] refreshUserInfoCache:theLastedInfo withUserId:userInfoDic[@"sendUsersId"]];
[[RCDataManager shareManager] syncFriendList:^(NSMutableArray *friends, BOOL isSuccess) {
} JSON字典就是下面的这个样子,iOSer看了就懂了 //
{"sendUsersId":"85","sendUsersName":"快乐","sendUsersPhoto":"http://weixintest.ihk.cn/ihkwx_upload/userPhoto/-6.jpg
NSString *notTroubleStr = [TheUserDefaults
objectForKey:@"setSpareTimeYES"];
下面处理的是勿扰时段,就是何时有声音,何时没声音,何时有震动,何时无震动,如果app设置里面没用这些设置项,那么请忽略 if
([notTroubleStr isEqualToString:@"setSpareTimeNO"]) {
[self RemindSwitch];
}else if ([notTroubleStr
isEqualToString:@"setSpareTimeYES"]){
NSString *timeDuring = [TheUserDefaults objectForKey:@"spareTimeStr"];//11位时间
21:00-09:00
NSString *fromHourStr = [timeDuring substringToIndex:2];
NSString *toHourStr
= [timeDuring substringWithRange:NSMakeRange(6,2)];
NSInteger fromHour=0;
NSInteger toHour =0;
if ([fromHourStr hasPrefix:@"0"]) {
fromHour = [[fromHourStr substringWithRange:NSMakeRange(1, 1)] integerValue];
fromHour = [fromHourStr integerValue];
if ([toHourStr hasPrefix:@"0"]) {
toHour = [[toHourStr substringWithRange:NSMakeRange(1, 1)] integerValue];
toHour = [toHourStr integerValue];
NSLog(@"fromHour =%ld ,toHour = %ld",fromHour,toHour);
NSString *nowString
= [MSUtil gethhmmss];//01:28:02
nowString = [nowString substringToIndex:2];
if ([nowString hasPrefix:@"0"]) {
nowString = [nowString substringFromIndex:0];
NSLog(@"%@",nowString);
// NSDate *nowDate = [self getCustomDateWithHour:fromHour];
if (fromHour&toHour) {//21--9跨天
if ([nowString integerValue]&=fromHour||[nowString integerValue]&=toHour) {
[RCIM sharedRCIM].disableMessageAlertSound = YES;//关闭声音
[self RemindSwitch];
}else if(fromHour==toHour){//8--8相同
if ([nowString integerValue]==fromHour) {
[RCIM sharedRCIM].disableMessageAlertSound = YES;//关闭声音
[self RemindSwitch];
}else if(fromHour=fromHour&&[nowString integerValue]&=toHour) {
[RCIM sharedRCIM].disableMessageAlertSound = YES;//关闭声音
[self RemindSwitch];
if (![[RCDataManager shareManager]
hasTheFriendWithUserId:message.senderUserId]) {
//检查message.senderUserId这个人在不在我好友里面,如果没有在,测网络刷新最新的好友列表
[[RCDataManager shareManager] syncFriendList:^(NSMutableArray
*friends,BOOL isSuccess) { [[RCDataManager shareManager]
getUserInfoWithUserId:message.senderUserId completion:^(RCUserInfo
*userInfo) { NSLog(@"名字 = %@ ID =
%@",userInfo.name,userInfo.userId); }]; }]; } [[RCDataManager
shareManager] getUserInfoWithUserId:message.senderUserId
completion:^(RCUserInfo *userInfo) { NSLog(@"名字 = %@ ID =
%@",userInfo.name,userInfo.userId); }]; [self
setDisplayConversationTypeArray:@[@(ConversationType_PRIVATE)]];
[self refreshConversationTableViewIfNeeded]; [[RCDataManager
shareManager] refreshBadgeValue]; }
(void)RemindSwitch {
NSString *setShake = [TheUserDefaults
objectForKey:@"setShakeYES"]; NSString *setSound=[[NSUserDefaults
standardUserDefaults]objectForKey:@"setSoundYES"];
if (setShake && [setShake
isEqualToString:@"setShakeYES"]) {
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);//震动 }
if(setSound && [setSound
isEqualToString:@"setSoundYES"]) {//有声音,这个方法可以设置融云接收消息时候的声音的有和无
[RCIM sharedRCIM].disableMessageAlertSound = NO; } else{//无声音 [RCIM
sharedRCIM].disableMessageAlertSound = YES; } }
pragma mark - RCIMConnectionStatusDelegate
这个是检测连接connect状态的代理,踢人的功能可以做在这里,逻辑是,staue=ConnectionStatus_KICKED_OFFLINE_BY_OTHER_CLIENT,就是被T了,然后弹出提示框,提示用户“您的帐号已在别的设备上登录,\n您被迫下线!”,然后点击确定就要调用登出的接口,处理登出的逻辑了,每位开发者自己处理登出的逻辑,登出的逻辑可以单独抽离出来。
(void)onRCIMConnectionStatusChanged:(RCConnectionStatus)status
{ NSLog(@"RCConnectionStatus = %ld",(long)status); if (status ==
ConnectionStatus_KICKED_OFFLINE_BY_OTHER_CLIENT) { UIAlertView
*alert = [[UIAlertView alloc] initWithTitle:nil
message:@"您的帐号已在别的设备上登录,\n您被迫下线!" delegate:self
cancelButtonTitle:@"知道了" otherButtonTitles:nil, nil]; [alert show];
-(id)initWithCoder:(NSCoder *)aDecoder{ self =[super
initWithCoder:aDecoder]; if (self) { //设置要显示的会话类型 [self
setDisplayConversationTypes:@[@(ConversationType_PRIVATE)]]; [self
setConversationAvatarStyle:1]; } }
-(void)callSpecialAgent:(UITapGestureRecognizer *)sender{ if
(firstShowView) { [firstShowView removeFromSuperview];
firstShowView =
SpecialAgentViewController *saVC = [[SpecialAgentViewController alloc]init];
[self.navigationController pushViewController:saVC animated:YES];
pragma mark
pragma mark viewDidLoad
(void)viewDidLoad { [super viewDidLoad];
self.edgesForExtendedLayout = UIRectEdgeN
self.view.backgroundColor = [UIColor whiteColor]; //设置title UIView
*netWorkView = (UIView *)self.networkIndicatorV
netWorkView.frame = CGRectZ netWorkView.hidden = YES;
[netWorkView removeFromSuperview];
self.navigationItem.title=KTitle_isShowAllSame?KTitle_SameStr:
@"合记买楼";
//布局 UIImage *headerImage = [UIImage imageNamed:@"hjtgdk.jpg"];
CGFloat radi = headerImage.size.width/headerImage.size.
headerIV =[[UIImageView alloc]initWithFrame:CGRectMake(0, 0,
self.conversationListTableView.frame.size.width,
self.conversationListTableView.frame.size.width/(radi))];
headerIV.userInteractionEnabled = YES; headerIV.image =
headerI NSLog(@"%@",self.conversationListTableView);
NSLog(@"%@",headerIV); [self.view addSubview:headerIV];
self.conversationListTableView.frame =
CGRectMake(self.conversationListTableView.frame.origin.x,
headerIV.frame.origin.y+headerIV.frame.size.height,
self.conversationListTableView.frame.size.width,
self.conversationListTableView.frame.size.height-headerIV.frame.size.height);
self.conversationListTableView.rowHeight = kCellH
self.conversationListTableView.separatorStyle =
UITableViewCellSeparatorStyleSingleL UITapGestureRecognizer
*tap = [[UITapGestureRecognizer alloc]initWithTarget:self
action:@selector(callSpecialAgent:)]; [headerIV
addGestureRecognizer:tap]; //设置tableView样式
self.conversationListTableView.backgroundColor = [MSUtil
colorWithHexString:@"#e5e5e5"]; //
self.conversationListTableView.backgroundColor = [UIColor
whiteColor]; self.conversationListTableView.separatorStyle =
UITableViewCellSeparatorStyleN
if ([RCIM sharedRCIM].currentUserInfo.userId) { if
(self.conversationListDataSource.count==0) {
self.conversationListTableView.tableFooterView = [UIView new];
}else{ UIView *afooter = [[UIView alloc]initWithFrame:CGRectMake(0,
0, self.conversationListTableView.frame.size.width, 0.5)];
afooter.backgroundColor = [UIColor lightGrayColor];
self.conversationListTableView.tableFooterView = } }else{
self.conversationListTableView.tableFooterView = [UIView new]; } if
([TheUserDefaults boolForKey:@"everShow"]==NO) { firstShowView =
[[UIView alloc]initWithFrame:CGRectMake(0, 0, kScreenWidth,
kScreenHeight-kNavbarHeight-kTabBarHeight)];
firstShowView.backgroundColor = [UIColor colorWithWhite:0.2
alpha:0.95]; [self.view addSubview:firstShowView]; [self.view
bringSubviewToFront:firstShowView]; [TheUserDefaults setBool:YES
forKey:@"everShow"]; [TheUserDefaults synchronize];
UIImage *image = [UIImage imageNamed:@"hjtgdc"];
float radio = image.size.width/image.size.
UIImageView *centerIV = [[UIImageView alloc]initWithFrame:CGRectMake(0, firstShowView.frame.size.height-((kScreenWidth-2*30)/radio)/2, kScreenWidth-2*30, (kScreenWidth-2*30)/radio)];
centerIV.image =
centerIV.userInteractionEnabled = YES;
centerIV.center = firstShowView.
[firstShowView addSubview:centerIV];
UIButton *Xbtn = [UIButton buttonWithType:UIButtonTypeCustom];
Xbtn.frame = CGRectMake(centerIV.frame.size.width-50+5, -5, 50, 50);
[Xbtn setImage:[UIImage imageNamed:@"chatDelete"] forState:UIControlStateNormal];
[Xbtn setImage:[UIImage imageNamed:@"chatDelete"] forState:UIControlStateSelected];
[Xbtn addTarget:self action:@selector(removeShowView:) forControlEvents:UIControlEventTouchUpInside];
[centerIV addSubview:Xbtn];
[centerIV bringSubviewToFront:Xbtn];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(callSpecialAgent:)];
[centerIV addGestureRecognizer:tap];
} } -(void)removeShowView:(UIButton *)sender{ if (firstShowView)
{ [firstShowView removeFromSuperview]; firstShowView = } [self
showEmptyConversationView]; }
(void)viewWillAppear:(BOOL)animated { [super
viewWillAppear:animated]; [[UIApplication
sharedApplication]setStatusBarStyle:UIStatusBarStyleLightContent];
[self.navigationController.navigationBar
wm_setBackgroundColor:kColor_Theme]; [self
refreshConversationTableViewIfNeeded]; [self
resetConversationListBackgroundViewIfNeeded]; if ([RCIMClient
sharedRCIMClient].currentUserInfo.userId) {//登录 [[RCDataManager
shareManager] refreshBadgeValue]; [self
setDisplayConversationTypeArray:@[@(ConversationType_PRIVATE)]];
aIV.hidden = NO;
aLabel.hidden = NO;
[bgView sendSubviewToBack:aIV];
[bgView sendSubviewToBack:aLabel];
[hud removeFromSuperview];
}else{//没登录 BaseNavigationController *chatNav =[AppDelegate
shareAppDelegate].rootTabbar.viewControllers[2];
chatNav.tabBarItem.badgeValue = [self
setDisplayConversationTypeArray:nil];
if (self.conversationListDataSource.count) {//已登出,有数据
// [hud show:YES]; aIV.hidden = YES; aLabel.hidden = YES;
[bgView sendSubviewToBack:aIV]; [bgView sendSubviewToBack:aLabel];
[hud removeFromSuperview];
}else{//已登出,没数据
[hud show:NO];
aIV.hidden = NO;
aLabel.hidden = NO;
[hud removeFromSuperview];
dispatch_async(dispatch_get_main_queue(), ^{
[self refreshConversationTableViewIfNeeded];
[self showEmptyConversationView];
} [self showEmptyConversationView];
} -(void)removeLoginHud:(NSNotification *)obj{ NSLog(@"收到通知");
if (hud) { dispatch_async(dispatch_get_main_queue(), ^{
[self setDisplayConversationTypeArray:@[@(ConversationType_PRIVATE)]];
[self performSelector:@selector(refershTable) withObject:nil afterDelay:0.5];
} -(void)refershTable{ dispatch_async(dispatch_get_main_queue(),
^{ [self.conversationListTableView reloadData]; [self
performSelector:@selector(refershTableIfNeeded) withObject:nil
afterDelay:0.5]; }); } -(void)refershTableIfNeeded{ [hud hide:YES];
[hud removeFromSuperview]; aIV.hidden = NO; aLabel.hidden = NO;
dispatch_async(dispatch_get_main_queue(), ^{ [self
refreshConversationTableViewIfNeeded]; [self
showEmptyConversationView]; });
} -(void)viewWillDisappear:(BOOL)animated{ [super
viewWillDisappear:animated]; //show self.navigationItem.title =
pragma mark override
//通知更新未读消息数目,用于显示未读消息,当收到会话消息的时候,会触发一次。
(void)notifyUpdateUnreadMessageCount{ [[RCDataManager
shareManager] refreshBadgeValue]; }
-(void)loginorRegister:(UIButton *)sender{
[self.navigationController pushViewController:[LoginViewController
new] animated:YES]; }
//重写方法,设置会话列表emptyConversationView的视图。//无聊天cell的时候一般会显示一个默认的图片或者加一些button或者一些imageView啊等等,那么逻辑就是在下面的这个方法中处理,我的方法可能不是最好的,如果有同学有好方法欢迎找我交流,加我的iOS技术交流群,谢谢。
(void)showEmptyConversationView{ UsersType type = [MSUtil
checkUserType];
if (firstShowView) { } if (bgView==nil) { UIImage *
nochatDataImage = [UIImage imageNamed:@"nochatData"]; bgView =
[[UIView alloc]initWithFrame:CGRectMake(0,
(kScreenHeight-kNavbarHeight-headerIV.frame.size.height-kTabBarHeight)/2-nochatDataImage.size.height/2,
kScreenWidth, nochatDataImage.size.height+kNavbarHeight)];
bgView.hidden = NO; bgView.center =
self.conversationListTableView. aIV = [[UIImageView
alloc]initWithFrame:CGRectMake(kScreenWidth/2-nochatDataImage.size.width/2,
0, nochatDataImage.size.width, nochatDataImage.size.height)];
aIV.image = nochatDataI [bgView addSubview:aIV];
aLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, aIV.frame.origin.y+aIV.frame.size.height, bgView.frame.size.width, kNavbarHeight)];
aLabel.text = @"暂无聊天数据";
aLabel.textColor = kFontColor_999999;
aLabel.textAlignment = NSTextAlignmentC
[bgView addSubview:aLabel];
// UserInfoModel *userinfo = [UserInfoModel currentUserinfo]; //
(userinfo.login==YES&&![userinfo.userId
isEqualToString:@""]&&![RCIMClient
sharedRCIMClient].currentUserInfo.userId) { //// aIV.hidden = YES;
// aLabel.hidden = YES; //// }else{ // aIV.hidden = NO; //
aLabel.hidden = NO; // }
if ([RCIM sharedRCIM].currentUserInfo.userId) {//登录了
if (type==UsersTypeYouke) {
}else if (type==UsersTypeCustomer){
self.emptyConversationView = bgV
if (self.conversationListDataSource.count) {//有数据
}else{//没数据
self.emptyConversationView = bgV
[hud show:NO];
aIV.hidden = NO;
aLabel.hidden = NO;
[hud removeFromSuperview];
}else if (type==UsersTypeSales){
if (self.conversationListDataSource.count) {//有数据
}else{//没数据
self.emptyConversationView = bgV
[hud show:NO];
aIV.hidden = NO;
aLabel.hidden = NO;
[hud removeFromSuperview];
self.emptyConversationView = bgV
}else{//没登录
self.emptyConversationView = bgV
if (self.conversationListDataSource.count) {//已登出,有数据
aIV.hidden = YES;
aLabel.hidden = YES;
[bgView sendSubviewToBack:aIV];
[bgView sendSubviewToBack:aLabel];
[self.view bringSubviewToFront:self.conversationListTableView];
[hud removeFromSuperview];
}else{//已登出,没数据
self.emptyConversationView = bgV
[hud show:NO];
aIV.hidden = NO;
aLabel.hidden = NO;
[bgView bringSubviewToFront:aIV];
[bgView bringSubviewToFront:aLabel];
[hud removeFromSuperview];
if ([self.view.subviews containsObject:bgView]) {
[self.view addSubview:self.emptyConversationView];
//插入自定义会话model -(NSMutableArray
*)willReloadTableData:(NSMutableArray *)dataSource{ for (int i=0;
pragma mark
pragma mark onSelectedTableRow
(void)onSelectedTableRow:(RCConversationModelType)conversationModelType
conversationModel:(RCConversationModel *)model
atIndexPath:(NSIndexPath *)indexPath{ ConversationViewController
*_conversationVC = [[ConversationViewController alloc]init];
_conversationVC.conversationType = model.conversationT
_conversationVC.targetId = model.targetId; for (RCUserInfo
*userInfo in [AppDelegate shareAppDelegate].friendsArray) { if
([model.targetId isEqualToString:userInfo.userId]) {
_conversationVC.userName = userInfo. _conversationVC.title
=[userInfo.realName isEqualToString:@""]?[NSString
stringWithFormat:@"%@",userInfo.name]:[NSString
stringWithFormat:@"%@",userInfo.realNa}

我要回帖

更多关于 刘美频调到哪去了 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信