LeanCloud实时通信模块iOS端快速接入指南(二)

2016年03月03日更新

使用id A进入聊天,然后返回登陆界面使用id B进入聊天,然后对A发起会话会导致崩溃,原因是没有关闭A的客户端,会导致自己和自己发起会话。解决方法是在开启聊天客户端之前先关闭之前的客户端,即改写『登陆』的事件为下列代码
- (IBAction)loginBtnClicked:(id)sender {
[[CDChatManager manager]closeWithCallback:^(BOOL succeeded, NSError *error) {
[[CDChatManager manager]openWithClientId:_textField.text callback:^(BOOL succeeded, NSError *error) {
ChatListViewController * chatList = [[ChatListViewController alloc]init];
[self.navigationController pushViewController:chatList animated:YES];
}];

 }];

}

写在最前面

更新了最新版的LeanCloud的SDK
静态库的体积确实小了很多,但是有一些LeanCloud改了一小部分方法的名称
如果按照我的攻略发现代码有问题的,请把所有的Conv改为Conversation不管这个Conv是在开头还是结尾还是方法名中间

比如老版的是

  [[CDChatManager manager] fetchConvWithOtherId:_textField.text callback:^(AVIMConversation *conversation, NSError *error) {
    }];

现在就是

[[CDChatManager manager]fetchConversationWithOtherId:@"78" callback:^(AVIMConversation *conversation, NSError *error) {
    }];

其他方法同上,如有其它发现我都会写在这里
另外老版的CDUserModel协议已经更名为CDUserModelDelegate

  • LeanCloud的程序员一定是强迫症晚期(╯‵□′)╯︵┻━┻

写在前面

首先附上之前文章的链接
[LeanCloud实时通信模块IOS端快速接入指南(一)]
废话少说,这一节我们来实现一个相对完整的聊天功能。


功能描述

还记得上一节说过的LeanCloud如何创建聊天吗?没错,你自己的id加上你要聊天的人的id就可以创建一个对话。
那么我们今天做这么一个东西,项目启动时输入一个自己的id,确认后弹出类似QQ的最近聊天界面,点击最近聊天的任意会话进行聊天或对任意指定id发起聊天。

正文

准备项目

新建一个项目,起一个你喜欢的名字


初始化项目

然后是导入SDK,在AppDelegate中注册,和前边一样


Paste_Image.png
搭建页面结构

这里我们准备的项目在下一节还要继续用,所以我们使用StoryBoard搭建一个相对完整的项目

*为了尽量照顾大多数人,我这里把构建StoryBoard的过程也贴出来,已经熟练使用的请忽略

删除自带的ViewController和Main.storyboard中对应的控件
在Main.storyboard中添加一个标签栏控制器(TabBarViewController)并设置为根视图控制器(勾选Is Initial View Controller选项,被设置为根视图控制器的控件左边会有箭头)

设置标签栏

去掉标签栏自带的两个视图控制器,更换成导航视图控制器(NavigationController)
按住鼠标左键不动从标签栏拖动到导航栏


添加关联

松开鼠标后选择ViewControlers

添加关联

另一个导航栏一样照做
运行项目,如下图所示

Paste_Image.png
搭建登陆界面

前一篇说过,我们使用[CDChatManager manager] openWithClientId:@"Tom" callback:^(BOOL succeeded, NSError *error) {}];方法只需要一个自定义的ClientId就可以登陆一个聊天客户端
因此第一个界面我们就用来输入这个Id。
由于在StoryBoard中导航栏自带的根视图控制器默认是UITableVIewController,所以我们删掉它,换成普通的视图控制器
并给它一个标题--『登陆』

登陆界面

登陆界面很简单,如下所示

Paste_Image.png

新建一个视图控制器并将其和StroyBoard中的登陆界面关联起来

Paste_Image.png
实现聊天

给登陆按钮添加事件之前我们先创建接下来要跳转的界面--最近聊天列表ChatListViewController,继承于CDChatListVC

