用户工具

im_ios_sdk指南

这是本文档旧的修订版!


iOS SDK 集成及配置指导

1、iOS SDK导入

1.1、集成前准备

在云之讯官方网站注册开发者帐号,可参考新手指引

1.2、制作并上传APNS推送证书

如果你的App不需要离线推送功能,可以跳过这一步。(为乐更好的用户体验,我们建议使用离线推送)

Push的工作机制可以简单的概括为下图:

图中:provider是云之讯提供的推送服务器。APNs 是 Apple Push Notification Service(Apple Push服务器)的缩写,是苹果的服务器。ClientApp 是您开发的App。

1) 制作推送证书

  • 打开苹果开发者网站,进行证书生成。

2) 上传推送证书

  • 对生成好的证书,上传到云之讯平台。

1.3、下载SDK

在这里你需要下载IMSDK(下载地址

1.4、SDK目录讲解

SDK包括libucstcplib.a(通信库) 和 libucsimlib.a(业务库)两个库。

TCPSDK

lib静态库

libucstcplib.a          整个TCPSDK 的库文件 与云平台进行通讯的库

头文件

UCSTCPSDK.h             包含TCPSDK所有头文件,使用时import这个文件就行
UCSTcpClient.h          包含TCPSDK的核心能力接口,比如登陆云平台、注销云平台等。
UCSTcpClientDelegate.h  包含TCPSDK的事件回调接口
UCSTcpDefine.h          TCP相关的一些定义
UCSError.h              SDK错误信息定义类

IMSDK

lib静态库

libucsimlib.a                整个IMSDK的库文件,消息业务逻辑处理的库

头文件

UCSIMSDK.h                   包含整个IMSDK的头文件,使用时import这个文件就行			
UCSIMClient.h                包含IMSDK的核心能力接口,比如发消息、获取会话列表等。
UCSIMClientDelegate.h        包含IMSDK的回调接口,回调服务器返回到SDK的信息。比如接收到服务器返回的消息、接收到服务器返回的错误等。
UCSIMDefine.h                包含IMSDK的一些定义。比如聊天类型、会话类型、消息发送状态等。
UCSConversation.h            会话类型
UCSDiscussion.h              讨论组类型
UCSMessage.h                 消息类型,包含一条消息的所有属性
UCSUserInfo.h                用户类
UCSMsgContent.h              消息内容基类
UCSTextMsg.h                 文本消息类,UCSMsgContent的子类
UCSImageMsg.h		     图片消息类,UCSMsgContent的子类
UCSVoiceMsg.h                语音消息类,UCSMsgContent的子类
UCSLocationMsg.h             地理位置消息类,UCSMsgContent的子类
UCSDiscussionNotification.h  讨论组通知类,UCSMsgContent的子类
UCSNotificationMessage.h     通知消息类,UCSMsgContent的子类
UCSCustomMsg.h               自定义消息类,UCSMsgContent的子类
UCSUnknownMsg.h              未知消息类。(高版本的sdk可能会增加新的消息类型,低版本使用未知消息类型兼容识别不了的新类型)

以上就是IMSDK 和TCPSDK目录讲解,具体接口讲解请转到IMSDK接口文档。

1.5、配置工程

1) 导入SDK

将下载好的IMSDK和TCPSDK文件夹拖入到项目中,并勾选Destination。

2) 设置工程属性

3) 添加依赖库 向Build Phases → Link Binary With Libraries 中添加依赖库

SDK的依赖库有 (iOS9以上库的后缀为.tbd):

libstdc++.dylib
libc++.dylib
libz.1.1.3.dylib
SystemConfiguration.framework
libsqlite3.0.dylib
libicucore.dylib

向Targets →Build Settings → Linking → Other Linker Flags 中 添加-ObjC(注意大小写)

1.6、编译工程

以上步骤进行完后,编译工程,如果没有报错,恭喜你,集成SDK成功,可以进行下一步了。

2、连接平台和注销

在介绍SDK的基本功能时,我们会将IMSDK和TCPSDK中的方法逐一讲解,并且在讲解的后面附上云之讯IMDemo调用代码作为参考。

2.1、初始化SDK

1)设置IMSDK的代理,遵循协议,实现代理方法

设置IMSDK的代理,首先要初始化一个UCSIMClient类型的对象,因为这个对象全局通用,所以应该实例化为单例对象。实例化的方法为:

*  @brief  实例化UCSIMClient单例对象
*  @discussion 必须使用这个方法创建UCSIMClient对象,请不要使用init()等初始化方法,否则会出现错误。
*  @return UCSIMClient的单例对象
+ (instancetype)sharedIM;

执行上面的方法,我们有了一个UCSIMClient类型的单例对象,在连接上平台的情况已经可以使用这个对象去发送消息了,但是收不到服务器推过来的消息。如果我们需要接收到服务器推送的消息,那么我们设置一个代理对象,让代理对象遵守协议,代理对象执行代理方法,回调消息给客户端。

代理对象需要遵守的协议为: UCSIMClientDelegate

设置代理的方法为:

*  @brief  设置UCSIMClient的代理对象。
*  @discussion 云之讯IM能力通过 UCSIMClientDelegate 中 didReceiveMessage: withData: 回调收到的消息。如果不设置,则无法接受聊天消息。
*  @param delegate 遵守UCSIMClientDelegate的对象 
- (void)setDelegate:(id <UCSIMClientDelegate>)delegate;

回调消息的方法为:

*  @brief  接收到服务器推送的消息时回调
*  @param messageArray 消息数组。数组中的每一个元素是一个UCSMessage类型的对象。
-(void)didReceiveMessage:(NSArray*) messageArray;

云之讯IMDemo代码参考:

在AppDelegate.m中

// 遵循UCSIMClientDelegate
@interface AppDelegate ()<UCSIMClientDelegate>
//设置im代理对象
-(BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 设置IM代理对象
    [[UCSIMClient sharedIM] setDelegate:self];
    return YES;
}
//实现代理方法
#pragma mark UCSIMClientDelegate
-(void)didReceiveMessage:(NSArray*) messageArray
{
 // 收到消息数组,自定义业务
}

