NIMKit
是一款可以帮助用户快速打造出聊天功能的UI组件,开发者可以通过一些简洁的代码,快速的实现聊天界面和最近联系人功能,并实现基础的一些定制化开发。 NIMKit
完全开源,如果开发者希望修改界面,只需要通过替换界面资源,修改配置等方式即可实现。如果开发者希望更深层次的自定义,也可自行修改代码。
NIMKit
依赖云信通讯能力库NIMSDK
,请自行在您的工程中添加。- 定制自定义消息教程 NIM Guide For Custom Message 。
- 利用组件绘制自定义消息气泡教程 NIM Guide For Custom Message UI 。
- 工程配置和自定义消息配置示例请参考
NIMKitDemo\DemoApplication
工程 (请自行在 DemoApplication/NIMSDK/ 下添加通讯能力库 libNIMSDK.a )。 - 具体使用范例请参考 NIM Demo For iOS 。
-
添加
NIMKit
到您自己的工程中。 -
添加
NIMSDK
到您自己的工程中,您可以选择手动添加或者使用 CocoaPods 导入。 -
在您自己的工程中,打开
Build Phases
选项,展开Link Binary With Libraries
选项卡。添加必要的依赖项:- CoreText.framework
如果您选择手动添加 NIMSDK , 您还要添加以下依赖项:
- CoreTelephony.framework
- AVFoundation.framework
- MobileCoreServices.framework
- SystemConfiguration.framework
- AudioToolbox.framework
- CoreMedia.framework
- libstdc++.6.0.9.tbd 注1 注2
- libsqlite3.0.tbd 注1
- libz.tbd 注1
注1 :在 XCode7 以上版本中后缀为 tbd , XCode6 及以下均为 dylib。
注2 :请注意c++库的版本号,务必保证为 6.0.9 。
-
设置
Other Linker Flags
为-ObjC
。 -
在工程配置
info.plist
文件中,添加条目NSAppTransportSecurity
,属性设为Dictionary
。在此条目下添加键值对,key 为NSAllowsArbitraryLoads
, 值为YES
。 -
在工程中添加
NIMKitResouce.bundle
。 -
在需要使用到组件的地方导入头文件
NIMKit.h
。 -
新建一个 SessionViewController,从 NIMSessionViewController 进行继承 (此时运行将可以得到一个简单的会话界面)。
NIMKit 代替开发者实现了会话页和最近会话列表两个复杂界面。开发者只需要继承 NIMSessionViewController 和 NIMSessionListViewController , 通过简洁的代码设置,即可在最短的时间内将聊天功能快速集成进App产品中。
由于 NIMKit 并不关心业务逻辑信息,比如用户昵称,用户头像等。用户可以通过 NIMKit 单例向 NIMKit 注入一个内容提供类,通过这个内容提供类,NIMKit 才能够正确的进行业务逻辑数据的绘制。
开发者需要自定义一个提供类并实现NIMKitDataProvider协议
@protocol NIMKitDataProvider <NSObject>
@optional
/**
* 上层提供用户信息的接口
*
* @param userId 用户ID
* @param session 所在的会话
*
* @return 用户信息
*/
- (NIMKitInfo *)infoByUser:(NSString *)userId
inSession:(NIMSession *)session;
/**
* 上层提供用户信息的接口
*
* @param userId 用户ID
* @param message 所在的消息
*
* @return 用户信息
*/
- (NIMKitInfo *)infoByUser:(NSString *)userId
withMessage:(NIMMessage *)message;
/**
* 上层提供群组信息的接口
*
* @param teamId 群组ID
*
* @return 群组信息
*/
- (NIMKitInfo *)infoByTeam:(NSString *)teamId;
/**
* 当消息作为提醒时(即会话里灰色的提示条),需要显示的文本
*
* @param message 消息
*
* @return 显示文本
*/
- (NSString *)tipMessage:(NIMMessage *)message;
开发者可以在程序启动的时候,将实现类注入到 NIMKit 里。代码示例:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
...
//这里的 NTESDataProvider 实现了 NIMKitDataProvider 协议
[[NIMKit sharedKit] setProvider:[NTESDataProvider new]];
...
return YES;
}
由于开发者应用的数据很多时候都是异步获取的(如用户信息可能从应用服务器请求获取),内容提供类在接收到 NIMKit 数据请求时,可能本地并没有数据,这个时候可以在回调里直接返回占位信息,如用户的昵称可以用 ID 代替,用户的头像可以用默认头像代替。等到数据请求回来时,调用 NIMKit 的通知接口,NIMKit 会自动刷新用户信息。
刷新接口
/**
* 用户信息变更通知接口
*
* @param userId 用户id
*/
- (void)notfiyUserInfoChanged:(NSString *)userId;
/**
* 群信息变更通知接口
*
* @param teamId 群id
*/
- (void)notfiyTeamInfoChanged:(NSString *)teamId;
代码示例:
- (NIMKitInfo *)infoByUser:(NSString *)userId
inSession:(NIMSession *)session
{
BOOL needFetchInfo = NO;
NIMSessionType sessionType = session.sessionType;
NIMKitInfo *info = [[NIMKitInfo alloc] init];
//填写默认值
info.infoId = userId;
info.showName = userId;
switch (sessionType) {
case NIMSessionTypeP2P:
case NIMSessionTypeTeam:
{
NIMUser *user = [[NIMSDK sharedSDK].userManager userInfo:userId];
NIMUserInfo *userInfo = user.userInfo;
NIMTeamMember *member = nil;
if (sessionType == NIMSessionTypeTeam)
{
member = [[NIMSDK sharedSDK].teamManager teamMember:userId
inTeam:session.sessionId];
}
NSString *name = [self nickname:user
memberInfo:member];
if (name)
{
info.showName = name;
}
info.avatarUrlString = userInfo.thumbAvatarUrl;
info.avatarImage = self.defaultUserAvatar;
if (userInfo == nil)
{
needFetchInfo = YES;
}
}
break;
case NIMSessionTypeChatroom:
//聊天室的Info不会通过这个回调请求
NSAssert(0, @"invalid type");
break;
default:
NSAssert(0, @"invalid type");
break;
}
if (needFetchInfo)
{
//远程获取用户信息
[self.request requestUserIds:@[userId]];
}
return info;
}
NIMKit 中所有的资源都文件都是从 NIMKitResouce.bundle 读取,开发可以替换相应的素材以起到修改界面的效果。
-
概述
NIMSessionViewController
继承UIViewController
,由UITableView
(界面),id<NIMSessionConfig>
(会话配置),NIMSessionMsgDatasource
(数据源) 作为基本构成。-
会话页结构
├── NIMSessionViewController #核心会话类 │ ├── NIMSession # 所属会话 │ ├── UITableView # 聊天气泡聊表 │ ├── NIMSessionViewLayoutManager # 布局管理器 │ ├── NIMSessionConfig # 会话参数配置协议 │ │ ├── NIMCellLayoutConfig # 消息的排版配置协议,默认配置为 NIMCellLayoutDefaultConfig , 可以继承这个类,并重写部分布局方法 │ │ │ ├── # 气泡大小 │ │ │ ├── # 气泡内容布局 │ │ │ ├── # 是否显示头像 │ │ │ ├── # 是否显示姓名 │ │ │ └── # 气泡自定义控件 │ │ ├── NIMKitMessageProvider # 消息数据提供器协议 │ │ │ ├── # 自定义消息数据源 │ │ │ └── # 是否需要时间戳 │ │ ├── # 输入按钮类型,录音,文本,表情,更多菜单等按钮,支持自定义顺序排列 │ │ ├── # 更多菜单中的按钮定义 │ │ ├── # 自定义按钮禁用规则 │ │ ├── # 文本输入长度限制 │ │ ├── # 文本输入提示占位符 │ │ ├── # 进入会话是否自动获取历史消息 │ │ ├── # 会话中一次拉取的最大条数 │ │ ├── # 消息之间时间戳的显示间隔 │ │ ├── # 语音未读红点是否禁用 │ │ ├── # 贴耳时,是否自动切换成听筒模式 │ │ ├── # 录音类型和最大时长设置 │ │ └── # 是否处理已读回执 │ ├── NIMInputView # 输入框 │ └── UIRefreshControl # 下拉刷新控件
-
会话配置
需要重写
NIMSessionViewController
的- (id<NIMSessionConfig>)sessionConfig
方法,返回一个实现id<NIMSessionConfig>
协议的配置类。如果没有重写,或者返回的配置类里有一些配置方法没有实现,则会调用默认配置NIMCellLayoutDefaultConfig
。会话配置会在下一节作详细说明。
-
数据源
NIMSessionMsgDatasource
包含两类数据模型,NIMMessageModel
和NIMTimestampModel
。 数据源会将 消息NIMMessaage
包装成界面显示模型NIMMessageModel
,用来缓存一些布局信息来避免重复计算,如消息高度,内容大小等等;同时,由于有的消息距离上一条消息过久,需要在此之间显示一条时间。数据源会根据定义的间隔规则,计算出需要显示的时间模型NIMTimestampModel
,插在这两条消息中间。当消息显示时,首先会触发
UITableViewDatasource
的几个基本回调:- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
在这个回调中,会将数据源中的模型取出,如果模型中没有缓存
cell
的布局信息,则进行一次计算,并存入模型的缓存。- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
在这个回调中,根据模型的种类复用
NIMMessageCell
或者NIMSessionTimestampCell
来进行显示。消息
NIMMessageCell
的几点说明:NIMMessageCell
本质是由一个所有消息通用(如重试红点,头像)的视图和内容子视图NIMSessionMessageContentView
构成的。NIMSessionMessageContentView
是一个子视图的基类,所有消息的子视图都必须继承这个类。- 不同消息类型
NIMMessageCell
需要由不同的cellReuseIdentifier
来方便复用,cellReuseIdentifier
即为内容子视图的类名。 NIMSessionMessageContentView
的具体实现子类名由协议NIMCellLayoutConfig
中方法- (NSString *)cellContent:(NIMMessageModel *)model
返回。
关于
NIMMessageCell
会在下一节做详细说明。对于内置的消息类型(如图片,语音,位置等消息),
NIMKit
已在NIMCellLayoutDefaultConfig
(实现了NIMCellLayoutConfig
协议) 中定义。NIMCellLayoutDefaultConfig
将根据消息类型返回不同的消息配置。所有内置的消息配置都可以从NIMKit/Classes/Sections/Session/Config/
目录下找到。内置的
NIMSessionMessageContentView
如下,在命名自己的子视图时,请注意不要重名。- NIMSessionTextContentView
- NIMSessionVideoContentView
- NIMSessionAudioContentView
- NIMSessionFileTransContentView
- NIMSessionImageContentView
- NIMSessionLocationContentView
- NIMSessionNetChatNotifyContentView
- NIMSessionNotificationContentView
- NIMSessionUnknowContentView
对于开发者上层的自定义消息类型,开发者需要自己实现一个配置类并实现
NIMCellLayoutConfig
协议,并在cellContent:
方法中返回此消息独有的cellReuseIdentifier
(见会话配置)。 -
-
NIMMessageCell
-
蓝色区域:为具体内容 ContentView,如文字 UILabel ,图片 UIImageView 等。
-
绿色区域:为消息的气泡,具体的内容和气泡之间会有一定的内间距,这里为 contentViewInsets 。
-
紫色区域:为整个 UITableViewCell ,具体的气泡和整个cell会有一定的内间距,这里为 cellInsets 。
-
红色区域:为用户的头像。
-
在刷新数据时,会调用方法并 -(void)refresh
将界面模型 NIMMessageModel
传入。
当第一次调用这个方法(即不是复用生成),会调用 - (void)addContentViewIfNotExist
方法,根据 NIMMessageModel
找到对应的布局配置(如果找不到则按未知类型消息处理)。
Tips:开发者在第一次接入的时候,可能由于协议实现不全或者注入布局配置有误等原因,导致消息在界面上显示为 未知类型消息
,这个时候可以尝试从 NIMMessageCell
的 - (void)addContentViewIfNotExist
方法入手调试,查看NIMMessageModel
对应的布局配置以及协议的返回值是否正确。
-
NIMSessionMsgDatasource
会话数据源主要用于数据读取,在读取数据后会自动排序成界面需要的消息顺序,需要注意的是,会话数据源可以接受一个消息数据提供者
NIMKitMessageProvider
,用来显示不同来源的数据,默认不设置则读取本地数据。以 云信Demo 为例,在进入单人会话
NTESSessionViewController
时,读取的本地数据;当进入拉取服务器云端会话页NTESSessionRemoteHistoryViewController
时,则将自己的配置改成NTESRemoteSessionConfig
,并在NTESRemoteSessionConfig
的- (id<NIMKitMessageProvider>)messageDataProvider
方法里返回了NIMRemoteMessageDataProvider
,即可用来显示云端记录。
NIMKit 提供一个自定义的多媒体面板,用户只需要实现 NIMSessionConfig 即可。SessionViewController 会在初始化进行查询。
- (NSArray *)mediaItems;
- (BOOL)shouldHideItem:(NIMMediaItem *)item;
目前 NIMKit 提供了多种多样的事件的,主要定义在 NIMInputActionDelegate 和 NIMMessageCellDelegate,子类只需要按需实现即可。
####参数配置
目前 NIMKit 提供如下的界面逻辑配置
是否禁用输入框 | 输入框面板菜单 |
---|---|
最大输入长度 | 输入框place holder |
消息分页条数 | 消息时间戳显示间隔 |
内置聊天气泡布局配置 | 自定义消息数据源 |
这次消息时候需要做已读回执的处理 | 是否需要处理已读回执 |
进入会话自动获取历史消息 | 录音类型 |
是否禁用语音未读红点 | 是否禁用在贴耳的时候自动切换成听筒模式 |
所有的配置项都可以在 NIMSessionConfig
中找到。
开发者需要自定义一个配置类实现 NIMSessionConfig
中的配置方法,并注入到 NIMSessionViewController
的 - (id<NIMSessionConfig>)sessionConfig
方法中 (可由子类复写)。详细可参考 NIM Demo For iOS 中的 NTESSessionViewController
类。
#####NIMSessionConfig
配置范例
@interface NTESSessionConfig()<NIMSessionConfig>
@end
@implementation NTESSessionConfig
/**
* 可以显示在点击输入框“+”按钮里的多媒体按钮
*/
- (NSArray *)mediaItems
{
// NTESMediaButtonPicture , NTESMediaButtonShoot 为 NIMMediaItem 的 tag 值,用来区分多个 NIMMediaItem 。
return @[[NIMMediaItem item:NTESMediaButtonPicture
normalImage:[UIImage imageNamed:@"bk_media_picture_normal"]
selectedImage:[UIImage imageNamed:@"bk_media_picture_nomal_pressed"]
title:@"相册"],
[NIMMediaItem item:NTESMediaButtonShoot
normalImage:[UIImage imageNamed:@"bk_media_shoot_normal"]
selectedImage:[UIImage imageNamed:@"bk_media_shoot_pressed"]
title:@"拍摄"],
}
/**
* 是否隐藏多媒体按钮
*/
- (BOOL)shouldHideItem:(NIMMediaItem *)item
{
return NO;
}
/**
* 是否禁用输入控件
*/
- (BOOL)disableInputView
{
return NO;
}
/**
* 输入控件最大输入长度
*/
- (NSInteger)maxInputLength
{
return 5000;
}
/**
* 输入控件placeholder
*/
- (NSString *)inputViewPlaceholder
{
return @"请输入消息";
}
/**
* 一次最多显示的消息条数
*/
- (NSInteger)messageLimit
{
return 20;
}
/**
* 消息的排版配置,只有使用默认的NIMMessageCell,才会触发此回调
*/
- (id<NIMCellLayoutConfig>)layoutConfigWithMessage:(NIMMessage *)message
{
//具体消息的排版配置,关于消息结构模型,请参考下一章节 自定义消息和 MessageCell 。
id<NIMCellLayoutConfig> config;
switch (message.messageType) {
case NIMMessageTypeCustom:{
if ([NTESSessionCustomLayoutConfig supportMessage:message]) {
config = [[NTESSessionCustomLayoutConfig alloc] init];
break;
}
}
default:
break;
}
return config;
}
@end
####自定义消息
#####内置MessageCell的自定义配置
使用云信用户可以自定义自己的消息格式,而同样的 NIMKit 也提供了不同消息类型的绘制方法。手把手教程可以参考如下:
-
定制自定义消息教程 NIM Guide For Custom Message 。
-
利用组件绘制自定义消息气泡教程 NIM Guide For Custom Message UI 。
在会话中,每种 message 都对应一个 NIMCellLayoutConfig,NIMSessionViewController 在生成 message 对应的 cell 时会询问子类是否有 当前 message 到 NIMCellLayoutConfig 的对应关系,如果没有则直接使用默认配置。
NIMCellLayoutConfig 中主要的方法有:
- 查询某个消息对应的ContentView类名
- (NSString *)cellContent:(NIMMessageModel *)model;
- 查询某个消息对应的内容区域的大小
- (CGSize)contentSize:(NIMMessageModel *)model cellWidth:(CGFloat)width;
- cell气泡距离整个cell的内间距
- (UIEdgeInsets)cellInsets:(NIMMessageModel *)model;
- cell内容距离气泡的内间距
- (UIEdgeInsets)contentViewInsets:(NIMMessageModel *)model;
- 是否显示头像
- (BOOL)shouldShowAvatar:(NIMMessageModel *)model;
- 是否显示姓名
- (BOOL)shouldShowNickName:(NIMMessageModel *)model;
只要用户对自定义消息实现这2个接口就能够完整的实现一个 MessageCell 。需要注意的是返回的ContentView类必须是 NIMSessionMessageContentView 的子类。
当然用户也可以实现自己的 MessageCell这种方式自然是最为灵活,但也有代价:需要实现 NIMMessageCell 已实现的一些功能,并不推荐。
###最近会话列表界面 NIMSessionListViewController
与会话界面类似,新建一个 SessionListViewController ,从SessionListViewController 进行继承 (此时运行将可以得到一个简单的最近会话列表界面)。
#####最近会话列表配置
- 删除会话时是不是也同时删除服务器会话 (防止漫游)
@property (nonatomic,assign) BOOL autoRemoveRemoteSession;
#####最近会话列表显示自定义 以下方法都有默认实现,开发者可以根据自己的需求自行定制重写某个或全部方法。
- cell显示的会话名
- (NSString *)nameForRecentSession:(NIMRecentSession *)recent;
默认实现为,点对点会话,显示聊天对象的昵称(没有昵称则显示账号);群聊会话,显示群名称。
- cell显示的最近会话具体内容
- (NSString *)contentForRecentSession:(NIMRecentSession *)recent;
默认实现为:显示最近一条消息的内容,文本消息则显示文本信息,其他消息显示消息类型文案
- cell显示的最近会话时间戳
- (NSString *)timestampDescriptionForRecentSession:(NIMRecentSession *)recent;
默认实现为:最后一条消息的时间戳的格式化文案。
##联系人选择器 NIMContactSelectViewController NIMKit 提供联系人选择器功能。支持选择用户或者群组,支持多选。
###初始化联系人选择器
开发者需要在初始化的时候通过传入配置器 id<NIMContactSelectConfig>
,对联系人选择器进行配置。 NIMKit 预留了三种常用的配置,分别为:
1.选择好友 NIMContactFriendSelectConfig
2.选择群 NIMContactTeamSelectConfig
3.选择群成员 NIMContactTeamMemberSelectConfig
开发者可在 NIMContactSelectConfig.h
中找到对应声明。
选择好友示例:
NSMutableArray *users = [[NSMutableArray alloc] init];
//使用内置的好友选择器
NIMContactFriendSelectConfig *config = [[NIMContactFriendSelectConfig alloc] init];
//获取自己id
NSString *currentUserId = [[NIMSDK sharedSDK].loginManager currentAccount];
[users addObject:currentUserId];
//将自己的id过滤
config.filterIds = users;
//需要多选
config.needMutiSelected = YES;
//初始化联系人选择器
NIMContactSelectViewController *vc = [[NIMContactSelectViewController alloc] initWithConfig:config];
//回调处理
vc.finshBlock = block;
###显示联系人选择器
创建完联系人选择器之后,调用 -(void)show
方法就可以弹出联系人选择器。
###联系人选择器回调
联系人选择器提供 delegate
和 block
两种回调,可以根据业务需求自行选择监听方式。
##群名片
群名片分为普通群群名片 NIMNormalTeamCardViewController
和 高级群群名片 NIMAdvancedTeamCardViewController
两种类型,初始化时传入需要展示的群组 NIMTeam
即可。
此组件意在为快速为开发者搭建一套可以直接使用的群名片,开发者可以根据需求自行修改组件源码。