Paste_Image.png

在LoginViewController中引入头文件
#import <CDChatManager.h>
#import"ChatListViewController.h"
按钮的点击事件这么写
- (IBAction)loginBtnClicked:(id)sender {
[[CDChatManager manager]openWithClientId:_textField.text callback:^(BOOL succeeded, NSError *error) {
ChatListViewController * chatList = [[ChatListViewController alloc]init];
[self.navigationController pushViewController:chatList animated:YES];
}];
}

  • 这里解释一下这个CDChatListVC,和前一篇用到的CDChatRoomVC一样,这也是LeanChatLib中写好的一个类,继承于UITableVIewController,每个cell代表一个会话,第一次进入或者刷新会拉取最近的会话,获取到一个叫做conversations的数组,然后将conversation作为数据源读出每一个会话然后展示。点击会话则进入聊天。我们将在下一节详细讲解他的方法并按照我们的需求加以改造,所以这里我们只需要先知道它是干嘛的就够了。

刚才说了,这个ChatListViewController是一个UITableVIewController,所以我们对它稍加改造,给它的TableView加一个HeaderView。
在它的viewDidLoad中这么写
- (void)viewDidLoad {
[super viewDidLoad];

UIView * headerView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 60)];
self.tableView.tableHeaderView = headerView;

_textField = [[UITextField alloc]initWithFrame:CGRectMake(15, 5, self.view.bounds.size.width - 30, 25)];
_textField.layer.borderColor = [UIColor lightGrayColor].CGColor;
_textField.layer.borderWidth = 1;
[headerView addSubview:_textField];

UIButton * startChat = [UIButton buttonWithType:UIButtonTypeSystem];
startChat.frame = CGRectMake(60, 35, self.view.bounds.size.width - 120, 20);
[startChat setTitle:@"开始聊天" forState:UIControlStateNormal];
[headerView addSubview:startChat];
[startChat addTarget:self action:@selector(startChatClicked:) forControlEvents:UIControlEventTouchUpInside];

}

在添加按钮的点击事件之前我们要向之前一样,去创建一个继承于CDChatRoomVC的ChatRoomViewController。

创建聊天室

把聊天室引入到聊天列表
#import "ChatRoomViewController.h"
然后是按钮的点击事件
- (void)startChatClicked:(UIButton *)btn
{
if(_textField.text.length > 0)
{
[[CDChatManager manager] fetchConvWithOtherId:_textField.text callback:^(AVIMConversation *conversation, NSError *error) {
ChatRoomViewController * chatRoom = [[ChatRoomViewController alloc]initWithConv:conversation];
[self.navigationController pushViewController:chatRoom animated:YES];
}];
}

}

因为标签栏会遮住聊天室下方的输入控件,所以我们这么做
在ChatListViewController中添加方法
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.navigationController.tabBarController.tabBar.hidden = NO;
}
在ChatRoomViewController中添加方法
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.navigationController.tabBarController.tabBar.hidden = YES;
}

到此为止我们已经实现了前面的需求,运行项目
在登录界面输入你的id

登陆

点击登陆后输入你想聊天的人的id,然后点击开始聊天

寻找聊天对象

出现如下界面

聊天界面

点击返回

返回最近聊天列表

然后你会发现,卧槽?说好的最近聊天呢? 怎么一篇空白?别急,接下来我们就解决这个问题。

显示最近聊天

刚才点返回的时候,控制台会给你报一堆警告

控制台警告

前面说过,你第一次进入最近聊天页或者刷新最近聊天的时候会拉取到最近的会话,但是你拉取的是会话,和你聊天的对象的头像昵称等信息并没有包含在会话对象中,你需要从CDChatManager的代理中获取到这些信息。因此我们需要实现CDChatManager的CDUserDelegate。这个代理会返回一个遵循CDUserModel协议的对象。

创建一个继承于NSObject的UserFactory类