2)设置离线推送环境 需要使用离线推送功能的需要设置离线推送环境,推送环境包含两种:一种为开发环境,一种为生产环境(发布环境),分别对应的证书为开发证书和发布证书(生成的profile文件就可以看出是发开证书(Developer)还是发布证书(Distribution))。

/*!
 *  @brief  设置离线推送环境
 *  @discussion 具体见UCSPushEnvironment,不设置的话,默认是开发环境。
 *  @param environment  开发环境或生产环境
 */
- (void)setPushEnvironment:(UCSPushEnvironment) environment;

云之讯IMDemo代码参考:

在AppDelegate中

// 设置离线推送环境为正式环境(发布环境)
[[UCSTcpClient sharedTcpClientManager] setPushEnvironment:UCSPushEnvironment_Production];

3)保存苹果下发的离线推送deviceToken

将苹果返回的Token去掉空格、<、>保存在NSUserDefaults的DeviceToken字段内(注意大小写,最好复制),sdk会将会去这个字段里面取值。

// 保存离线推送token
[[NSUserDefaults standardUserDefaults] setObject:deviceToken1 forKey:@"DeviceToken"];
[[NSUserDefaults standardUserDefaults] synchronize]

云之讯IMDemo代码参考:

在AppDelegate中

//    // 在Appdelegate中 
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    if (TARGET_IPHONE_SIMULATOR) return;    
    //判断是否拥有推送权限
    NSUInteger rntypes =0;
    if ([[UIDevice currentDevice] systemVersion].integerValue >=8.0){
#ifdef __IPHONE_8_0
        rntypes = [[UIApplication sharedApplication] isRegisteredForRemoteNotifications];
        if (rntypes == UIUserNotificationTypeNone) //没有得到推送的授权
            return;
#endif
    }
    else{
        rntypes = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];
        if (rntypes == UIRemoteNotificationTypeNone) //没有得到推送的授权
            return;
    }
    NSString *deviceToken1 = [[[[deviceToken description] stringByReplacingOccurrencesOfString:@"<"withString:@""] stringByReplacingOccurrencesOfString:@">" withString:@""] stringByReplacingOccurrencesOfString: @" " withString: @""];         
    [[NSUserDefaults standardUserDefaults] setObject:deviceToken1 forKey:@"DeviceToken"];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

2.2、连接云平台

云之讯IM能力是建立在客户端和云平台连接成功的基础上,在连接断开的情况下,你的应用只能收到离线的推送消息(设置了离线推送的情况下),其他的功能都是失效的。云之讯IM是通过tcp长连接与云平台进行交互的,所以我们这里调用TCPSDK中接口去登陆云平台。

注意:在调用接口连接平台之前,请保证你已经设置好了IMSDK的代理对象。这是非常重要的。在下面的讲解中,我们可能会用到“登陆云平台”这个说法,其实也就是“连接云平台”的意思。

连接云平台,由UCSTcpClient的单例对象调用下面的方法

/*!
 *  @brief  连接云平台.
 *  @discussion (注意: 除非是为了兼容旧的IMSDK,否则请使用这个登陆方式)。
 *  @param token        加密的token
 *  @param success 成功回调
 *  @param failure 登陆失败回调,注意:登陆账号被踢线(在其他地方登录)也会回调这个block
 */
- (void)login_connect:(NSString *)token
              success:(void (^)(NSString *userId))success
              failure:(void (^)(UCSError *error))failure;
/*!
 *  @brief 连接云平台.
 *  @discussion  (注意:这个登陆方式是为了兼容旧的IMSDK,后面可能会废弃)。使用这个接口的唯一场景是: 用户已经在现有的app中集成了我们旧的IMSDK,并且不希望更改成新的登陆方式(云之讯建议你更改成新的登陆方式)。其他场景下,请使用新的登陆方式。
 *  @param accountSid   账号sid
 *  @param accountToken 账号token
 *  @param clientNumber clientNumber
 *  @param clientPwd    clientPwd
 *  @param success 成功回调
 *  @param failure 失败回调
 */
- (void)login_connect_old:(NSString *)accountSid
         withAccountToken:(NSString *)accountToken
         withClientNumber:(NSString *)clientNumber
            withClientPwd:(NSString *)clientPwd
                  success:(void (^)(NSString *userId))success

注意:连接平台,我们提供了以上两个方法,但是我们建议你使用前一个方法。还有一点,每一次连接云平台前,我们都建议你先做一次断开操作。token通过AS服务器的注册或者登录接口获取,已注册过的用户每次连接云平台时的token都调用AS登录接口获取。

你可以使用下面这个方法来执行断开操作:

/*!
 *  @brief  断开客户端和云平台的连接
 *  @param flag 是否关闭离线推送的boll值。YES关闭,NO不关闭。
 *  @discussion 在客户端不需要继续与云平台保持连接的时候,调用这个方法断开连接。断开连接后,客户端将不会在收到与云平台的消息推送,也无法发送消息到云平台。
 */
- (void)login_uninitWithFlag:(BOOL)flag;

关于云之讯IM的重连机制:

当客户端和云平台的异常断开后,客户端处于Active的状态下,SDK会自动尝试重连云平台。

主动调用SDK提供的断开连接的方法不属于异常断开,SDK不会尝试重连

云之讯IMDEMO的参考代码:

//每次连接之前,先断开tcp连接。
[[UCSTcpClient sharedTcpClientManager] login_uninitWithFlag:0];
//使用token登陆。token由用户的as服务器下发。这里不赘述。
[[UCSTcpClient sharedTcpClientManager] login_connect:im_token  success:^(NSString *userId) {
	// 连接云平台成功,业务自己处理
} failure:^(UCSError *error) {
	// 连接云平台失败,业务自己处理
}];

登陆成功后,加上前面已经设置好了代理,IM能力就启动了,可以开始收发消息了。

2.3、TCP连接状态回调

TCP连接状态回调包括,TCP连接成功,连接失败,重连成功,重连失败,账号再其他地方登录被踢线等……

状态回调是通过一个代理方法回调的,首先遵守UCSTCPDelegateBase协议,然后设置TCP单例的代理,最后实现代理方法。

/*!
 *  @brief  设置代理.
 *  @discussion  如果需要通过回调监控tcp连接状态之类的,就必须设置这个代理
 *  @param delegate tcp事件回调代理
 */
