iOS开发-NotificationServiceExtension实现实时音视频呼叫通知响铃与震动

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在后台时候,需要通知到用户,用户点击通知栏后是否接入实时音视频的视频或者音频通话。

学习记录,每天不停进步。

相关推荐
Magnetic_h11 小时前
【iOS】单例模式
笔记·学习·ui·ios·单例模式·objective-c
归辞...13 小时前
「iOS」——单例模式
ios·单例模式·cocoa
yanling202315 小时前
黑神话悟空mac可以玩吗
macos·ios·crossove·crossove24
归辞...17 小时前
「iOS」viewController的生命周期
ios·cocoa·xcode
crasowas21 小时前
Flutter问题记录 - 适配Xcode 16和iOS 18
flutter·ios·xcode
2401_8524035521 小时前
Mac导入iPhone的照片怎么删除?快速方法讲解
macos·ios·iphone
SchneeDuan21 小时前
iOS六大设计原则&&设计模式
ios·设计模式·cocoa·设计原则
羊十一1 天前
C++(C++的文件I/O)
开发语言·c++·cocoa
JohnsonXin2 天前
【兼容性记录】video标签在 IOS 和 安卓中的问题
android·前端·css·ios·h5·兼容性
蒙娜丽宁2 天前
Go语言错误处理详解
ios·golang·go·xcode·go1.19