CYLChatKit 2.1.10.1

CYLChatKit 2.1.10.1

陈义龙 维护。



 
依赖项
AVOSCloud~> 11.1.2
AVOSCloudIM~> 11.1.2
MJRefresh~> 3.1.15.1
Masonry~> 1.1.0
SDWebImage~> 4.4.1
FMDB~> 2.6.2
pop~> 1.0.9
UITableView+FDTemplateLayoutCell~> 1.5.beta
FDStackView~> 1.0
DACircularProgress~> 2.3.1
MLLabel~> 1.10.5
CYLDeallocBlockExecutor~> 1.2.0
MBProgressHUD~> 1.1.0
 

CYLChatKit 2.1.10.1

  • 作者
  • 伊隆·陈

ChatKit 快速入门 · iOS

如有任何问题,请在 issue 中提出,也欢迎提出 PR。

本篇为快速入门,更多自定义需求请参考以下页面:

  1. 《ChatKit 自定义样式》
  2. 《ChatKit 自定义业务》
  3. 《集成红包功能》

导航

  1. 简介
  2. 获取项目
  3. 集成效果
  4. 项目结构
  5. 使用方法
    1. CocoaPods 导入
    2. 胶水函数快速集成
    3. 最近联系人界面
    4. 从最近联系人进入聊天界面
    5. 聊天界面
    6. 响应聊天界面的操作
    7. 手动集成
  6. 常见问题

简介

ChatKit 是一个免费开源的 UI 聊天组件,自带云服务器,支持推送,具备消息漫游和永久存储特性。它是基于 LeanCloud 的 IM 实时通信服务 LeanMessage 开发的,采用 Protobuf 协议来传输消息。ChatKit 有助于开发者快速集成 IM 服务,轻松实现聊天功能,提供完全自由的授权协议,支持二次开发。其显著特点是将一些常用的聊天功能与 UI 搭配起来提供给开发者。

获取项目

git clone --depth=1 https://github.com/ChenYilong/CYLChatKit

集成效果

从大量的使用场景来看,「最近联系人列表」和「聊天界面」这两个页面是开发者最常使用的,同时也是比较难处理的。

最近联系人页面实现的难点在于:

  • 要根据最近打开的聊天窗口排序联系人列表;
  • 对每一个最近聊天人/组需要显示最新的一条消息及时间;
  • 需要实时更新未读消息的计数;

而聊天页面的实现难点则在于:

  • 消息种类繁多,要有比较好的用户体验,界面以及异步处理方面有大量的开发工作;
  • 音视频消息的录制和发送,需要对系统以及 LeanCloud 实时通信 API 比较熟悉;
  • 推、拉展示本对话中的最新消息,需要对 LeanCloud 实时通信接口比较熟悉;
最近联系人 语音消息,根据语音长度调整宽度 图片消息,尺寸自适应
enter image description here enter image description here enter image description here
地理位置消息 失败消息本地缓存,可重发 上传图片,进度条提示
enter image description here enter image description here enter image description here
图片消息支持多图联播,支持多种分享 文本消息支持图文混排 文本消息支持双击全屏展示
enter image description here enter image description here enter image description here

项目结构

├── ChatKit  #核心库文件夹
│   ├── LCChatKit.h  # 这是整个库的入口,也是中枢,相当于”组件化方案“中的 Mediator。
│   ├── LCChatKit.m
│   └── Class
│       ├── Model
│       ├── Module
│       │   ├── Base
│       │   ├── Conversation
│       │   │   ├── Controller
│       │   │   ├── Model
│       │   │   ├── Tool
│       │   │   └── View
│       │   └── ConversationList
│       │       ├── Controller
│       │       ├── Model
│       │       └── View
│       ├── Resources  # 资源文件,如图片、音频等
│       ├── Tool
│       │   ├── Service
│       │   └── Vendor
│       └── View
└── ChatKit-OC  # Demo演示
    ├── ChatKit-OC.xcodeproj
    └── Example
        └── LCChatKitExample.h  #这是Demo演示的入口类,这个类中提供了很多胶水函数,可完成初步的集成
        └── LCChatKitExample.m
            ├── Model
            ├── Module
            │   ├── ContactList
            │   │   ├── Controller
            │   │   ├── Tool
            │   │   └── View
            │   ├── Login
            │   │   ├── Controller
            │   │   ├── Model
            │   │   └── View
            │   ├── Main
            │   │   ├── Controller
            │   │   └── View
            │   └── Other