- (void)setTcpDelegate:(id <UCSTCPDelegateBase>) delegate;

云之讯 IMDEMO代码参考:

//设置tcp代理
[[UCSTcpClient sharedTcpClientManager] setTcpDelegate:self];

实现协议的方法:

/*!
 *  @brief  连接状态变化时
 *  @param connectionStatus 连接状态
 *  @param error            错误描述
 */
- (void)didConnectionStatusChanged:(UCSConnectionStatus)connectionStatus  error:(UCSError *) error;

云之讯IMDEMO代码参考

- (void)didConnectionStatusChanged:(UCSConnectionStatus)connectionStatus error:(UCSError *)error
{
    switch (connectionStatus) {
        case UCSConnectionStatus_BeClicked:
           // 账号在其他地方登录,被踢线。
            [self kickOff];
            break;
        default:
            break;
    }
}

3、基本功能集成

3.1、接收消息或者通知

注意:这里所指的是在线情况下的消息接收,不包括离线推送。

登陆云平台后,当服务器推送新的消息、通知时,将会回调didReceiveMessages:方法。如果未收到回调消息,请检查是否成功初始化SDK并且设置好了代理。

/*!
 *  @brief  收到服务器推送的消息时回调
 *  @param messageArray  消息数组。数组中每一个元素是一个UCSMessage对象
 */
- (void)didReceiveMessages:(NSArray*)messageArray;

消息接收的可能原因:

1、 未按照以上步骤设置好代理对象,导致代理方法为调用;

2、 网络异常,导致与云平台的连接被断开;

3、 服务器异常。

云之讯IMDEMO参考代码:

#pragma mark UCSIMClientDelegate
- (void)didReceiveMessages:(NSArray*)messageArray
{
 // 收到消息数组,自定义业务
}

messageArray的中元素是UCSMessage类型的对象。是IM消息元数据,对其属性进行相应的解析获取消息的内容,详细看SDK中该头文件的注释。(注意:如果上抛的消息是语音消息,这时候语音消息并未下载完成,接收状态为下载中。)

SDK会自动帮我们下载接收到的语音消息,下载结果在通过下面的代理方法回调:

/*!
 *  @brief  自动下载语音成功时回调。主动调用接口下载语音成功不会回调。
 *  @param message 语音消息
 */
- (void)didVoiceDownloadSuccessWithMessage:(UCSMessage *)message;
 
/*!
 *  @brief  自动语音下载失败时回调。主动调用接口下载语音失败不会回调。
 *  @param message 语音消息
 */
- (void)didVoiceDownloadFailWithMessage:(UCSMessage *)message;

云之讯IMDEMO代码参考

// 语音下载完成回调
- (void)didVoiceDownloadSuccessWithMessage:(UCSMessage *)message
{
    [[NSNotificationCenter defaultCenter] postNotificationName:DidRecuveVoiceDownloadStateNotification object:message];
}
// 语音下载失败回调
- (void)didVoiceDownloadFailWithMessage:(UCSMessage *)message
{
    [[NSNotificationCenter defaultCenter] postNotificationName:DidRecuveVoiceDownloadStateNotification object:message];
}

语音消息下载失败时,重新下载

/*!
*  @discussion 云之讯IM收到语音消息时首先会自动下载语音数据。在绝大部分的情况下,语音数据能够下载成功,但不排除因网络等因素带来的失败情况,这个时候开发者可以调用这个接口主动下载语音数据。一般在自动下载失败的情况下调用。
 *  @brief  主动下载消息的语音数据
 *  @param conversationType 会话类型
 *  @param targetId 聊天对象的id。群组聊天时为群组id,讨论组聊天时为讨论组id。
 *  @param messageId 消息id
 *  @param success   下载成功
 *  @param failure   下载失败。
 */
- (void)downloadVoiceWithConversationType:(UCS_IM_ConversationType)conversationType
                                 targetId:(NSString *)targetId
                                messageId:(long long)messageId
                                  success:(void (^)(UCSMessage *message))success
                                  failure:(void (^)(UCSMessage *message, UCSError *error))failure;

云之讯IMDEMO代码参考

// 语音下载失败,主动下载该语音
[[UCSIMClient sharedIM] downloadVoiceWithConversationType:_chatType targetId:_chatter messageId:model.messageId success:^(UCSMessage *message) {
            NSNotification * notification = [[NSNotification alloc] initWithName:DidRecuveVoiceDownloadStateNotification object:message userInfo:nil];
            [weakSelf voiceDownloadStateChange:notification];
        } failure:^(UCSMessage *message, UCSError *error) {
            NSNotification * notification = [[NSNotification alloc] initWithName:DidRecuveVoiceDownloadStateNotification object:message userInfo:nil];
            [weakSelf voiceDownloadStateChange:notification];
        }];

3.2、会话操作

会话在IMSDK中对应的类型是UCSConversation。

1) 获取所有的会话

使用场景:获取最近有过聊天的会话,可以再次进入该会话与联系人进行通讯,可以用于展示会话列表或者最近联系人列表。

/*!
 *  @brief 获取会话列表
 *  @param UCS_IM_ConversationListType会话类型的枚举,具体参考UCS_IM_ConversationListType
 *  @return 会话数组,每个元素是一个UCSConversation对象
 */
- (NSArray*)getConversationList:(UCS_IM_ConversationListType*)conversationListType;

云之讯IMDEMO参考代码:

NSArray*conversationLists = [[UCSIMClient sharedIM] getConversationList: allChat];

2) 获取某个会话的未读消息

使用场景:某个会话的未读消息数用来标识该会话有几条消息是用户未看到过的,提醒用户去看新的消息。

/*!
 *  @brief 获取某个会话的未读消息数
 *  @discussion 这个方法用来获取某个会话的未读消息数,提醒用户有未读的消息
 *  @param conversationType 会话类型。类型值参考UCS_IM_ConversationType
 *  @param targetId         会话id,单聊为对方的id,讨论组聊天为讨论组id,群组聊天为群组id
 *  @return 未读消息数量
 */
- (int)getUnreadCount:(UCS_IM_ConversationType)conversationType
targetId:(NSString *)targetId;

3) 获取所有会话的未读消息

使用场景 :获取所有会话的未读消息总数,用来提醒用户应用有多少条新消息,可以将获取到的未读消息总数显示在应用图标上,吸引用户进入应用查看消息。

