如果是使用OpenIMCore集成,IMSDK为你提供消息通道的能力,即消息发送和消息接收。
你可以基于消息通道的能力,自己完成消息的发送、存储、显示等过程,继而为用户提供IM沟通的能力。
要使用消息通道的基础能力,你只需要关注下面这几个步骤:初始化、登录、发消息、收消息等。
/**
* 初始化示例代码
*/
- (BOOL)exampleInit;
{
/// 设置环境
[[YWAPI sharedInstance] setEnvironment:YWEnvironmentRelease];
/// 开启日志
[[YWAPI sharedInstance] setLogEnabled:YES];
NSLog(@"SDKVersion:%@", [YWAPI sharedInstance].YWSDKIdentifier);
NSError *error = nil;
/// 异步初始化IM SDK
#warning TODO: CHANGE TO YOUR AppKey
[[YWAPI sharedInstance] syncInitWithOwnAppKey:@"23015524" getError:&error];
if (error.code != 0 && error.code != YWSdkInitErrorCodeAlreadyInited) {
/// 初始化失败
return NO;
} else {
if (error.code == 0) {
/// 首次初始化成功
/// 获取一个IMCore并持有
self.IMCore = [[YWAPI sharedInstance] fetchNewIMCoreForOpenIM];
} else {
/// 已经初始化
}
return YES;
}
}
syncInitWithOwnAppKey:getError:方法进行初始化【YWAPI.h】fetchNewIMCoreForOpenIM接口获取并保存YWIMCore的实例,你可以使用YWIMCore的实例建立消息通道。【YWAPI.h】IMSDK的登录有几个概念:
预登录
预登录的作用,是为了能在登录成功之前就打开本地数据库,为用户展示本地聊天数据。
所以一般你可以根据业务的需要,在允许用户查看聊天数据时,就使用调用预登录的接口,如果预登录成功,即可显示本地数据。
真正登录
无论预登录是否成功,你都需要发起真正登录,才能与IM服务器建立连接,收发IM消息。
请参考:官方demo中callThisAfterISVAccountLoginSuccessWithYWLoginId:passWord:preloginedBlock:successBlock:failedBlock:方法。
登录时机【重要,务必理解下述内容】:
asyncLoginWithCompletionBlock:接口发起登录,IMSDK不会做自动登录。/**
* 预登陆
*/
- (void)examplePreLoginWithLoginId:(NSString *)loginId successBlock:(void(^)())aPreloginedBlock
{
/// 预登录
if ([[self.ywIMKit.IMCore getLoginService] preLoginWithPerson:[[YWPerson alloc] initWithPersonId:loginId]]) {
/// 预登录成功,直接进入页面,这里可以打开界面
if (aPreloginedBlock) {
aPreloginedBlock();
}
}
}
/**
* 登录的示例代码
*/
- (void)exampleLoginWithUserID:(NSString *)aUserID password:(NSString *)aPassword successBlock:(void(^)())aSuccessBlock failedBlock:(void (^)(NSError *))aFailedBlock
{
aSuccessBlock = [aSuccessBlock copy];
aFailedBlock = [aFailedBlock copy];
/// 登录之前,先告诉IM如何获取登录信息。
/// 当IM向服务器发起登录请求之前,会调用这个block,来获取用户名和密码信息。
[[self.ywIMKit.IMCore getLoginService] setFetchLoginInfoBlock:^(YWFetchLoginInfoCompletionBlock aCompletionBlock) {
aCompletionBlock(YES, aUserID, aPassword, nil, nil);
}];
/// 发起登录
[[self.ywIMKit.IMCore getLoginService] asyncLoginWithCompletionBlock:^(NSError *aError, NSDictionary *aResult) {
if (aError.code == 0 || [[self.ywIMKit.IMCore getLoginService] isCurrentLogined]) {
/// 登录成功
#ifdef DEBUG
[[SPUtil sharedInstance] showNotificationInViewController:self.rootWindow.rootViewController title:@"登录成功" subtitle:nil type:SPMessageNotificationTypeSuccess];
#endif
if (aSuccessBlock) {
aSuccessBlock();
}
} else {
/// 登录失败
[[SPUtil sharedInstance] showNotificationInViewController:self.rootWindow.rootViewController title:@"登录失败" subtitle:aError.description type:SPMessageNotificationTypeError];
if (aFailedBlock) {
aFailedBlock(aError);
}
}
}];
}
setFetchLoginInfoBlock:设置获取登录信息的回调。一般地,你需要在这个回调里先获取该用户的昵称,成功后再调用aCompletionBlock,将userId、password、displayName等信息告知IMSDK。(昵称用于对方收到系统推送时显示)【IYWLoginService.h】asyncLoginWithCompletionBlock:真正发起登录【IYWLoginService.h】注意: 目前要求登录操作,必须在主线程调用(底层CoreData的NSFetchedResultsController需要在主线程创建才能在主线程回调),否则一些回调比如未读数变更的回调,将会无效。
你可以通过IYWLoginService.h中的- (BOOL)hasLoginThread函数判断是否已经发起登录。
- (void)sendImageMessageData:(NSData *)imageData
{
/// 构造消息体
YWMessageBodyImage *imageMessageBody = [[YWMessageBodyImage alloc] initWithMessageImageData:imageData];
/// 获取会话
YWP2PConversation *conv = [YWP2PConversation fetchConversationByPerson:[[YWPerson alloc] initWithPersonId:@"uid1"] creatIfNotExist:YES baseContext:self.IMCore];
/// 发送消息
[conv asyncSendMessageBody:imageMessageBody controlParameters:nil progress:^(CGFloat progress, NSString *messageID) {
/// 更新消息进度显示
} completion:^(NSError *error, NSString *messageID) {
if (error) {
/// 消息发送失败,提示用户
}
}];
}
消息发送控制asyncSendMessageBody:progress:completion:方法发送消息。[[self.IMCore getConversationService] addOnNewMessageBlockV2:^(NSArray *aMessages, BOOL aIsOffline) {
[aMessages enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * stop) {
id<IYWMessage> message = [obj conformsToProtocol:@protocol(IYWMessage)] ? obj : nil;
if (message) {
/// 处理消息
}
}];
} forKey:self.description ofPriority:YWBlockPriorityDeveloper];
aMessages数组中的每一个对象都是遵循IYWMessage协议的对象,你可以从中获取到消息的具体信息。目前账号设置支持单聊、群聊的消息接收设置和开发者自定义设置,方法声明在YWIMCore层中的IYWSettingService中,这个头文件中的方法分为同步方法和异步方法,同步方法只获取本地的数据,异步方法则需要发送网络请求。
开发者可以通过
/** * 将本地的消息接收设置更新至服务端的状态,sdk内部每24h同步一次,开发者可以视自己需求调用 */ - (void)syncMessageSettingFromServerWithompletionBlcok:(YWCompletionBlock)aCompletion;
来同步服务端的设置,同步成功后开发者可以在aCompletion中通过调用同步方法来获取本地的数据。
单聊消息可以设置在后台时消息是否PUSH,屏蔽单聊消息则是通过更多功能中的黑名单来实现的。
/// 获取person 发送的消息后台是否push - (BOOL)getMessagePushEnableForPerson:(YWPerson *)person; /// 异步设置person 发送的消息后台是否push - (void)asyncSetMessagePushEnable:(BOOL)enable ForPerson:(YWPerson *)person completion:(YWCompletionBlock)aCompletion;
群聊消息可以分别设置群普通消息的接收和群@消息的接收方式,需要注意的是,群普通消息分为接收并PUSH、接收不PUSH和不接收三种,而群@消息只有接收并PUSH和不接收两种,其取值参考IYWSettingServiceDef中的YWMessageFlag和YWAtMessageFlag两个枚举:
typedef NS_ENUM(NSInteger, YWMessageFlag) {
YWMessageFlagNotReceive, // 屏蔽消息
YWMessageFlagReceiveButNoAlert, // 前台在线时接收消息,后台不push
YWMessageFlagReceive, // 正常接收消息,后台有push
};
typedef NS_ENUM(NSInteger, YWAtMessageFlag) {
YWAtMessageFlagNotReceive, // 屏蔽消息
YWAtMessageFlagReceive, // 正常接收消息,后台有push
};
群消息设置的方法较多,开发者可以移步IYWSettingService头文件中查看。
云旺提供了开发者保存自定义设置的功能,客户端和服务器均为透传,当开发者需要多端同步自定义设置时,可以通过
/** * 获取开发者自定义的设置项 */ - (NSDictionary *)getExtraSettings; /** * 异步设置自定义设置项,服务端只负责保存,不会进行解析 */ - (void)asyncSetExtraSettings:(NSDictionary *)settings completion:(YWCompletionBlock)aCompletion;
来获取和设置。
IMSDK提供了消息发送控制的能力,你利用YWConversation.h中消息发送接口携带的controlParameters参数,控制对方iOS设备接收消息的推送文案、推送声音、是否需要推送等,也可以控制消息仅存本地而不发送到对方。
如下面的代码所示,通过controlParameters参数,控制了对方收到推送的推送文案,你还可以控制是否弹出Push、Push的声音等等,详见:YWConversationServiceDef.h
/**
* 发送透传指令
* 并且展示了如何在客户端控制对方iOS设备收到的Push文案
* 不显示在会话列表和聊天页面,开发者可以监听到该消息,做特定的逻辑处理
*/
- (void)exampleSendTransparentCommand:(NSString *)aCommand inConversation:(YWConversation *)aConversation completion:(YWMessageSendingCompletionBlock)aCompletion
{
YWMessageBodyCustomize *body = [[YWMessageBodyCustomize alloc] initWithMessageCustomizeContent:aCommand summary:@"阅后即焚" isTransparent:YES];
/// 控制对方收到的Push文案,你还可以控制推送声音,是否需要push等,详见:YWConversationServiceDef.h
NSDictionary *controlParameters = @{kYWMsgCtrlKeyPush:@{kYWMsgCtrlKeyPushKeyHowToPush:@{kYWMsgCtrlKeyPushKeyHowToPushKeyTitle:@"请务必阅后即焚"}}};
[aConversation asyncSendMessageBody:body controlParameters:controlParameters progress:NULL completion:aCompletion];
}
/**消息控制字段定义**/
/**
**示例**
@{
kYWMsgCtrlKeyPush:@{
kYWMsgCtrlKeyPushKeyNeedPush:@(1),
kYWMsgCtrlKeyPushKeyHowToPush:@{
kYWMsgCtrlKeyPushKeyHowToPushKeyTitle:@"推送文案自定义",
kYWMsgCtrlKeyPushKeyHowToPushKeySound:@"customsound.caf",
kYWMsgCtrlKeyPushKeyHowToPushKeyData:@"推送透传数据",
},
},
kYWMsgCtrlKeyClientLocal:@{kYWMsgCtrlKeyClientLocalKeyOnlySave:@(YES)}, /// 本地保存
}
*******
*/
/// 推送控制
/// 值一个字典,控制推送。该字典包含:kYWMsgCtrlKeyPushKeyNeedPush、kYWMsgCtrlKeyPushKeyHowToPush
FOUNDATION_EXTERN NSString *const kYWMsgCtrlKeyPush;
/// 值为一个整数,控制是否推送:没有这个key为需要推送,@(1)为需要推送,@(0)为不需要推送
FOUNDATION_EXTERN NSString *const kYWMsgCtrlKeyPushKeyNeedPush;
/// 值为一个字典,控制推送样式。该字典包含:kYWMsgCtrlKeyPushKeyHowToPushKeyTitle、kYWMsgCtrlKeyPushKeyHowToPushKeySound、kYWMsgCtrlKeyPushKeyHowToPushKeyData
FOUNDATION_EXTERN NSString *const kYWMsgCtrlKeyPushKeyHowToPush;
/// 值为字符串,控制推送文案
FOUNDATION_EXTERN NSString *const kYWMsgCtrlKeyPushKeyHowToPushKeyTitle;
/// 值为字符串,控制推送声音文件
FOUNDATION_EXTERN NSString *const kYWMsgCtrlKeyPushKeyHowToPushKeySound;
/// 值为字符串,控制推送携带的数据
FOUNDATION_EXTERN NSString *const kYWMsgCtrlKeyPushKeyHowToPushKeyData;
/// 值为一个字典,控制客户端本地行为。该字典包含:kYWMsgCtrlKeyClientLocalKeyOnlySave
FOUNDATION_EXTERN NSString *const kYWMsgCtrlKeyClientLocal;
/// 值为一个bool值,控制该消息仅保存本地,不发送到服务器。无此key或者@(0)则为需要发送,@(1)则为仅保存本地
FOUNDATION_EXTERN NSString *const kYWMsgCtrlKeyClientLocalKeyOnlySave;
/// 值为一个bool值,控制该消息保存本地时即标记删除,但仍然发送到服务器,本地因为被标记删除所以不会显示。无此key或者@(0)则为不标记删除,@(1)则为标记删除
FOUNDATION_EXTERN NSString *const kYWMsgCtrlKeyClientLocalKeyMarkDeleted;
下面的代码展示了使用controlParameters字段控制消息不发送给对方,只在本地展示
/**
* 插入本地消息
* 消息不会被发送到对方,仅本地展示
*/
- (void)exampleInsertLocalMessageBody:(YWMessageBody *)aBody inConversation:(YWConversation *)aConversation
{
NSDictionary *controlParameters = @{kYWMsgCtrlKeyClientLocal:@{kYWMsgCtrlKeyClientLocalKeyOnlySave:@(YES)}}; /// 控制字段
[aConversation asyncSendMessageBody:aBody controlParameters:controlParameters progress:NULL completion:NULL];
}
kYWMsgCtrlKeyClientLocalKeyMarkDeleted,并设置为@(YES)示例如下:
YWConversationViewController *controller = [YWConversationViewController makeControllerWithIMKit:self.imkit conversation:conversation];
__weak typeof(controller) weakController = controller;
__weak typeof(self) weakSelf = self;
[controller setViewDidLoadBlock:^{
BOOL needToSayHi = ...; /// 根据你的需要,确定是否需要自动打招呼。一般需要判断,对方是否客服以及最近一天是否已经和客服打过招呼
NSString *hiContent = @"Hello"; /// 根据你的需要设置合适的招呼内容
if (needToSayHi) {
[weakController.conversation asyncSendMessageBody:[[YWMessageBodyText alloc] initWithMessageText:hiContent] controlParameters:@{kYWMsgCtrlKeyClientLocal:@{kYWMsgCtrlKeyClientLocalKeyMarkDeleted:@(YES)}} progress:NULL completion:NULL];
}
}];
消息透传指令用于在当前客户端发送一条消息给对方,对方收到后,不会在聊天页面或者会话页面有任何展示。你可以根据需要,监听该消息,并处理相关逻辑。
下面的代码用透传指令演示了阅后即焚的功能,对方收到消息后,展示一个弹框。(你也可以不做任何提示,仅做逻辑处理)。
/**
* 发送透传指令
* 并且展示了如何在客户端控制对方iOS设备收到的Push文案
* 不显示在会话列表和聊天页面,开发者可以监听到该消息,做特定的逻辑处理
*/
- (void)exampleSendTransparentCommand:(NSString *)aCommand inConversation:(YWConversation *)aConversation completion:(YWMessageSendingCompletionBlock)aCompletion
{
YWMessageBodyCustomize *body = [[YWMessageBodyCustomize alloc] initWithMessageCustomizeContent:aCommand summary:@"阅后即焚" isTransparent:YES];
/// 控制对方收到的Push文案,你还可以控制推送声音,是否需要push等,详见:YWConversationServiceDef.h
NSDictionary *controlParameters = @{kYWMsgCtrlKeyPush:@{kYWMsgCtrlKeyPushKeyNeedPush:@(0)}};
[aConversation asyncSendMessageBody:body controlParameters:controlParameters progress:NULL completion:aCompletion];
}
你需要监听所有消息,并可以对透传消息做特定的处理。下面的代码监听了所有消息,当消息体是透传指令时,展示一个弹框。
/**
* 监听新消息
*/
- (void)exampleListenNewMessage
{
[[self.ywIMKit.IMCore getConversationService] addOnNewMessageBlockV2:^(NSArray *aMessages, BOOL aIsOffline) {
/// 你可以在此处根据需要播放提示音
/// 展示透传消息
[aMessages enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
id<IYWMessage> msg = obj;
YWMessageBodyCustomize *body = nil;
if ([msg respondsToSelector:@selector(messageBody)]) {
body = [[msg messageBody] isKindOfClass:[YWMessageBodyCustomize class]] ? (YWMessageBodyCustomize *)[msg messageBody] : nil;
}
if (body) {
NSData *contentData = [body.content dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *contentDictionary = [NSJSONSerialization JSONObjectWithData:contentData
options:0
error:NULL];
NSString *messageType = contentDictionary[@"customizeMessageType"];
if ([messageType isEqualToString:@"yuehoujifen"] && body.isTransparent) {
NSString *text = contentDictionary[@"Text"];
if (text.length > 0) {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"阅后即焚" message:text delegate:nil cancelButtonTitle:@"朕知道了" otherButtonTitles:nil];
[av show];
});
}
}
}
}];
} forKey:self.description ofPriority:YWBlockPriorityDeveloper];
}
对于每一条发出的消息,IMSDK均会给予回调,通过如下的代码添加监听,你需要实现YWMessageLifeDelegate协议:
/**
* 监听自己发送的消息的生命周期
*/
- (void)exampleListenMyMessageLife
{
[[self.ywIMKit.IMCore getConversationService] addMessageLifeDelegate:self forPriority:YWBlockPriorityDeveloper];
}
你可以通过消息发送前的回调,进行修改消息内容、修改会话或者干脆控制不发出该消息。(影响所有消息,请务必谨慎调试)。
下面的代码展示了,所发送的消息包含违禁词语时,改为插入一条本地消息。controlParameters的定义与前面消息发送控制中的controlParameters一致。
/// 当你监听了消息生命周期,IMSDK会回调以下两个函数
- (YWMessageLifeContext *)messageLifeWillSend:(YWMessageLifeContext *)aContext
{
/// 你可以通过返回context,来实现改变消息的能力
if ([aContext.messageBody isKindOfClass:[YWMessageBodyText class]]) {
NSString *text = [(YWMessageBodyText *)aContext.messageBody messageText];
if ([text rangeOfString:@"法轮功"].location != NSNotFound) {
YWMessageBodySystemNotify *bodyNotify = [[YWMessageBodySystemNotify alloc] initWithContent:@"消息包含违禁词语"];
[aContext setMessageBody:bodyNotify];
NSDictionary *params = @{kYWMsgCtrlKeyClientLocal:@{kYWMsgCtrlKeyClientLocalKeyOnlySave:@(YES)}};
[aContext setControlParameters:params];
return aContext;
}
}
return nil;
}
- (void)messageLifeDidSend:(NSString *)aMessageId conversationId:(NSString *)aConversationId result:(NSError *)aResult
{
/// 你可以在消息发送完成后,做一些事情,例如播放一个提示音等等
}