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

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

相关推荐
人月神话-Lee1 小时前
【图像处理】Core Image 与 GPU 渲染管线——让滤镜飞起来
图像处理·人工智能·ios·chatgpt·ai编程·swift·gpu
chenying9981793 小时前
语音克隆模型的难点之一:音素对齐及交叉注意力早期失效问题 (兼论旋转位置编码)——F5-TTS、SupertonicTTS、VoxFlash-TTS 对比
人工智能·实时音视频·语音合成·tts·语音克隆
byte轻骑兵5 小时前
【LE Audio】CAP精讲[11]: 多设备虚拟单接收器的设计与实现规范
人机交互·实时音视频·le audio·蓝牙音频·低功耗音频
夏天的峰没有风5 小时前
Typora+gitcode+picgo搭建免费图床
开发语言·ios·swift
库奇噜啦呼5 小时前
【iOS】源码学习-分类、扩展、关联对象
学习·ios·分类
帅次18 小时前
Android 17 开发者实战:核心更新与应用场景落地指南
android·java·ios·android studio·iphone·android jetpack·webview
人月神话Lee19 小时前
【图像处理】Core Image 与 GPU 渲染管线——让滤镜飞起来
ios·ai编程·图像识别
hz567891 天前
2026 年 RTC 音视频 SDK 解析:技术架构、主流厂商与选型指南
架构·云计算·音视频·webrtc·实时音视频·信息与通信
帅次1 天前
讯飞与腾讯云:Android 实时语音识别服务对比选择
android·ios·微信小程序·小程序·android studio·android runtime
DogDaoDao1 天前
AV1 帧内预测核心文件 reconintra.c 源码深度解析
音视频·实时音视频·视频编解码·av1·libaom·帧内预测·reconintra.c