/*!
 *  @brief 获取所有会话的未读消息总数
 *  @return 未读消息总数
 */
- (int)getTotalUnreadCount;

4) 清除某个会话的所有未读消息数

使用场景:当用户点击会话进入聊天界面阅读完新消息,或者用户忽略新消息时,可以使用这个功能清除会话的未读消息数。如果不清除,该会话的未读消息数不会为空。

*!
 *  @brief 清空某个会话的未读消息总数
 *  @param conversationType 会话类型。类型值参考UCS_IM_ConversationType
 *  @param targetId         会话id,单聊为对方的id,讨论组聊天为讨论组id,群组聊天为群组id
 *  @return 操作结果的bool值
 */
- (BOOL)clearConversationsUnreadCount:(UCS_IM_ConversationType)conversationType
targetId:(NSString *)targetId;

云之讯IMDEMO的参考代码:

//获取某个会话的未读消息总数
ret = [[UCSIMClient sharedIM] clearConversationsUnreadCount:_chatType targetId:_chatter];

5) 会话置顶和取消置顶

当用户的会话数量比较多的时候,可能希望能将经常联系的好友会话放到会话列表的顶部,方便沟通。这种情况下,我们就可以使用置顶功能将某个会话加到顶部。如果多个会话置顶,后置顶的会话会把先置顶的会话往后挤,新置顶的会话会排在第一位。同样,在不需要置顶的情况下,我们也可以取消会话置顶。

注意:当和某个人聊天的会话被删除后,再创建的话,会话默认是不置顶的。

/*!
 *  @brief 会话列表中,设置某条会话的置顶状态
 *  @param conversationType 会话类型。类型值参考UCS_IM_ConversationType
 *  @param targetId          会话id,单聊为对方的id,讨论组聊天为讨论组id,群组聊天为群组id
 *  @param isTop            yes 置顶 , no 取消置顶
 *  @return 操作结果的bool值
 */
- (BOOL)setConversationToTop:(UCS_IM_ConversationType)conversationType
                    targetId:(NSString *)targetId
                       isTop:(BOOL)isTop;

云之讯IMDEMO参考代码:

取消置顶
//取消置顶
[[UCSIMClient sharedIM] setConversationToTop:aConversation.conversationType targetId:aConversation.targetId isTop:NO];
//会话置顶
[[UCSIMClient sharedIM] setConversationToTop:aConversation.conversationType targetId:aConversation.targetId isTop:YES];

6) 删除一条会话

当不需要某个会话显示在会话列表时,我们可以删除这个会话。如果再次创建,这个会话还是会出现在会话列表中。

/*!
 *  @brief 在会话列表中移除一个会话,但是不会删除该会话在数据库中的消息。
 *  @param conversationType 会话类型。类型值参考UCS_IM_ConversationType
 *  @param targetId         会话id,单聊为对方的id,讨论组聊天为讨论组id,群组聊天为群组id
 *  @return 操作结果的bool值
 */
- (BOOL)removeConversation:(UCS_IM_ConversationType)conversationType
                  targetId:(NSString *)targetId;

云之讯IMDEMO参考代码:

//删除一个会话
[[UCSIMClient sharedIM] removeConversation:aConversation.conversationType targetId:aConversation.targetId];

7) 清空某个会话的所有聊天记录

当需要删除和某个人或者某个讨论组、群的聊天记录时,可以调用这个方法。删除后,被删除的记录将不能恢复。

/*!
 *  @brief 清空某一个会话所有的聊天记录
 *  @param conversationType  会话类型。类型值参考UCS_IM_ConversationType
 *  @param targetId          会话id,单聊为对方的id,讨论组聊天为讨论组id,群组聊天为群组id
 *
 *  @return 操作结果的bool值
 */
- (BOOL)clearMessages:(UCS_IM_ConversationType)conversationType

云之讯IMDEMO代码参考:

[MBProgressHUD showMessage:@"删除消息记录中.." toView:self.view];
BOOL ret = [[UCSIMClient sharedIM] clearMessages:UCS_IM_DISCUSSIONCHAT targetId:_targetId];
if (ret) {
   [MBProgressHUD hideHUDForView:self.view animated:YES];
   [MBProgressHUD showSuccess:@"已删除" toView:self.view];
}else {
   [MBProgressHUD hideHUDForView:self.view animated:YES];
   [MBProgressHUD showError:@"删除失败" toView:self.view];
}

3.3、文本草稿操作

在聊天会话中,如果编辑了消息,但是未发送,可以将草稿消息保存起来,下次进入聊天会话时,取出草稿消息并展示。一个会话默认的草稿消息为空,只有调用保存草稿的接口,才能保存。使用完草稿的值之后,可以调用接口将草稿置空。

1) 保存某个会话的文本草稿

如果这个会话已经有草稿了,保存新的草稿将会覆盖旧的草稿。

/*!
 *  @brief 保存某个会话的文本草稿
 *  @param conversationType 会话类型。类型值参考UCS_IM_ConversationType
 *  @param targetId         会话id,单聊为对方的id,讨论组聊天为讨论组id,群组聊天为群组id
 *  @param content          文本草稿
 *  @return 操作结果的bool值
 */
- (BOOL)saveTextMessageDraft:(UCS_IM_ConversationType)conversationType
                    targetId:(NSString *)targetId
                    content:(NSString *)content;

云之讯IMDEMO参考代码:

[[UCSIMClient sharedIM] saveTextMessageDraft:_chatType targetId:_chatter content:draft];

2) 获取某个会话的文本草稿

如果这个会话没有草稿,会返回nil

/*!
 *  @brief 获取某个会话的文本草稿
 *  @param conversationType 会话类型。类型值参考UCS_IM_ConversationType
 *  @param targetId         会话id,单聊为对方的id,讨论组聊天为讨论组id,群组聊天为群组id
 *  @return 文本草稿。如果没有,为空。
 */
- (NSString *)getTextMessageDraft:(UCS_IM_ConversationType)conversationType
                         targetId:(NSString *)targetId;

云之讯IMDEMO参考代码:

NSString * draft = [[UCSIMClient sharedIM] getTextMessageDraft:_chatType targetId:_chatter];