从上面可以看出,ChatKit-OC 项目包分为两个部分:

  • ChatKit 是库的核心库文件夹。
  • ChatKit-OC 为Demo 演示部分,其中 LCChatKitExample 这个类提供了很多胶水函数,可完成初步的集成。

使用方法

ChatKit 支持以下两种方式导入到您的项目中:

  1. 通过 CocoaPods 管理依赖
  2. 手动集成并管理依赖,参考下文的手动集成部分。

这里推荐通过 CocoaPods 管理依赖

CocoaPods 是目前最流行的 Cocoa 项目库依赖管理工具之一,考虑到便捷与项目的可维护性,我们更推荐您使用 CocoaPods 导入并管理 SDK。

CocoaPods 导入

  1. CocoaPods 安装

如果您的机器上已经安装了 CocoaPods,直接进入下一步即可。

如果您的网络已经翻墙,在终端中运行如下命令直接安装:

   sudo gem install cocoapods

如果您的网络不能翻墙,可以通过淘宝的 RubyGems 镜像进行安装。

在终端依次运行以下命令:

   gem sources --add https://ruby.taobao.org/ --remove https://rubygems.org.cn/
   sudo gem install cocoapods
  1. 查询 CocoaPods 源中的本库

在终端中运行以下命令:

   pod search CYLChatKit

这里注意,这个命令搜索的是本机上的最新版本,并没有联网查询。如果运行以上命令,没有搜到或者搜不到最新版本,您可以运行以下命令,更新一下您本地的 CocoaPods 源列表。

   pod repo update
  1. 使用 CocoaPods 导入

打开终端,进入到您的工程目录,执行以下命令,会自动生成一个 Podfile 文件。

   pod init

然后使用 CocoaPods 进行安装。如果尚未安装 CocoaPods,运行以下命令进行安装:

   gem install cocoapods

打开 Podfile,在您项目的 target 下加入以下内容。(在此以 v2.1.1 版本为例)

在文件 Podfile 中加入以下内容:

   pod 'CYLChatKit', '2.1.1'

然后在终端中运行以下命令:

   pod install

或者这个命令:

   # 禁止升级 CocoaPods 的 spec 仓库,否则会卡在 Analyzing dependencies,非常慢
   pod update --verbose --no-repo-update

如果提示找不到库,则可去掉 --no-repo-update

完成后,CocoaPods 会在您的工程根目录下生成一个 .xcworkspace 文件。您需要通过此文件打开您的工程,而不是之前的 .xcodeproj

然后在需要的地方导入 ChatKit:

   #import <CYLChatKit/LCChatKit.h>

CocoaPods 使用说明

指定 SDK 版本

CocoaPods 中,有几种设置 SDK 版本的方法。如:

>= 0.8.5 会根据您本地的 CocoaPods 源列表,导入不低于 0.8.5 版本的 SDK。 ~> 0.8.5 会根据您本地的 CocoaPods 源列表,介于 0.7.X~0.8.5 之前版本的 SDK。 我们建议您锁定版本,便于团队开发。如,指定 0.8.5 版本。

pod 'CYLChatKit', '~> 2.1.8'
  • 升级本地 CocoaPods 源