UserFactory

引入头文件
#import <LeanChatLib/LeanChatLib.h>
遵守协议

@interface UserFactory : NSObject <CDUserDelegate>

@end

在UserFactory.m中实现代理方法
为了方便我们把遵循CDUserModel协议的类也在这里声明

#import "CDUserFactory.h"

@interface CDUser : NSObject <CDUserModel>

@property (nonatomic, strong) NSString *userId;

@property (nonatomic, strong) NSString *username;

@property (nonatomic, strong) NSString *avatarUrl;

@end

@implementation CDUser

@end

@implementation UserFactory

#pragma mark - UserDelegate


- (void)cacheUserByIds:(NSSet *)userIds block:    (AVBooleanResultBlock)block {
block(YES, nil); 
}

- (id <CDUserModel> )getUserById:(NSString *)userId {
CDUser *user = [[CDUser alloc] init];
user.userId = userId;
//在cell中显示的聊天对象的名字
user.username = userId;
//聊天对象的头像
user.avatarUrl = @"http://tp2.sinaimg.cn/5088940253/180/5745995456/1";
return user;
}

@end

然后在Appdelegate.m中添加代理
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
[CDChatManager manager].userDelegate = [[UserFactory alloc]init];
...
return YES;
}

然后再次运行项目,输入刚才的ID,这个时候我们的最近聊天列表就出现了

成功
  • 头像不显示的同学请检查是否打开了ATS。iOS 9 之后默认开启ATS,无法使用Http请求
    关闭方法为在info.plist中添加字段
    <key>NSAppTransportSecurity</key>
    <dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
    </dict>

接下来我们要做的是实现点击最近会话进入聊天
首先让ChatListViewController遵循协议
interface ChatListViewController ()<CDChatListVCDelegate>

然后在viewDidLoad方法中添加加上一句
self.chatListDelegate = self;

然后实现代理方法
- (void)viewController:(UIViewController *)viewController didSelectConv:(AVIMConversation *)conv
{
ChatRoomViewController * chatRoom = [[ChatRoomViewController alloc]initWithConv:conv];
[self.navigationController pushViewController:chatRoom animated:YES];
}
再运行试试,点击最近的聊天也可以进入聊天了


总结

到此为止,我们就利用LeanCloud搭建了一个相对完整的聊天,你已经可以用这个东西跟你的小伙伴聊天了。
虽然我写了这么多乱七八糟的东西,其实总计一下我们只用了三个类就实现了这全部的东西。
这里我们回顾一下

三个类:
  • CDChatRoomVC:LeanChatLib提供的聊天室。拥有带Conversation参数的构造方法,声明后直接跳转进来即可。
  • CDChatListVC:LeanChatLib提供的聊天列表类,登陆聊天Client后直接跳转进入或者进入后再登陆Client都可以。
  • CDChatManager:LeanChatLib的核心管理类,通过[CDChatManager manager]获取单例。它的两个重要方法:
    //登陆一个聊天客户端 openWithClientId:_textField.text callback:^(BOOL succeeded, NSError *error) { };
    //获取一个单聊会话 fetchConvWithOtherId:@"78" callback:^(AVIMConversation *conversation, NSError *error) { }

为了方便理解,这里再多嘴提一句,第一个方法,openClientId。既然有open,对应的也有一个close方法用来关闭聊天客户端。我们所开启的这个Client,不像我们学的Button,Label一样,依附于父视图,父视图销毁,它们也跟着销毁。Client除非你主动关闭或者直接关掉程序,执行open之后它会一直在后台处于开启状态。这也就意味着,只要你执行了openClient,你可以在程序的任意一个界面执行fetchConv获取到一个会话然后跳转到聊天,并不一定是在最近聊天列表才能这么做。这样就能很方便灵活的使用即时通讯模块。


这一节到此结束,下一节,我们来学习按照自己的需求改造我们的聊天功能。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容