3) 清除某个会话的文本草稿

当某个会话的文本草稿已经被使用,且不再需要,请调用这个方法将文本草稿清空。

/*!
 *  @brief 清除某个会话的文本草稿
 *  @param conversationType 会话类型。类型值参考UCS_IM_ConversationType
 *  @param targetId         会话id,单聊为对方的id,讨论组聊天为讨论组id,群组聊天为群组id
 *  @return 操作结果的bool值
 */
- (BOOL)clearTextMessageDraft:(UCS_IM_ConversationType)conversationType

云之讯IMDEMO参考代码

[[UCSIMClient sharedIM] clearTextMessageDraft:_chatType targetId:_chatter];

3.4、消息操作

云之讯IMSDK的消息类为UCSMessage。UCSMessage类包含描述一条消息的所有属性。比如消息发送时间、发送者、接收者、消息内容等。对这个类的属性进行解析,获取我们所需的内容,如消息的内容,保存在这个类的content属性中,而content这个属性是所有消息类型的基类,它的子类包括文本消息,图片消息,语音消息,地图消息等,我们可以先判断消息的类型,再相应地获取消息的内容。

具体的消息内容子类有:

UCSTextMsg.h                 文本消息类
UCSImageMsg.h	             图片消息类
UCSVoiceMsg.h                语音消息类
UCSDiscussionNotification.h  讨论组通知消息类
UCSLocationMsg.h             地理位置消息
UCSCustomMsg.h               自定义消息类
UCSUnknownMsg.h              未知消息类型

当你收到IMSDK传上来的消息时,content属性里面会存一个具体的消息内容子类的对象。比如你收到一条文本消息,content中存储的将会是一个UCSTextMsg类型的对象。

云之讯IMSDK对外提供了一个消息发送方法,所有类型的消息发送都使用这一个方法,并通过参数传值来区分发送的类型。SDK提供的方法:

/*!
 *  @brief  发送一条聊天消息
 *  @discussion 云之讯所有的消息发送都使用这个方法,根据不同的参数来区分不同的消息类型。
 *  @param conversationType 这条消息对应的会话的类型。这个参数用来区分这条消息是什么场景下产生的。现在暂时有单聊、群聊、讨论组三中会话类型。比如一对一单聊,设为UCS_IM_SOLOCHAT。具体参考UCS_IM_ConversationType
 *  @param receiveId        聊天对象的id。这个参数用来标识这条消息发到哪里,单聊发给某个人,群聊发给某个讨论组或者某个群。单聊设置为对方的id,讨论组设置为讨论组id,群聊设置为群id。
 *  @param msgType          消息的类型。这个参数用来标识这条消息的类型。比如文本消息,设置为UCS_IM_TEXT。具体参考UCS_IM_MsgType
 *  @param content          消息实体。这个参数存储发送的内容。UCSMsgContent是一个消息基类,这里传入一个继承UCSMsgContent的子类的对象。比如发送文本消息时,传入UCSTextMsg类型的对象。注意:这里传的内容对象的类型必须和前一个参数msgType类型对应。比如不允许前一个参数传文本类型,后一个参数传图片,否知会出现错误。
 *  @param success          发送消息成功的Block回调。回调中会返回发送成功的消息id,拿到这个id可以做一些自定义的处理。比如刷新消息的发送状态。
 *  @param failure            发送消息失败的Block回调。回调中会返回发送失败的消息id和发送失败的错误码,自定义处理。
 *  @return 发送的message。此时消息的发送状态为发送中,需要根据success回调和error回调来改变消息的发送状态。
 *  注意:如果发送的参数不符合要求,会回调失败。发送的文本长度不能超过1500。当发送语音消息时,语音大小不要超120kB,否则会丢失部分语音内容。
 */
- (UCSMessage *)sendMessage:(UCS_IM_ConversationType)conversationType
                  receiveId:(NSString *)receiveId
                    msgType:(UCS_IM_MsgType)msgType
                    content:(UCSMsgContent *)content
                    success:(void (^)(long long messageId))success
                    failure:(void (^)(UCSError *error, long long messageId))failure;

1) 发送文本、表情消息

云之讯IMDEMO参考代码:

UCSTextMsg *aText = [[UCSTextMsg alloc]init];
 //转换内置字符串为通用字符串
 NSString * aliasedString =  [text aliasedString];
 aText.content = aliasedString;
 return [[UCSIMClient sharedIM]sendMessage:conversationType receiveId:targetId msgType:UCS_IM_TEXT content:aText success:^(long long messageId) {
	//发送成功
} failure:(void (^)(UCSError *error, long long messageId)) {
	//发送失败
        }
}];

2) 发送图片消息

云之讯IMDEMO参考代码:

UCSImageMsg * imageMsg = [[UCSImageMsg alloc]init];
imageMsg.originalImage = image;
return  [[UCSIMClient sharedIM] sendMessage:conversationType receiveId:targetId msgType:UCS_IM_IMAGE content:imageMsg success:^(long long messageId) {
        //发送成功
    } failure:(void (^)(UCSError *error, long long messageId)) {
        //发送失败
}];

3) 发送语音消息

云之讯IMDEMO参考代码:

NSData *data = [NSData dataWithContentsOfFile:voicePath];
NSMutableData *voiceData = [NSMutableData dataWithData:data];
UCSVoiceMsg * voiceMsg = [[UCSVoiceMsg alloc] init];
voiceMsg.wavAudioData = voiceData;
voiceMsg.duration = (duration >= 1.0)? duration : 1.0;
return [[UCSIMClient sharedIM] sendMessage:conversationType receiveId:targetId msgType:UCS_IM_VOICE content:voiceMsg success:^(long long messageId) {
        //发送成功
} failure:(void (^)(UCSError *error, long long messageId)) {
       //发送失败
}];

4) 发送地理位置消息

云之讯IMDEMO参考代码:

UCSLocationMsg * locationMsg = [[UCSLocationMsg alloc]init];
locationMsg.thumbnailImage = image;
locationMsg.latitude = latitude;
locationMsg.longitude = longitude;
locationMsg.address = address;
return [[UCSIMClient sharedIM] sendMessage:conversationType receiveId:targetId msgType:UCS_IM_Location content:locationMsg success:^(long long messageId) {
        //发送成功
} failure:(void (^)(UCSError *error, long long messageId)) {
       //发送失败
}];

