iOS开发-NotificationServiceExtension实现实时音视频呼叫通知响铃与震动
在之前的开发中,遇到了实时音视频呼叫通知,当App未打开或者App在后台时候,需要通知到用户,用户点击通知栏后是否接入实时音视频的视频或者音频通话。
在iOS需要为工程新建Target:NotificationServiceExtension
一、主工程配置
需要在主工程中开启推送功能,配置证书。
二、新建NotificationServiceExtension的target
新建NotificationServiceExtension的target
三、实现NotificationService
在NotificationService的方法
objectivec
// 主要代码
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler
- (void)serviceExtensionTimeWillExpire;
在didReceiveNotificationRequest实现呼叫响铃及震动效果。
objectivec
// 通过通知的Sound设置为voip_call.caf,这里播放一段空白音频,音频结束后结束震动
NSString *path = [[NSBundle mainBundle] pathForResource:@"blank_call.mp3" ofType:nil];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:path], &soundID);
AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, soundCompleteCallback, NULL);
AudioServicesAddSystemSoundCompletion(kSystemSoundID_Vibrate, NULL, NULL, soundCompleteCallback, NULL);
完整代码如下
objectivec
#import "NotificationService.h"
#import <AVFoundation/AVFAudio.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
@interface NotificationService ()
{
SystemSoundID soundID;
}
@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
@property (nonatomic, strong) NSMutableArray *requests;
@end
@implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
BOOL playVoice = NO;
NSString *chatPushVo = [self.bestAttemptContent.userInfo objectForKey:@"chatPushVo"];
if (chatPushVo && [chatPushVo isKindOfClass:[NSString class]] && chatPushVo > 0) {
NSDictionary *dict = [self dictionaryWithJsonString:chatPushVo];
if (dict && [dict isKindOfClass:[NSDictionary class]]) {
NSString *type = [NSString stringWithFormat:@"%@", [dict objectForKey:@"type"]];
// type : 0 呼叫
if ([@"0" isEqualToString:type]) {
playVoice = YES;
// 通过通知的Sound设置为voip_call.caf,这里播放一段空白音频,音频结束后结束震动
NSString *path = [[NSBundle mainBundle] pathForResource:@"blank_call.mp3" ofType:nil];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)[NSURL fileURLWithPath:path], &soundID);
AudioServicesAddSystemSoundCompletion(soundID, NULL, NULL, soundCompleteCallback, NULL);
AudioServicesAddSystemSoundCompletion(kSystemSoundID_Vibrate, NULL, NULL, soundCompleteCallback, NULL);
[self playVoiceWithContent:self.bestAttemptContent.userInfo];
}
}
}
if (playVoice == NO) {
self.contentHandler(self.bestAttemptContent);
}
}
- (void)playVoiceWithContent:(NSDictionary *)userInfo {
// iOS 10之前前台没有通知栏
// 此处调用之前的语音播报的内容
[self playRegisterNotifications:userInfo];
}
- (void)playRegisterNotifications:(NSDictionary *)userInfo {
[self registerNotifications:userInfo];
}
- (void)registerNotifications:(NSDictionary *)userInfo {
[self startShakeSound];
}
/// 开始响铃
- (void)startShakeSound {
// 声音
AudioServicesPlaySystemSound(soundID);
// 震动
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
self.contentHandler(self.bestAttemptContent);
}
/// 结束响铃
- (void)stopShakeSound {
AudioServicesDisposeSystemSoundID(soundID);
AudioServicesRemoveSystemSoundCompletion(soundID);
}
//AudioServicesAddSystemSoundCompletion的回调函数
void soundCompleteCallback(SystemSoundID sound,void * clientData) {
if (sound == kSystemSoundID_Vibrate) {
AudioServicesPlayAlertSound(sound);//重复响铃震动
} else {
// 移除
AudioServicesDisposeSystemSoundID(sound);
AudioServicesRemoveSystemSoundCompletion(sound);
AudioServicesDisposeSystemSoundID(kSystemSoundID_Vibrate);
AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate);
}
}
- (void)serviceExtensionTimeWillExpire {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
self.contentHandler(self.bestAttemptContent);
}
/**
json转成NSDictionary
@param jsonString json字符串
@return NSDictionary
*/
- (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString {
if (jsonString == nil) {
return nil;
}
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *err;
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];
if(err) {
return nil;
}
return dic;
}
@end
四、使用推送
我这里使用的极光推送,注意需要设置推送的mutable-content=1字段。
五、点击通知后处理是否通实时音视频视频通话
在收到通知后,用户点击点击通知后处理是否通实时音视频视频通话逻辑。
在AppDelegate的方法
objectivec
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
增加didReceiveRemoteNotification
objectivec
// 获取启动时收到的APN
NSDictionary *userInfo = [[DFPushManager shareInstance] launchOptionsRemoteNotification:launchOptions];
if (userInfo) {
[self application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result) {
}];
}
当收到通知后,在didReceiveRemoteNotification中处理是否接通实时音视频的视频通话的逻辑
objectivec
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
DFDebugLogger(@"didReceiveRemoteNotification");
[[SDPushManager shareInstance] handleRemoteNotification:application userInfo:userInfo completion:nil];
NSLog(@"收到通知:%@", userInfo);
[[SDPushManager shareInstance] setBadgeNumberMax:nil];
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive) {
// 登录后调用check
__weak typeof(self) weakSelf = self;
if (userInfo && [userInfo isKindOfClass:[NSDictionary class]]) {
NSString *chatPushVo = [userInfo objectForKey:@"chatPushVo"];
if (chatPushVo && [chatPushVo isKindOfClass:[NSString class]] && appPushVo.length > 0) {
NSDictionary *dict = [DFJsonUtil dictionaryWithJsonString: chatPushVo];
if (dict && [dict isKindOfClass:[NSDictionary class]]) {
NSString *type = [NSString stringWithFormat:@"%@", [dict objectForKey:@"type"]];
// type : 0 呼叫
/// 0/用户呼叫
// 打开接听页面,进行接听
}
}
}
}
completionHandler(UIBackgroundFetchResultNewData);
}
六、小结
iOS开发-NotificationServiceExtension实现实时音视频呼叫通知与语音播报
在之前的开发中,遇到了实时音视频呼叫通知,当App未打开或者App在后台时候,需要通知到用户,用户点击通知栏后是否接入实时音视频的视频或者音频通话。
学习记录,每天不停进步。