现在大多数社交app都有消息免打扰功能,因为环信SDK主要是对即时通讯模块进行封装,因此如果要实现消息免打扰功能则需要开发者自己对此功能逻辑进行处理。
先解释一下,本人项目中对消息免打扰功能的定义:正常情况下,我们收到的每一条聊天消息都会收到小红点、声音、震动的提示。如果对某个好友设置消息免打扰功能,则只提示小红点,声音和震动则不再提示。
下面简述结合环信SDK时,此功能的实现方法。
环信将即时聊天的所有功能分为四大模块进行管理:
//聊天模块:
[EMClient sharedClient].chatManager
//好友模块 :
[EMClient sharedClient].contactManager
//群组模块 :
[EMClient sharedClient].groupManager
//聊天室模块:
[EMClient sharedClient].roomManager
消息免打扰的功能借助聊天模块[EMClient sharedClient].chatManager
的API就能实现。
一般来说,在app内不管当前在哪个界面,只要收到消息都需要被判断是否需要免打扰,因此可以在appdelegate
里写如下代码,app通常都有tabBarController
,那么也可以让tabBarController
来实现如下代码。
首先让控制器tabBarController
遵守代理EMChatManagerDelegate
然后成为代理
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];
EMChatManagerDelegate
中有一个代理方法
- (void)didReceiveMessages:(NSArray *)aMessages;
实现此代理方法
- (void)didReceiveMessages:(NSArray *)aMessages{
[self setupUnreadMessageCount];
EMMessage *message = aMessages[0];
NSString *sendPerson = message.from;
BHNavigatiomController *imNaviCV = self.viewControllers[1];
BHConversationListController *converCV = imNaviCV.viewControllers[0];
[converCV refreshDataSource];//只要收到消息就从服务器拿
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
for (NSString *hx_name in AppEngine.IMDataCent.data_ExcuseFriendsData) {
if ([hx_name isEqualToString:sendPerson]) {
return;
}
}
switch (state) {
case UIApplicationStateActive:
[self playSoundAndVibration];
break;
case UIApplicationStateInactive:
[self playSoundAndVibration];
break;
case UIApplicationStateBackground:
[self showNotificationWithMessage:message];
break;
default:
break;
}
}
方法中有一个aMessages
参数。这个参数是一个消息组,每一个元素都是EMMessage
类型的实例。
因为通常都只有一条信息。因此只需要取出EMMessage *message = aMessages[0];
EMMessage
类中有许多属性,因此根据一条信息基本可以获取想知道的所有信息。这里我们只需要知道此消息的发送方即可,也就是发送方的环信idNSString *sendPerson = message.from;
下面代码中有一AppEngine.IMDataCent.data_ExcuseFriendsData
,这个数组里面装的都是已经被设置消息免打扰的好友的环信id,是请求自己服务器获得的,获取的代码最好在一打开app时,就及时获取到。然后根据对好友免打扰设置的操作,访问后台接口进行增删,并刷新数组与后端保持一致即可。
通过[hx_name isEqualToString:sendPerson]
,遍历免打扰数组与当前消息的发送方环信id,就可以知道是否需要免打扰了。
下面附上完整代码
//
// BHTabBarController.m
// xxxxxxx
//
// Created by LiBohan on 2017/8/24.
// Copyright © 2017年 xxxxxx. All rights reserved.
//
//两次提示的默认间隔
static const CGFloat kDefaultPlaySoundInterval = 3.0;
static NSString *kMessageType = @"MessageType";
static NSString *kConversationChatter = @"ConversationChatter";
static NSString *kGroupName = @"GroupName";
#import "BHTabBarController.h"
#import <UserNotifications/UserNotifications.h>
#import "BHConversationListController.h"
@interface BHTabBarController ()<EMChatManagerDelegate>
@property (strong, nonatomic) NSDate *lastPlaySoundDate;
@end
@implementation BHTabBarController
- (void)viewDidLoad {
[super viewDidLoad];
[DemoCallManager sharedManager].mainController = self;
[[EMClient sharedClient].chatManager addDelegate:self delegateQueue:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(setupUnreadMessageCount) name:@"setupUnreadMessageCount" object:nil];
}
// 统计未读消息数
-(void)setupUnreadMessageCount
{
NSArray *conversations = [[EMClient sharedClient].chatManager getAllConversations];
NSInteger unreadCount = 0;
for (EMConversation *conversation in conversations) {
unreadCount += conversation.unreadMessagesCount;
}
NSArray *tabBarItems = self.tabBar.items;
UITabBarItem *conlistTabBarItem = [tabBarItems objectAtIndex:1];
if (unreadCount > 0) {
conlistTabBarItem.badgeValue = [NSString stringWithFormat:@"%i",(int)unreadCount];
}else{
conlistTabBarItem.badgeValue = nil;
}
// UIApplication *application = [UIApplication sharedApplication];
// [application setApplicationIconBadgeNumber:unreadCount];
}
- (void)cmdMessagesDidReceive:(NSArray *)aCmdMessages {
for (EMMessage *message in aCmdMessages) {
EMCmdMessageBody *body = (EMCmdMessageBody *)message.body;
NSLog(@"收到的action是 -- %@",body.action);
if (body.action == nil) {
return;
}
NSData *jsonData = [body.action dataUsingEncoding:NSUTF8StringEncoding];
NSError *err;
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];
if(err) {
NSLog(@"json解析失败:%@",err);
return;
}
NSNumber *num = dic[@"count"];
NSString *str = [num stringValue];
[AppEngine.IMDataCent requestUpdateUnreadNumberWithUnreadNumber:str];
}
}
- (void)didReceiveMessages:(NSArray *)aMessages{
// [self refresh];
[self setupUnreadMessageCount];
EMMessage *message = aMessages[0];
NSString *sendPerson = message.from;
BHNavigatiomController *imNaviCV = self.viewControllers[1];
BHConversationListController *converCV = imNaviCV.viewControllers[0];
// [converCV refresh];
[converCV refreshDataSource];//只要收到消息就从服务器拿
UIApplicationState state = [[UIApplication sharedApplication] applicationState];
for (NSString *hx_name in AppEngine.IMDataCent.data_ExcuseFriendsData) {
if ([hx_name isEqualToString:sendPerson]) {
return;
}
}
switch (state) {
case UIApplicationStateActive:
[self playSoundAndVibration];
break;
case UIApplicationStateInactive:
[self playSoundAndVibration];
break;
case UIApplicationStateBackground:
[self showNotificationWithMessage:message];
break;
default:
break;
}
}
- (void)playSoundAndVibration{
NSTimeInterval timeInterval = [[NSDate date]
timeIntervalSinceDate:self.lastPlaySoundDate];
if (timeInterval < kDefaultPlaySoundInterval) {
//如果距离上次响铃和震动时间太短, 则跳过响铃
NSLog(@"skip ringing & vibration %@, %@", [NSDate date], self.lastPlaySoundDate);
return;
}
//保存最后一次响铃时间
self.lastPlaySoundDate = [NSDate date];
// 收到消息时,播放音频
[[EMCDDeviceManager sharedInstance] playNewMessageSound];
// 收到消息时,震动
[[EMCDDeviceManager sharedInstance] playVibration];
}
- (void)showNotificationWithMessage:(EMMessage *)message
{
EMPushOptions *options = [[EMClient sharedClient] pushOptions];
NSString *alertBody = nil;
if (options.displayStyle == EMPushDisplayStyleMessageSummary) {
EMMessageBody *messageBody = message.body;
NSString *messageStr = nil;
switch (messageBody.type) {
case EMMessageBodyTypeText:
{
messageStr = ((EMTextMessageBody *)messageBody).text;
}
break;
case EMMessageBodyTypeImage:
{
messageStr = NSLocalizedString(@"message.image", @"Image");
}
break;
case EMMessageBodyTypeLocation:
{
messageStr = NSLocalizedString(@"message.location", @"Location");
}
break;
case EMMessageBodyTypeVoice:
{
messageStr = NSLocalizedString(@"message.voice", @"Voice");
}
break;
case EMMessageBodyTypeVideo:{
messageStr = NSLocalizedString(@"message.video", @"Video");
}
break;
default:
break;
}
do {
// NSString *title = [[UserProfileManager sharedInstance] getNickNameWithUsername:message.from];
NSString *title = @"大佬";
if (message.chatType == EMChatTypeGroupChat) {
NSDictionary *ext = message.ext;
if (ext && ext[kGroupMessageAtList]) {
id target = ext[kGroupMessageAtList];
if ([target isKindOfClass:[NSString class]]) {
if ([kGroupMessageAtAll compare:target options:NSCaseInsensitiveSearch] == NSOrderedSame) {
alertBody = [NSString stringWithFormat:@"%@%@", title, NSLocalizedString(@"group.atPushTitle", @" @ me in the group")];
break;
}
}
else if ([target isKindOfClass:[NSArray class]]) {
NSArray *atTargets = (NSArray*)target;
if ([atTargets containsObject:[EMClient sharedClient].currentUsername]) {
alertBody = [NSString stringWithFormat:@"%@%@", title, NSLocalizedString(@"group.atPushTitle", @" @ me in the group")];
break;
}
}
}
NSArray *groupArray = [[EMClient sharedClient].groupManager getJoinedGroups];
for (EMGroup *group in groupArray) {
if ([group.groupId isEqualToString:message.conversationId]) {
title = [NSString stringWithFormat:@"%@(%@)", message.from, group.subject];
break;
}
}
}
else if (message.chatType == EMChatTypeChatRoom)
{
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
NSString *key = [NSString stringWithFormat:@"OnceJoinedChatrooms_%@", [[EMClient sharedClient] currentUsername]];
NSMutableDictionary *chatrooms = [NSMutableDictionary dictionaryWithDictionary:[ud objectForKey:key]];
NSString *chatroomName = [chatrooms objectForKey:message.conversationId];
if (chatroomName)
{
title = [NSString stringWithFormat:@"%@(%@)", message.from, chatroomName];
}
}
alertBody = [NSString stringWithFormat:@"%@:%@", title, messageStr];
} while (0);
}
else{
// alertBody = NSLocalizedString(@"receiveMessage", @"you have a new message");
alertBody = @"您有一条消息";
}
NSTimeInterval timeInterval = [[NSDate date] timeIntervalSinceDate:self.lastPlaySoundDate];
BOOL playSound = NO;
if (!self.lastPlaySoundDate || timeInterval >= kDefaultPlaySoundInterval) {
self.lastPlaySoundDate = [NSDate date];
playSound = YES;
}
NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];
[userInfo setObject:[NSNumber numberWithInt:message.chatType] forKey:kMessageType];
[userInfo setObject:message.conversationId forKey:kConversationChatter];
//发送本地推送
if (NSClassFromString(@"UNUserNotificationCenter")) {
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0.01 repeats:NO];
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
if (playSound) {
content.sound = [UNNotificationSound defaultSound];
}
content.body =alertBody;
content.userInfo = userInfo;
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:message.messageId content:content trigger:trigger];
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:nil];
}
else {
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = [NSDate date]; //触发通知的时间
notification.alertBody = alertBody;
notification.alertAction = NSLocalizedString(@"open", @"Open");
notification.timeZone = [NSTimeZone defaultTimeZone];
if (playSound) {
notification.soundName = UILocalNotificationDefaultSoundName;
}
notification.userInfo = userInfo;
//发送通知
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
}
- (void)messagesDidDeliver:(NSArray *)aMessages{
NSLog(@"sf");
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
[Github] (https://github.com/BHAreslee)
以上就是集成环信时暂时发现的问题,欢迎大家分享你们遇到的问题,也欢迎加入QQ群:372251359,一起讨论交流即时通讯的问题。
本人微信公众号:放心安慰剂
网友评论