5) 发送自定义消息

云之讯IMDEMO参考代码:

// base64加密这段文字,GTMBase64是一个开源加密库,开发者可以选择任意加密方式。
NSString *text = @"开发者可以根据自己的需求,将图片、语音、文本等数据加密成NSData类型的数据,构建自定义消息。云之讯SDK只负责传输这条消息,加密、解密的过程完全由开发者完成。"
NSString * base64Str = [GTMBase64 encodeBase64String:text];
NSData * data = [base64Str dataUsingEncoding:NSUTF8StringEncoding];
 
//构建自定义消息
UCSCustomMsg * customMsg = [[UCSCustomMsg alloc] initWithData:data];
[[UCSIMClient sharedIM] sendMessage:<#(UCS_IM_ConversationType)#> receiveId:<#(NSString *)#> msgType:UCS_IM_Custom content:customMsg success:^(long long messageId) {
     //success, do somethings
} failure:^(UCSError *error, long long messageId) {
    //failed, do somethings
}]

6) 获取最近的聊天消息

使用场景:当我们进入一个会话的时候,我们希望将最近的聊天记录展示出来,方便用户查看。如果这个会话的聊天信息很多,该接口的最后一个参数可以控制获取最近消息的数量。

 /*!
 *  @brief 获取最新的消息.用于进入聊天界面后第一次加载消息
 *  @discussion 这个方法用于进入聊天界面第一次加载消息时候调用,如果下拉加载更多消息的时候请使用下面的 -getLatestMessages:targetId:count: 方法
 *  @param conversationType 会话类型。类型值参考UCS_IM_ConversationType
 *  @param targetId         会话id
 *  @param count            需要获取的消息数量。默认获取10条。也可以自己设置,如果该会话的消息总数小于设置的count数,则返回该会话的消息总数。
 *  @return 消息数组。数组中元素的类型是
 */
- (NSArray *)getLatestMessages:(UCS_IM_ConversationType)conversationType
                      targetId:(NSString *)targetId
                         count:(int)count;

云之讯IMDEMO参考代码:

NSArray * messages = [[UCSIMClient sharedIM] getLatestMessages:_chatType targetId:_chatter count:10];

7) 获取更多的聊天信息

当一个会话的聊天信息很多,我们需要看更早的信息时,可以调用下面这个方法拉取更多的聊天消息。即获取历史消息。数组内的第一个元素为时间最早的聊天消息。

/*!
 *  @brief 获取更多的消息。用于聊天界面中加载更多消息。
 *  @discussion 这个方法用于聊天界面中下拉加载更多消息时候调用。进入聊天界面第一次加载消息请使用上面的 - getLatestMessages:targetId:count: 方法。
 *  @param conversationType 会话类型。类型值参考UCS_IM_ConversationType
 *  @param targetId         会话id
 *  @param oldestMessageId  当前已经请求好的消息中最早的那条消息的消息id。
 *  @param count            需要获取的消息数量
 *  @return 消息数组
 */
- (NSArray *)getHistoryMessages:(UCS_IM_ConversationType)conversationType
                       targetId:(NSString *)targetId
                oldestMessageId:(long long)oldestMessageId
                          count:(int)count;

云之讯IMDEMO参考代码:

UCSMessage * firstModel = [_messages firstObject];
long long oldestMessageId = firstModel.messageId;
NSArray * oldMessages = [[UCSIMClient sharedIM] getHistoryMessages:_chatType targetId:_chatter oldestMessageId:oldestMessageId count:10];

8) 删除一个会话的所有聊天记录

/*!
 *  @brief 删除一条指定的消息
 *  @discussion 这个方法一般用于聊天界面删除一条消息,删除后这条消息在数据库中也会被删除。
 *  @param conversationType 会话类型。类型值参考UCS_IM_ConversationType
 *  @param targetId         会话id
 *  @param messageId        消息id
 *  @return 操作结果的bool值
 */
- (BOOL)deleteMessages:(UCS_IM_ConversationType)conversationType
              targetId:(NSString *)targetId
messageId:(long long)messageId;

云之讯IMDEMO参考代码:

[[UCSIMClient sharedIM] deleteMessages:_chatType targetId:_chatter messageId:model.messageId];

9) 设置接收到的某条消息在本地的接收状态(用于判断语音消息是否已读)

用于判断语音消息是否已读。当收到语音消息时,你可能需要提醒用户点击收听语音。用户听完后,需要在UI上告诉用户这条语音已经听过了,不需要重复收听。UCSMessage提供了receivedStatus属性来标识消息的接收状态。receivedStatus的类型是一个枚举类型。

/*!
 @enum
 @brief    聊天消息接收状态
 @constant ReceivedStatus_UNREAD     未读(如果是语音消息,那么语音已经下载成功)
 @constant ReceivedStatus_READ       已读
 @constant ReceivedStatus_LISTENED   已听(用于语音消息)
 @constant ReceivedStatus_DOWNLOADED 已下载(用于语音消息)
 @constant ReceivedStatus_DOWNLOADING   正在下载(用于语音消息)
 @constant ReceivedStatus_DOWNLOADFail 下载失败(用于语音消息)
 @constant
 */
typedef enum{
    ReceivedStatus_UNREAD = 0,
    ReceivedStatus_READ = 1,
    ReceivedStatus_LISTENED = 2,
    ReceivedStatus_DOWNLOADED = 3,
    ReceivedStatus_DOWNLOADING = 4,
    ReceivedStatus_DOWNLOADFail = 5,
}UCSReceivedStatus;

你可以调用下面这个方法来改变消息的接收状态:

/*!
 *  @brief 设置接收到的某条消息在本地的接收状态,目前只用于语音消息,具体参考UCSReceivedStatus
 *  @param conversationType 会话类型。类型值参考UCS_IM_ConversationType
 *  @param targetId          会话id
 *  @param messageId        消息id
 *  @param receivedStatus   要设置的状态,已读或者未读,用于语音消息是否播放。
 *  @return 操作结果的bool值
 */
-(BOOL)setMessageReceivedStatus:(UCS_IM_ConversationType)conversationType
                       targetId:(NSString *)targetId
                      messageId:(long long)messageId
                 receivedStatus:(UCSReceivedStatus)receivedStatus;

