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

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

相关推荐
DisonTangor4 分钟前
苹果发布iOS 18.2首个公测版:Siri接入ChatGPT、iPhone 16拍照按钮有用了
ios·chatgpt·iphone
- 羊羊不超越 -7 分钟前
App渠道来源追踪方案全面分析(iOS/Android/鸿蒙)
android·ios·harmonyos
嵌入式小章4 小时前
基于STM32的实时时钟(RTC)教学
stm32·嵌入式硬件·实时音视频
2401_8658548816 小时前
iOS应用想要下载到手机上只能苹果签名吗?
后端·ios·iphone
HackerTom1 天前
iOS用rime且导入自制输入方案
ios·iphone·rime
良技漫谈1 天前
Rust移动开发:Rust在iOS端集成使用介绍
后端·程序人生·ios·rust·objective-c·swift
2401_852403551 天前
高效管理iPhone存储:苹果手机怎么删除相似照片
ios·智能手机·iphone
星际码仔2 天前
【动画图解】是怎样的方法,能被称作是 Flutter Widget 系统的核心?
android·flutter·ios
emperinter2 天前
WordCloudStudio:AI生成模版为您的文字云创意赋能 !
图像处理·人工智能·macos·ios·信息可视化·iphone
关键帧Keyframe2 天前
音视频面试题集锦第 8 期
ios·音视频开发·客户端