NTESNotificationCenter.m 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. //
  2. // NTESNotificationCenter.m
  3. // NIM
  4. //
  5. // Created by Xuhui on 15/3/25.
  6. // Copyright (c) 2015年 Netease. All rights reserved.
  7. //
  8. #import "NTESNotificationCenter.h"
  9. #import "NTESVideoChatViewController.h"
  10. //#import "NTESAudioChatViewController.h"
  11. //#import "NTESMainTabController.h"
  12. #import "MessageViewController.h"
  13. #import "NSDictionary+NTESJson.h"
  14. //#import "NTESCustomNotificationDB.h"
  15. //#import "NTESCustomNotificationObject.h"
  16. //#import "UIView+Toast.h"
  17. //#import "NTESWhiteboardViewController.h"
  18. //#import "NTESCustomSysNotificationSender.h"
  19. //#import "NTESGlobalMacro.h"
  20. #import <AVFoundation/AVFoundation.h>
  21. //#import "NTESLiveViewController.h"
  22. //#import "NTESSessionMsgConverter.h"
  23. #import "NTESSessionUtil.h"
  24. #import "NTESAVNotifier.h"
  25. //#import "NTESRedPacketTipAttachment.h"
  26. #import "ModelRootViewController.h"
  27. #import "MessageViewController.h"
  28. #import "NTESNetChatViewController.h"
  29. NSString *NTESCustomNotificationCountChanged = @"NTESCustomNotificationCountChanged";
  30. @interface NTESNotificationCenter () <NIMSystemNotificationManagerDelegate,NIMNetCallManagerDelegate,
  31. NIMRTSManagerDelegate,NIMChatManagerDelegate,NIMBroadcastManagerDelegate>
  32. @property (nonatomic,strong) AVAudioPlayer *player; //播放提示音
  33. @property (nonatomic,strong) NTESAVNotifier *notifier;
  34. @end
  35. @implementation NTESNotificationCenter
  36. + (instancetype)sharedCenter
  37. {
  38. static NTESNotificationCenter *instance = nil;
  39. static dispatch_once_t onceToken;
  40. dispatch_once(&onceToken, ^{
  41. instance = [[NTESNotificationCenter alloc] init];
  42. });
  43. return instance;
  44. }
  45. - (void)start
  46. {
  47. NSLog(@"Notification Center Setup");
  48. }
  49. - (instancetype)init {
  50. self = [super init];
  51. if(self) {
  52. NSURL *url = [[NSBundle mainBundle] URLForResource:@"message" withExtension:@"wav"];
  53. _player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
  54. _notifier = [[NTESAVNotifier alloc] init];
  55. [[NIMSDK sharedSDK].systemNotificationManager addDelegate:self];
  56. [[NIMAVChatSDK sharedSDK].netCallManager addDelegate:self];
  57. [[NIMAVChatSDK sharedSDK].rtsManager addDelegate:self];
  58. [[NIMSDK sharedSDK].chatManager addDelegate:self];
  59. [[NIMSDK sharedSDK].broadcastManager addDelegate:self];
  60. }
  61. return self;
  62. }
  63. - (void)dealloc{
  64. [[NIMSDK sharedSDK].systemNotificationManager removeDelegate:self];
  65. [[NIMAVChatSDK sharedSDK].netCallManager removeDelegate:self];
  66. [[NIMAVChatSDK sharedSDK].rtsManager removeDelegate:self];
  67. [[NIMSDK sharedSDK].chatManager removeDelegate:self];
  68. [[NIMSDK sharedSDK].broadcastManager removeDelegate:self];
  69. }
  70. #pragma mark - NIMChatManagerDelegate
  71. - (void)onRecvMessages:(NSArray *)recvMessages
  72. {
  73. NSArray *messages = [self filterMessages:recvMessages];
  74. if (messages.count)
  75. {
  76. static BOOL isPlaying = NO;
  77. if (isPlaying) {
  78. return;
  79. }
  80. isPlaying = YES;
  81. [self playMessageAudioTip];
  82. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  83. isPlaying = NO;
  84. });
  85. [self checkMessageAt:messages];
  86. }
  87. }
  88. - (void)playMessageAudioTip
  89. {
  90. UINavigationController *nav = [ModelRootViewController instance].selectedViewController;
  91. BOOL needPlay = YES;
  92. for (UIViewController *vc in nav.viewControllers) {
  93. if ([vc isKindOfClass:[MessageViewController class]] || [vc isKindOfClass:[NTESNetChatViewController class]])
  94. {
  95. needPlay = NO;
  96. break;
  97. }
  98. }
  99. if (needPlay) {
  100. [self.player stop];
  101. [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient error:nil];
  102. [self.player play];
  103. }
  104. }
  105. - (void)checkMessageAt:(NSArray<NIMMessage *> *)messages
  106. {
  107. //一定是同个 session 的消息
  108. NIMSession *session = [messages.firstObject session];
  109. if ([self.currentSessionViewController.session isEqual:session])
  110. {
  111. //只有在@所属会话页外面才需要标记有人@你
  112. return;
  113. }
  114. NSString *me = [[NIMSDK sharedSDK].loginManager currentAccount];
  115. for (NIMMessage *message in messages) {
  116. if ([message.apnsMemberOption.userIds containsObject:me]) {
  117. [NTESSessionUtil addRecentSessionMark:session type:NTESRecentSessionMarkTypeAt];
  118. return;
  119. }
  120. }
  121. }
  122. - (NSArray *)filterMessages:(NSArray *)messages
  123. {
  124. NSMutableArray *array = [[NSMutableArray alloc] init];
  125. for (NIMMessage *message in messages)
  126. {
  127. // if ([self checkRedPacketTip:message] && ![self canSaveMessageRedPacketTip:message])
  128. // {
  129. // [[NIMSDK sharedSDK].conversationManager deleteMessage:message];
  130. // [self.currentSessionViewController uiDeleteMessage:message];
  131. // continue;
  132. // }
  133. [array addObject:message];
  134. }
  135. return [NSArray arrayWithArray:array];
  136. }
  137. //- (BOOL)checkRedPacketTip:(NIMMessage *)message
  138. //{
  139. // NIMCustomObject *object = message.messageObject;
  140. // if ([object isKindOfClass:[NIMCustomObject class]] && [object.attachment isKindOfClass:[NTESRedPacketTipAttachment class]])
  141. // {
  142. // return YES;
  143. // }
  144. // return NO;
  145. //}
  146. //
  147. //- (BOOL)canSaveMessageRedPacketTip:(NIMMessage *)message
  148. //{
  149. // NIMCustomObject *object = message.messageObject;
  150. // NTESRedPacketTipAttachment *attach = (NTESRedPacketTipAttachment *)object.attachment;
  151. // NSString *me = [NIMSDK sharedSDK].loginManager.currentAccount;
  152. // return [attach.sendPacketId isEqualToString:me] || [attach.openPacketId isEqualToString:me];
  153. //}
  154. //- (void)onRecvRevokeMessageNotification:(NIMRevokeMessageNotification *)notification
  155. //{
  156. // NIMMessage *tipMessage = [NTESSessionMsgConverter msgWithTip:[NTESSessionUtil tipOnMessageRevoked:notification]];
  157. // NIMMessageSetting *setting = [[NIMMessageSetting alloc] init];
  158. // setting.shouldBeCounted = NO;
  159. // tipMessage.setting = setting;
  160. // tipMessage.timestamp = notification.timestamp;
  161. //
  162. // NTESMainTabController *tabVC = [NTESMainTabController instance];
  163. // UINavigationController *nav = tabVC.selectedViewController;
  164. //
  165. // for (NTESSessionViewController *vc in nav.viewControllers) {
  166. // if ([vc isKindOfClass:[NTESSessionViewController class]]
  167. // && [vc.session.sessionId isEqualToString:notification.session.sessionId]) {
  168. // NIMMessageModel *model = [vc uiDeleteMessage:notification.message];
  169. // if (model) {
  170. // [vc uiInsertMessages:@[tipMessage]];
  171. // }
  172. // break;
  173. // }
  174. // }
  175. //
  176. // // saveMessage 方法执行成功后会触发 onRecvMessages: 回调,但是这个回调上来的 NIMMessage 时间为服务器时间,和界面上的时间有一定出入,所以要提前先在界面上插入一个和被删消息的界面时间相符的 Tip, 当触发 onRecvMessages: 回调时,组件判断这条消息已经被插入过了,就会忽略掉。
  177. // [[NIMSDK sharedSDK].conversationManager saveMessage:tipMessage
  178. // forSession:notification.session
  179. // completion:nil];
  180. //}
  181. #pragma mark - NIMSystemNotificationManagerDelegate
  182. - (void)onReceiveCustomSystemNotification:(NIMCustomSystemNotification *)notification{
  183. NSString *content = notification.content;
  184. if([content isEqualToString:@"恭喜,您有新的订单"]){
  185. NSData *data = [content dataUsingEncoding:NSUTF8StringEncoding];
  186. [[NSNotificationCenter defaultCenter] postNotificationName:NTESCustomNotificationCountChanged object:nil];
  187. UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"订单消息"
  188. message:content
  189. delegate:self
  190. cancelButtonTitle:nil
  191. otherButtonTitles:@"去查看",nil];
  192. [alert show];
  193. }
  194. // if (data)
  195. // {
  196. //
  197. // NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data
  198. // options:0
  199. // error:nil];
  200. // if ([dict isKindOfClass:[NSDictionary class]])
  201. // {
  202. // switch ([dict jsonInteger:@"id"]) {
  203. // case NTESCustom:{
  204. // //SDK并不会存储自定义的系统通知,需要上层结合业务逻辑考虑是否做存储。这里给出一个存储的例子。
  205. // NTESCustomNotificationObject *object = [[NTESCustomNotificationObject alloc] initWithNotification:notification];
  206. // //这里只负责存储可离线的自定义通知,推荐上层应用也这么处理,需要持久化的通知都走可离线通知
  207. // if (!notification.sendToOnlineUsersOnly) {
  208. // [[NTESCustomNotificationDB sharedInstance] saveNotification:object];
  209. // }
  210. // if (notification.setting.shouldBeCounted) {
  211. // [[NSNotificationCenter defaultCenter] postNotificationName:NTESCustomNotificationCountChanged object:nil];
  212. // }
  213. // NSString *content = [dict jsonString:NTESCustomContent];
  214. // [self makeToast:content];
  215. // }
  216. // break;
  217. // case NTESTeamMeetingCall:{
  218. // if (![self shouldResponseBusy]) {
  219. // //繁忙的话,不回复任何信息,直接丢掉,让呼叫方直接走超时
  220. // NSTimeInterval sendTime = notification.timestamp;
  221. // NSTimeInterval nowTime = [[NSDate date] timeIntervalSince1970];
  222. // if (nowTime - sendTime < 45)
  223. // {
  224. // //60 秒内,认为有效,否则丢弃
  225. // NTESTeamMeetingCalleeInfo *info = [[NTESTeamMeetingCalleeInfo alloc] init];
  226. // info.teamId = [dict jsonString:NTESTeamMeetingTeamId];
  227. // info.members = [dict jsonArray:NTESTeamMeetingMembers];
  228. // info.meetingName = [dict jsonString:NTESTeamMeetingName];
  229. // info.teamName = [dict jsonString:NTESTeamMeetingTeamName];
  230. //
  231. // NTESTeamMeetingCallingViewController *vc = [[NTESTeamMeetingCallingViewController alloc] initWithCalleeInfo:info];
  232. // [self presentModelViewController:vc];
  233. // }
  234. // }
  235. // }
  236. // break;
  237. // default:
  238. // break;
  239. // }
  240. // }
  241. // }
  242. }
  243. #pragma mark - NIMNetCallManagerDelegate
  244. - (void)onReceive:(UInt64)callID from:(NSString *)caller type:(NIMNetCallMediaType)type message:(NSString *)extendMessage{
  245. ModelRootViewController *tabVC = [ModelRootViewController instance];
  246. [tabVC.view endEditing:YES];
  247. UINavigationController *nav = tabVC.selectedViewController;
  248. if ([self shouldResponseBusy]){
  249. [[NIMAVChatSDK sharedSDK].netCallManager control:callID type:NIMNetCallControlTypeBusyLine];
  250. }
  251. else {
  252. if ([self shouldFireNotification:caller]) {
  253. NSString *text = [self textByCaller:caller
  254. type:type];
  255. [_notifier start:text];
  256. }
  257. UIViewController *vc;
  258. switch (type) {
  259. case NIMNetCallTypeVideo:{
  260. vc = [[NTESVideoChatViewController alloc] initWithCaller:caller callId:callID];
  261. }
  262. break;
  263. case NIMNetCallTypeAudio:{
  264. // vc = [[NTESAudioChatViewController alloc] initWithCaller:caller callId:callID];
  265. }
  266. break;
  267. default:
  268. break;
  269. }
  270. if (!vc) {
  271. return;
  272. }
  273. // 由于音视频聊天里头有音频和视频聊天界面的切换,直接用present的话页面过渡会不太自然,这里还是用push,然后做出present的效果
  274. CATransition *transition = [CATransition animation];
  275. transition.duration = 0.25;
  276. transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
  277. transition.type = kCATransitionPush;
  278. transition.subtype = kCATransitionFromTop;
  279. [nav.view.layer addAnimation:transition forKey:nil];
  280. nav.navigationBarHidden = YES;
  281. if (nav.presentedViewController) {
  282. // fix bug MMC-1431
  283. [nav.presentedViewController dismissViewControllerAnimated:NO completion:nil];
  284. }
  285. vc.hidesBottomBarWhenPushed = YES;
  286. [nav pushViewController:vc animated:NO];
  287. }
  288. }
  289. - (void)onHangup:(UInt64)callID
  290. by:(NSString *)user
  291. {
  292. [_notifier stop];
  293. }
  294. //- (void)onRTSRequest:(NSString *)sessionID
  295. // from:(NSString *)caller
  296. // services:(NSUInteger)types
  297. // message:(NSString *)info
  298. //{
  299. // if ([self shouldResponseBusy]) {
  300. // [[NIMAVChatSDK sharedSDK].rtsManager responseRTS:sessionID accept:NO option:nil completion:nil];
  301. // }
  302. // else {
  303. //
  304. // if ([self shouldFireNotification:caller]) {
  305. // NSString *text = [self textByCaller:caller];
  306. // [_notifier start:text];
  307. // }
  308. // NTESWhiteboardViewController *vc = [[NTESWhiteboardViewController alloc] initWithSessionID:sessionID
  309. // peerID:caller
  310. // types:types
  311. // info:info];
  312. // [self presentModelViewController:vc];
  313. // }
  314. //}
  315. //- (void)presentModelViewController:(UIViewController *)vc
  316. //{
  317. // NTESMainTabController *tab = [NTESMainTabController instance];
  318. // [tab.view endEditing:YES];
  319. // if (tab.presentedViewController) {
  320. // __weak NTESMainTabController *wtabVC = tab;
  321. // [tab.presentedViewController dismissViewControllerAnimated:NO completion:^{
  322. // [wtabVC presentViewController:vc animated:NO completion:nil];
  323. // }];
  324. // }else{
  325. // [tab presentViewController:vc animated:NO completion:nil];
  326. // }
  327. //}
  328. - (void)onRTSTerminate:(NSString *)sessionID
  329. by:(NSString *)user
  330. {
  331. [_notifier stop];
  332. }
  333. - (BOOL)shouldResponseBusy
  334. {
  335. ModelRootViewController *tabVC = [ModelRootViewController instance];
  336. UINavigationController *nav = tabVC.selectedViewController;
  337. return [nav.topViewController isKindOfClass:[NTESNetChatViewController class]];
  338. // ||
  339. // [tabVC.presentedViewController isKindOfClass:[NTESWhiteboardViewController class]] ||
  340. // [tabVC.presentedViewController isKindOfClass:[NTESTeamMeetingCallingViewController class]] ||
  341. // [tabVC.presentedViewController isKindOfClass:[NTESTeamMeetingViewController class]];
  342. }
  343. #pragma mark - NIMBroadcastManagerDelegate
  344. //- (void)onReceiveBroadcastMessage:(NIMBroadcastMessage *)broadcastMessage
  345. //{
  346. // [self makeToast:broadcastMessage.content];
  347. //}
  348. #pragma mark - format
  349. - (NSString *)textByCaller:(NSString *)caller type:(NIMNetCallMediaType)type
  350. {
  351. NSString *action = type == NIMNetCallMediaTypeAudio ? @"音频":@"视频";
  352. NSString *text = [NSString stringWithFormat:@"你收到了一个%@聊天请求",action];
  353. NIMKitInfo *info = [[NIMKit sharedKit] infoByUser:caller option:nil];
  354. if ([info.showName length])
  355. {
  356. text = [NSString stringWithFormat:@"%@向你发起了一个%@聊天请求",info.showName,action];
  357. }
  358. return text;
  359. }
  360. //- (NSString *)textByCaller:(NSString *)caller
  361. //{
  362. // NSString *text = @"你收到了一个白板请求";
  363. // NIMKitInfo *info = [[NIMKit sharedKit] infoByUser:caller option:nil];
  364. // if ([info.showName length])
  365. // {
  366. // text = [NSString stringWithFormat:@"%@向你发起了一个白板请求",info.showName];
  367. // }
  368. // return text;
  369. //}
  370. - (BOOL)shouldFireNotification:(NSString *)callerId
  371. {
  372. //退后台后 APP 存活,然后收到通知
  373. BOOL should = YES;
  374. //消息不提醒
  375. id<NIMUserManager> userManager = [[NIMSDK sharedSDK] userManager];
  376. if (![userManager notifyForNewMsg:callerId])
  377. {
  378. should = NO;
  379. }
  380. //当前在正处于免打扰
  381. id<NIMApnsManager> apnsManager = [[NIMSDK sharedSDK] apnsManager];
  382. NIMPushNotificationSetting *setting = [apnsManager currentSetting];
  383. if (setting.noDisturbing)
  384. {
  385. NSDate *date = [NSDate date];
  386. NSCalendar *calendar = [NSCalendar currentCalendar];
  387. NSDateComponents *components = [calendar components:(NSCalendarUnitHour | NSCalendarUnitMinute) fromDate:date];
  388. NSInteger now = components.hour * 60 + components.minute;
  389. NSInteger start = setting.noDisturbingStartH * 60 + setting.noDisturbingStartM;
  390. NSInteger end = setting.noDisturbingEndH * 60 + setting.noDisturbingEndM;
  391. //当天区间
  392. if (end > start && end >= now && now >= start)
  393. {
  394. should = NO;
  395. }
  396. //隔天区间
  397. else if(end < start && (now <= end || now >= start))
  398. {
  399. should = NO;
  400. }
  401. }
  402. return should;
  403. }
  404. #pragma mark - Misc
  405. - (NIMSessionViewController *)currentSessionViewController
  406. {
  407. UINavigationController *nav = [ModelRootViewController instance].selectedViewController;
  408. for (UIViewController *vc in nav.viewControllers)
  409. {
  410. if ([vc isKindOfClass:[NIMSessionViewController class]])
  411. {
  412. return (NIMSessionViewController *)vc;
  413. }
  414. }
  415. return nil;
  416. }
  417. //- (void)makeToast:(NSString *)content
  418. //{
  419. // [[NTESMainTabController instance].selectedViewController.view makeToast:content duration:2.0 position:CSToastPositionCenter];
  420. //}
  421. @end