云之讯IMDEMO参考代码:

BOOL read =  [[UCSIMClient sharedIM] setMessageReceivedStatus:ucsmessage.conversationType     targetId:targetId  messageId:messageModel.messageId receivedStatus:ReceivedStatus_LISTENED];

3.5、讨论组操作

1) 创建一个讨论组

/*!
 *  @brief 主动创建一个讨论组
 *  @discussion 这个方法用来主动创建一个讨论组。成功block回调返回一个讨论组,失败block回调返回错误码。创建成功后,创建者会自动变成讨论组的所有者,拥有对讨论组操作的最高权限。
 *  @param topic       创建后的讨论组主题(讨论组名),如果不传,讨论组名称就为空。
 *  @param memberArray 创建时需要邀请到讨论组的成员数组(不需要把自己加进去),数组中每个元素为UCSUserInfo类的对象。UCSUserInfo的实体userId字段必填,若用用自己的服务器维护的用户其他字段在知道的情况下尽量填写。
 *  @param success     创建成功。block回调返回创建成功的讨论组
 *  @param failure       创建失败。block回调返回错误码。
 */
- (void)createDiscussionWithTopic:(NSString *)topic
                      memberArray:(NSArray *)memberArray
                          success:(void (^)(UCSDiscussion *discussion))success

云之讯IMDEMO参考代码:

[[UCSIMClient sharedIM] createDiscussionWithTopic:topic memberArray:memberArray success:^(UCSDiscussion *discussion) {
        [MBProgressHUD hideHUDForView:self.view animated:YES];
        [MBProgressHUD showSuccess:@"创建成功" toView:self.view];
} failure:^(UCSError * error) {
        [MBProgressHUD hideHUDForView:self.view animated:YES];
        [MBProgressHUD showError:@"创建失败" toView:self.view]; 
}];

2) 讨论组添加成员

/*!
 *  @brief 给已经存在的讨论组添加新的用户
 *  @discussion  这个方法用来给一个已经存在的讨论组添加新的成员,如果用户无权限进行操作会失败。
 *  @param discussionId 讨论组id
 *  @param memberArray  要新加的成员的数组,数组中的每个元素为UCSUserInfo类的对象。UCSUserInfo的实体userId字段必填,若用用自己的服务器维护的用户其他字段在知道的情况下尽量填写。
 *  @param success      添加成功.回调中返回修改后的讨论组
 *  @param error        添加失败.回调中返回错误码
 */
- (void)addMemberToDiscussionWithDiscussionId:(NSString *)discussionId
                                  memberArray:(NSArray *)memberArray
                                      success:(void (^)(UCSDiscussion *discussion))success
                                      failure:(void (^)(UCSError * error))failure;

云之讯IMDEMO参考代码:

[[UCSIMClient sharedIM] addMemberToDiscussionWithDiscussionId:_targetId memberArray:memberArray success:^(UCSDiscussion *discussion) {
        [MBProgressHUD hideHUDForView:self.view animated:YES];
        [MBProgressHUD showSuccess:@"添加成员成功" toView:self.view];
} failure:^(UCSError * error) {
        [MBProgressHUD hideHUDForView:self.view animated:YES];
        [MBProgressHUD showError:@"添加成员失败" toView:self.view];
}];

3) 讨论组删除成员

/*!
 *  @brief 在讨论组中移除已经存在的用户
 *  @discussion 这个方法用来删除一个存在的讨论组中存在的成员,如果用户无权限进行操作会失败。
 *  @param discussionId 讨论组id
 *  @param memberArray  要移除的用户的数组,数组中的每个元素为UCSUserInfo类的对象。UCSUserInfo的实体只需填充userId字段即可。
 *  @param success      移除成功.回调中返回修改后的讨论组
 *  @param error        移除失败.回调中返回错误码
 */
- (void)removeMemberFromDiscussionWithDiscussionId:(NSString *)discussionId
                                       memberArray:(NSArray *)memberArray
                                           success:(void (^)(UCSDiscussion *discussion))success
                                           failure:(void (^)(UCSError * error))failure;

云之讯IMDEMO参考代码

[[UCSIMClient sharedIM] removeMemberFromDiscussionWithDiscussionId:_targetId memberArray:memberArray success:^(UCSDiscussion *discussion) {
      [MBProgressHUD hideHUDForView:self.view animated:YES];
      [MBProgressHUD showSuccess:@"移除成员成功" toView:self.view];
} failure:^(UCSError * error){
      [MBProgressHUD hideHUDForView:self.view animated:YES];
      [MBProgressHUD showError:@"移除成员失败" toView:self.view];
}];

4) 修改讨论组的名称

/*!
 *  @brief 修改讨论组的主题(讨论组名称)
 *  @param discussionId 讨论组id
 *  @param newTopic     新的主题
 *  @param success      修改成功。回调中返回修改后的讨论组。
 *  @param errorBlock   修改失败。回调中返回失败的错误码
 */
- (void)setDiscussionTopicWithDiscussionId:(NSString *)discussionId
                                  newTopic:(NSString *)newTopic
                                   success:(void (^)(UCSDiscussion *discussion))success
                                   failure:(void (^)(UCSError * error))failure;

云之讯IMDEMO参考代码:

[[UCSIMClient sharedIM] setDiscussionTopicWithDiscussionId:_targetId newTopic:newName success:^(UCSDiscussion *discussion){ 
   [MBProgressHUD hideHUDForView:self.view animated:YES];
   [MBProgressHUD showSuccess:@"修改讨论组名称成功" toView:self.view]; 
} failure:^(UCSError * error) { 
   [MBProgressHUD hideHUDForView:self.view animated:YES];
   [MBProgressHUD showError:@"修改讨论组名称失败" toView:self.view];
}];

5) 退出讨论组

/*!
 *  @brief 主动退出讨论组
 *  @param discussionId 讨论组id
 *  @param success      退出成功
 *  @param error        退出失败。回调中返回错误码
 */
- (void)quitDiscussionWithDiscussionId:(NSString *)discussionId
                               success:(void (^)(UCSDiscussion *discussion))success
                               failure:(void (^)(UCSError * error))failure;