`CocoaPods 有一个中心化的源,默认本地会缓存 CocoaPods 源服务器上的所有 SDK 版本。

如果搜索的时候没有搜到或者搜不到最新版本,可以执行以下命令更新一下本地的缓存。

pod repo update
  • 升级工程的Pod版本

更新您工程目录中 Podfile 指定版本后,在终端中执行以下命令。

pod update
  • 清除 Cocoapods 本地缓存

在特殊情况下,由于网络或其他原因,通过 CocoaPods 下载的文件可能会有问题。

这时您可以删除 CocoaPods 的缓存(~/Library/Caches/CocoaPods/Pods/Release 目录),然后再次导入即可。

  • 查看当前使用的 SDK 版本

您可以在 Podfile.lock 文件中看到您工程中使用的 SDK 版本。

有关 CocoaPods 的更多信息,请参阅 CocoaPods 文档

使用 ChatKit 有几个关键步骤:

  1. -[AppDelegate application:didFinishLaunchingWithOptions:] 方法中调用 -[LCChatKit setAppId:appKey:] 来启用 LeanCloud 服务。您需要到 LeanCloud(原名 AVOS 申请一个 AppId 和一个 AppKey,可以在控制台创建应用,然后用这些值替换 Demo 中的 AppId 和 AppKey。
  2. 调用 -[LCChatKit sharedInstance] 来初始化一个单例对象。为了让这个库更容易上手,避免引入过多的公开类和概念,我们采用了设计模式中的「门面模式」,将使用 ChatKit 库时所需的所有方法都放在了 LCChatKit 这个类中。它是一个 Mediator,是整个库的入口。如果不特别说明,以下所说的「调用 API」,调用方都是 -[LCChatKit sharedInstance] 。示意图如下:

  1. 实现 -[[LCChatKit sharedInstance] setFetchProfilesBlock:],设置用户体系,其中要实现根据 userId 获取一个 User 对象的逻辑。当 ChatKit 需要使用用户信息时,它会调用您设置的这个逻辑。更具体的设置方法请参考: 《ChatKit 自定义业务-设置单聊用户的头像和昵称》LCCKUserSystemService.h 文件中给出了例子,演示了如何集成 LeanCloud 原生的用户系统 AVUser
  2. 如果您实现了 -[[LCChatKit sharedInstance] setGenerateSignatureBlock:] 方法,则 ChatKit 会自动为以下行为添加签名:open(开启聊天)、start(创建对话)、kick(踢人)、invite(邀请)。如果不实现该方法,则不会自动添加签名。
  3. 调用 -[[LCChatKit sharedInstance] openWithClientId:callback:] 来启用 LeanCloud 的 IM 服务 LeanMessage 并开始聊天。请确保在 open 操作之前已经实现了 -[[LCChatKit sharedInstance] setFetchProfilesBlock:],否则 ChatKit 会抛出异常并提示。
  4. 调用 -[[LCChatKit sharedInstance] closeWithCallback:] 来关闭 LeanCloud 的 IM 服务并结束聊天。

下面将按步骤进行详细讲解。

胶水函数快速集成

ChatKit 提供了一个快速集成的演示类 LCChatKitExample,路径如下:

 ├── ChatKit  #核心库文件夹
 └──  ChatKit-OC  # Demo演示
    ├── ChatKit-OC.xcodeproj
    └── Example
        └── LCChatKitExample.h  # 这是 Demo 演示的入口类,这个类中提供了很多胶水函数,可完成初步的集成。
        └── LCChatKitExample.m

使用 LCChatKitExample 提供的函数即可完成从程序启动到登录再到登出的完整流程,您可以复制 LCChatKitExample 里的代码,或者直接将 LCChatKitExample 拖入到项目中。

  • -[AppDelegate didFinishLaunchingWithOptions:] 等函数中调用以下几个基础的入口胶水函数,可以完成初步集成。您也可以参考胶水函数中的代码,自行编写逻辑。胶水函数的调用时机可以通过函数名称确定。
  • 胶水代码中包含了特别设置的 #warning,请仔细阅读这些警告注释,根据实际情况调整代码以满足您的需求。
/*!
 *  入口胶水函数:初始化入口函数
 *
 *  程序完成启动,在 appdelegate 中的 `-[AppDelegate didFinishLaunchingWithOptions:]` 一开始的地方调用.
 */
+ (void)invokeThisMethodInDidFinishLaunching;

/*!
 * Invoke this method in `-[AppDelegate appDelegate:didRegisterForRemoteNotificationsWithDeviceToken:]`.
 */
+ (void)invokeThisMethodInDidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;

/*!
 * invoke This Method In `-[AppDelegate application:didReceiveRemoteNotification:]`
 */
+ (void)invokeThisMethodInApplication:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo ;

/*!
 *  入口胶水函数:登入入口函数
 *
 *  用户即将退出登录时调用
 */
+ (void)invokeThisMethodAfterLoginSuccessWithClientId:(NSString *)clientId success:(LCCKVoidBlock)success failed:(LCCKErrorBlock)failed;

/*!
 *  入口胶水函数:登出入口函数
 *
 *  用户即将退出登录时调用
 */
+ (void)invokeThisMethodBeforeLogoutSuccess:(LCCKVoidBlock)success failed:(LCCKErrorBlock)failed;
+ (void)invokeThisMethodInApplicationWillResignActive:(UIApplication *)application;
+ (void)invokeThisMethodInApplicationWillTerminate:(UIApplication *)application;

最近联系人界面

主流的社交聊天软件,例如微信和 QQ 都会将最近联系人界面作为登录后的首页,这显示了其重要性。因此,我们在 ChatKit 也提供了对话列表 LCIMConversationListController 页面,其初始化方法非常简单:

LCCKConversationListViewController *firstViewController = [[LCCKConversationListViewController alloc] init];

由于最近联系人的所有信息都由 ChatKit 内部维护,因此不需要传入额外数据,直接展示这个 ViewController 即可。最近联系人界面的数据依赖于本地数据库。这些数据会在聊天过程中自动更新,您无需进行繁琐的数据库操作。

聊天界面

ChatKit 中的对话是一个 `AVIMConversation` 对象,LeanMessage 用它来管理对话成员、发送消息,不区分群聊、单聊。Demo 中采用判断对话人数的方式来区分群聊、单聊。

聊天界面有两种初始化方式:

// 用于单聊,默认会创建一个只包含两个成员的 unique 对话(如果已经存在则直接进入,不会重复创建)
LCCKConversationViewController *conversationViewController = [[LCCKConversationViewController alloc] initWithPeerId:peerId];
// 单聊或群聊,用于已经获取到一个对话基本信息的场合。
LCCKConversationViewController *conversationViewController = [[LCCKConversationViewController alloc] initWithConversationId:conversationId];

注意,通过 peerId 初始化时,如果内部实现中没有找到恰好包含这两个成员的 unique 对话,则会先创建一个 unique 对话,因此调用该方法时可能会在 _Conversation 表中自动增加一条记录。同理,通过 conversationId 初始化群聊时,如果没有对话成员会先添加当前用户到对话中,然后开启群聊。

通过最近联系人进入聊天界面

根据上述步骤,我们可以非常方便地打开最近联系人页面。但是我们会发现,点击其中的某个联系人/聊天群组,我们并不能直接进入聊天界面。若要实现这一点,我们需要给 LCChatKit 设置事件响应函数,示例代码如下:

[[LCChatKit sharedInstance] setDidSelectConversationsListCellBlock:^(NSIndexPath *indexPath, AVIMConversation *conversation, LCCKConversationListViewController *controller) {
    NSLog(@"conversation selected");
    LCCKConversationViewController *conversationVC = [[LCCKConversationViewController alloc] initWithConversationId:conversation.conversationId];
    [controller.navigationController pushViewController:conversationVC animated:YES];
}];

对于联系人列表页面,可以使用 [LCChatKit sharedInstance] 来调用以下四种操作接口:

/*!
 *  选中某个对话后的回调 (比较常见的需求)
 *  @param conversation 被选中的对话
 */
typedef void(^LCCKConversationsListDidSelectItemBlock)(NSIndexPath *indexPath, AVIMConversation *conversation, LCCKConversationListViewController *controller);
/*!
 *  设置选中某个对话后的回调
 */
- (void)setDidSelectConversationsListCellBlock:(LCCKConversationsListDidSelectItemBlock)didSelectItemBlock;

/*!
 *  删除某个对话后的回调 (一般不需要做处理)
 *  @param conversation 被选中的对话
 */
typedef void(^LCCKConversationsListDidDeleteItemBlock)(NSIndexPath *indexPath, AVIMConversation *conversation, LCCKConversationListViewController *controller);
/*!
 *  设置删除某个对话后的回调
 */
- (void)setDidDeleteConversationsListCellBlock:(LCCKConversationsListDidDeleteItemBlock)didDeleteItemBlock;

/*!
 *  对话左滑菜单设置block (最近联系人页面有复杂的手势操作时,可以通过这里扩展实现)
 *  @return  需要显示的菜单数组
 *  @param conversation, 对话
 *  @param editActions, 默认的菜单数组,成员为 UITableViewRowAction 类型
 */
typedef NSArray *(^LCCKConversationEditActionsBlock)(NSIndexPath *indexPath, NSArray<UITableViewRowAction *> *editActions, AVIMConversation *conversation, LCCKConversationListViewController *controller);
/*!
 *  可以通过这个block设置对话列表中每个对话的左滑菜单,这个是同步调用的,需要尽快返回,否则会卡住UI
 */
- (void)setConversationEditActionBlock:(LCCKConversationEditActionsBlock)conversationEditActionBlock;

响应聊天界面的几类操作

由于有 ChatKit 的帮助,聊天界面的初始化和展示非常简单,但在交互上还有很多地方需要自定义扩展。

  • 无法创建内部异常对话

如果通过 peerId 打开对话,或者通过 conversationId 打开对话时,网络出现问题或传入参数有误,那么对话将无法进行。这时,我们可以通过给 LCCKConversationViewController 设定 conversationHandler 来处理。示例代码如下:

 [[LCChatKit sharedInstance] setFetchConversationHandler:^(
                                                              AVIMConversation *conversation,
                                                              LCCKConversationViewController *aConversationController) {
    if (!conversation) {
        // 显示错误提示信息
        [conversationController alert:@"failed to create/load conversation."];
    } else {
        // 正常处理
    }
}];

请注意,这个 -setFetchConversationHandler: 方法无需每次创建 LCCKConversationViewController 对象时都设置,只需设置一次,之后每次创建 LCCKConversationViewController 对象都会复用该设置。

  • 展示对话详情页

在 QQ/微信等聊天应用中,聊天界面右上角通常会提供一个显示对话详细信息的按钮,点击可以打开对话详情页面,在那里可以进行改名、拉人、踢人、静音等操作。LCCKConversationViewController中也通过调用以下 API 支持这一功能:

typedef void(^LCCKBarButtonItemActionBlock)(void);

typedef NS_ENUM(NSInteger, LCCKBarButtonItemStyle) {
    LCCKBarButtonItemStyleSetting = 0,
    LCCKBarButtonItemStyleMore,
    LCCKBarButtonItemStyleAdd,
    LCCKBarButtonItemStyleAddFriends,
    LCCKBarButtonItemStyleShare,
    LCCKBarButtonItemStyleSingleProfile,
    LCCKBarButtonItemStyleGroupProfile,
};

- (void)configureBarButtonItemStyle:(LCCKBarButtonItemStyle)style action:(LCCKBarButtonItemActionBlock)action;

示例代码如下:

[aConversationController configureBarButtonItemStyle:LCCKBarButtonItemStyleGroupProfile
                                                          action:^(UIBarButtonItem *sender, UIEvent *event) {
    ConversationDetailViewController *detailVC = [[ConversationDetailViewController alloc] init];// 自己实现的对话详情页
    detailVC.conversation = conversation;
    [conversationController.navigationController pushViewController:detailVC animated:YES];
}];

手动集成

如果你不想使用 CocoaPods 进行集成,也可以选择使用源码集成。步骤如下:

第一步:

将项目结构中提到的 ChatKit 这个「核心库文件夹」拖拽到项目中。

第二步:

添加 ChatKit 依赖的第三方库以及对应版本:

具体以 这里 为准。

常见问题

ChatKit 组件收费吗?
ChatKit 完全是开源并且免费供开发者使用,使用聊天产生的费用以 这里 为准。

接入 ChatKit 有什么好处?
它可以降低应用或新功能研发初期的调研成本,直接引入使用即可。ChatKit 从底层到 UI 提供了一整套的聊天解决方案。

如何兼容 iOS7?
因为 ChatKit 中使用了 iOS8 的一个控件:UITableViewRowAction,所以想要兼容 iOS7,就需在 App 中添加一个 Lib:

pod "CYLTableViewRowAction", "1.0.0"

Demo 中也是通过这种方式来兼容 iOS7 的。

如果不使用 Pod,你可以直接下载 CYLTableViewRowAction 将里面的文件夹拖拽到项目中,不兼容 iOS7 的问题就解决了。

为什么收不到推送消息?
问题描述:推送的证书已经配置好,在控制台里测试推送,手机也能接收到,但另一个好友发送的消息就是接收不到。

在这种情况下,请先参考 《iOS 消息推送开发指南》,如果设置方法正确,再检查以下设置是否正确:

比如可以这样设置:

{"alert":"您有新的消息","badge":"Increment"}

如果想获取推送的消息内容可以参考 《iOS 消息推送 点击app图标 app icon如何获取推送信息 leanCloud 点击app图标 获得推送消息》

在使用中有任何问题都可以到我们的官方论坛提问,会有专业工程师回复,平均响应时间在 24 小时内。