云之讯IMDEMO参考代码:

[[UCSIMClient sharedIM] quitDiscussionWithDiscussionId:_targetId success:^(UCSDiscussion *discussion) { 
      [MBProgressHUD hideHUDForView:self.view animated:YES];
      [MBProgressHUD showSuccess:@"已经退出了讨论组"];
} failure:^(UCSError * error) {
     [MBProgressHUD hideHUDForView:self.view animated:YES];
     [MBProgressHUD showSuccess:@"退出讨论组失败" toView:self.view]; 
}];

6) 获取讨论组

/*!
 *  @brief 获取一个存在的讨论组
 *  @param targetId 讨论组id
 *  @return 讨论组
 */
- (UCSDiscussion *)getDiscussionInfoWithDiscussionId:(NSString *)targetId;

云之讯IMDEMO参考代码:

_discussion = [[UCSIMClient sharedIM] getDiscussionInfoWithDiscussionId:_targetId];

7) 获取所有讨论组

/*!
 *  @brief  获取当前账号加入的所有讨论组,返回一个数组,其中的每个元素是一个UCSDiscussion类型的对象
 *  @return 返回加入的所有讨论组.如果当前账号没有加入任何讨论组,则数组为空。
 */ 
- (NSArray *)getDiscussions;

云之讯IMDEMO参考代码:

NSArray * conversationLists = [[UCSIMClient sharedIM] getDiscussions];

8) 自己被踢出某个讨论组时的回调

/*!
 *  @brief 当自己被移除出某个讨论组的时候回调。(自己主动退出也会调用这个方法)。
 *  @param discussionID  对应的讨论组id
 */
- (void)didRemoveFromDiscussionWithDiscussionId:(NSString *) discussionID;

注意:这个方法为UCSIMClientDelegate的代理方法,实现该方法的类应该遵守UCSIMClientDelegate协议并且为IMClient的代理。 云之讯IMDEMO参考代码:

- (void)didRemoveFromDiscussionWithDiscussionId:(NSString *) discussionID
{
  DDLogWarn(@"你被踢出了讨论组 , 讨论组id为: %@", discussionID);
  [[NSNotificationCenter defaultCenter] postNotificationName:RemovedADiscussionNotification object:discussionID];
}

9) 讨论组相关操作异常情况

讨论组操作失败,可能原因:

1、 操作一个不存在的讨论组

2、 没有权限

3、 网络、服务器异常。

3.6、群组

云之讯SDK仅仅是提供群组消息的收发功能(SDK提供了讨论组的管理功能,参考讨论组章节),群组的建立、解散等操作,需用户AS服务器处理。用户也可以使用云之讯AS SDK自定义开发AS服务器(由云之讯提供硬件资源),详见云之讯IM-Rest接口使用说明书。

4、常见疑问

1、SDK为什么没有提供获取好友列表的接口:

答:由于我们的产品是面向企业的,SDK的使用场景也是面向各个App的,每个企业的App都有自己的用户,为了不打乱App原有的用户体系,所以好友列表由企业自己管理。

2、SDK没有提供新建会话接口,怎么样建立一个会话:

答:接收到消息或者发送成功一条消息时,会自动创建一个会话。(发送消息时若为单聊,那receiveId 直接填写对方的手机号码即可)。

3、我下载的IMSDK包里面,为什么有TCP与IM两个库?

答:因为IM的库是依赖于TCP的库运行的,所以集成IM功能需要IMSDK和TCPSDK两个库。

4、下载的SDK同时支持在模拟器和真机上运行吗?

答:已支持。

5、离线推送功能未能实现,失效。

答:首先检查推送证书是否错误,再检查一下代码中设置的离线推送环境与离线推送证书的类型是否统一,苹果下发的deviceToken是否按要求保存。

5、错误码

400000	没有错误				ErrorCode_NoError
401000	未知错误				ErrorCode_UnKnown
401100	连接服务器失败			ErrorCode_ConnectToServerFail
401101	超时				ErrorCode_TIMEOUT 
4001102	被别人踢下线			ErrorCode_BeClicked
4001103	无效的token或者与appid不符合	ErrorCode_InvalidToken
4001104	用户不存在			ErrorCode_InvalidUser
4001105	密码错误		                ErrorCode_IncorrectPassword
4023000	无效的消息,null或者nil	        ErrorCode_InvalidMessage
402301	无效的群组,传入的群组不存在	ErrorCode_InvalidGroud
402302	无效的讨论组,传入的讨论组不存在	ErrorCode_InvalidDiscussion
402303	修改讨论组名字失败	        ErrorCode_UpdateDiscussionNameFail
402304	创建讨论组失败	                ErrorCode_CreateDiscussionFail
402305	用户不在群组中	                ErrorCode_MemberIsNotInGroud
402306	用户不在讨论组中	                ErrorCode_MemberIsNotInDiscussion
402307	删除成员失败		        ErrorCode_DeleteMemberFail
402308	邀请成员失败		        ErrorCode_AddMemberFail
402309	文件上传失败		        ErrorCode_UploadFileFail
402310	文件下载失败		        ErrorCode_downLoadFileFail
402311	录音时间过短                     ErrorCode_RecoderTooShort
402312	文件格式不支持	                ErrorCode_FileFormatIsNotSupported
402313	消息内容过长			ErrorCode_MessageLengthTooLong
402314	读取本地数据库失败	        ErrorCode_SelectFromDataBaseFail 
402315	写入、更新数据库失败	        ErrorCode_UpdateDataBaseFail
402316	发送消息失败		        ErrorCode_SendMessageFail
402317	发送消息超时		        ErrorCode_SendMessageTimeOut
402318	成员列表错误	            	ErrorCode_MembersError
402319	退出讨论组错误	                ErrorCode_ExitDiscussionError
403600	参数错误			        ErrorCode_MethodParamError
403601	消息格式错误	              	ErrorCode_MessageTypeError
403602	网络未连接	              	ErrorCode_NetworkIsNotConnected 
403603	初始化加载失败(包括数据库加载)	ErrorCode_InitError
403604	服务器重连失败	                ErrorCode_ReConnectToServerFail
403605	错误IP地址		        ErrorCode_ErrorIPAddress 
403606  包解析错误                       ErrorCode_PacketParsingError

页面工具