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

news2024/11/17 19:45:34

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

在之前的开发中,遇到了实时音视频呼叫通知,当App未打开或者App在后台时候,需要通知到用户,用户点击通知栏后是否接入实时音视频的视频或者音频通话。

在iOS需要为工程新建Target:NotificationServiceExtension

一、主工程配置

需要在主工程中开启推送功能,配置证书。

在这里插入图片描述

二、新建NotificationServiceExtension的target

新建NotificationServiceExtension的target

在这里插入图片描述

三、实现NotificationService

在NotificationService的方法

// 主要代码
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler


- (void)serviceExtensionTimeWillExpire;

在didReceiveNotificationRequest实现呼叫响铃及震动效果。

// 通过通知的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);

完整代码如下

#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的方法

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

增加didReceiveRemoteNotification

// 获取启动时收到的APN
    NSDictionary *userInfo = [[DFPushManager shareInstance] launchOptionsRemoteNotification:launchOptions];
    if (userInfo) {
        [self application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result) {
            
        }];
    }

当收到通知后,在didReceiveRemoteNotification中处理是否接通实时音视频的视频通话的逻辑

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/814231.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【微服务】springboot整合mongodb使用详解

目录 一、mongodb简介 1.1 什么是mongodb 1.2 mongodb特点 二、mongodb中的核心术语 2.1 mogodb与数据库对比 2.2 mongodb中的核心概念 2.3 与关系数据库的差异 2.3.1 半结构化 2.3.2 支持多级嵌套 2.3.3 关系弱化 三、mongodb 技术优势和应用场景 3.1 mongodb 技术…

redis主从复制哨兵Cluster

目录 前言 一、模式介绍 1.1 主从复制 1.2 哨兵 1.3 集群 二、主从复制 2.1 主从复制的作用 2.2 主从复制流程 2.3 搭建Redis 主从复制 三、Redis 哨兵模式 3.1 哨兵模式原理 3.2 哨兵模式的作用 3.3 哨兵组成结构 3.4 哨兵故障转移机制 3.5 搭建Redis 哨兵模式…

利用频谱仪进行简单的2.4G 频率测试

一、概述 1. 信号源 我们开发2.4G 无线产品的时候&#xff0c;经常需要对产品的无线信号进行测试&#xff0c;以确定精确的频率。在进行频率测试之前&#xff0c;我们的2.4G 射频芯片需要进入单载波模式。 2. 频谱仪 这里选择的是普源的频谱仪。测试范围是 9kHz - 3.2GHz。…

【工具篇】Lombok 介绍及使用(详细教程)

Lombok 介绍及使用 一&#xff0c;Lombok介绍 在 Java 开发中&#xff0c;常常需要编写大量的getter、setter方法、equals和hashCode方法、构造函数等重复且繁琐的代码。 为了减少 Java 代码中的冗余和样板代码&#xff0c;提高代码的可读性和开发效率&#xff0c;就有了Lomb…

数据结构: 线性表(无哨兵位单链表实现)

文章目录 1. 线性表的链式表示: 链表1.1 顺序表的优缺点1.2 链表的概念1.3 链表的优缺点1.4 链表的结构 2. 单链表的定义2.1 单链表的结构体2.2 接口函数 3. 接口函数的实现3.1 动态申请一个结点 (BuySListNode)3.2 单链表打印 (SListPrint)3.3 单链表尾插 (SListPushBack)3.4 …

【雕爷学编程】MicroPython动手做(20)——掌控板之三轴加速度6

知识点&#xff1a;什么是掌控板&#xff1f; 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片&#xff0c;支持WiFi和蓝牙双模通信&#xff0c;可作为物联网节点&#xff0c;实现物联网应用。同时掌控板上集成了OLED…

【LangChain】向量存储(Vector stores)

概要 存储和搜索非结构化数据的最常见方法之一是嵌入它并存储生成的嵌入向量&#xff0c;然后在查询时嵌入非结构化查询并检索与嵌入查询“最相似”的嵌入向量。向量存储负责存储嵌入数据并为您执行向量搜索。 内容 本篇讲述与 VectorStore 相关的基本功能。使用向量存储的一…

【Git】远程仓库的创建、SSH协议克隆、拉取、推送

目录 一、创建远程仓库 二、HTTPS协议克隆仓库 三、SSH协议克隆仓库 四、向远程仓库推送 五、从远程仓库拉取 六、忽略特殊文件 七、配置命令别名 一、创建远程仓库 首先我们可以从GitHub或者Gitee中创建自己的个人仓库 工作台 - Gitee.comhttps://gitee.com/ 二、HTT…

Sestra 实用教程(三)输入与输出

目 录 一、前言二、分析流程三、输入文件3.1 模型与荷载3.2 分析控制数据 四、输出文件五、参考文献 一、前言 SESAM &#xff08;Super Element Structure Analysis Module&#xff09;是由挪威船级社&#xff08;DNV-GL&#xff09;开发的一款有限元分析&#xff08;FEA&…

关于在VS2017中编译Qt项目遇到的问题

关于在VS2017中编译Qt项目遇到的问题 【QT】VS打开QT项目运行不成功 error MSB6006 “cmd.exe”已退出,代码为 2。如何在VS2017里部署的Qt Designer上编辑槽函数 【QT】VS打开QT项目运行不成功 error MSB6006 “cmd.exe”已退出,代码为 2。 链接 如何在VS2017里部署的Qt Design…

【LeetCode】解码方法

这里写目录标题 题目描述算法流程编程代码代码优化 链接: 解码方法 题目描述 算法流程 编程代码 class Solution { public:int numDecodings(string s) {int n s.size();vector<int> dp(n);dp[0] s[0] ! 0;if(n 1) return dp[0];if(s[1] < 9 && s[1] >…

python之编写form表单提交到后端

一、环境配置 我们先去python的框架中下载Flask&#xff0c;具体的配置我给大家找了一篇博客讲解&#xff0c;环境调试没问题后&#xff0c;开始我们form表单提交的过程 Python之flask框架_python flask_【网络星空】的博客-CSDN博客 二、前端代码 在VScode里编写前端的代码为…

移动端加入购物车界面设计

效果图 源码如下 页面设计 <template><div class"container"><!--商品详情 start--><van-image class"goods-item-image" :src"goods.goodsHeadImg"></van-image><div class"goods-price">&…

【安装vue脚手架报错:npm install -g @vue-cli pm ERR! code EINVALIDTAGNAME 】

当我们执行npm install -g vue-cli时候会报错&#xff1a; npm ERR! Invalid tag name “vue-cli” of package “vue-cli”: Tags may not have any characters that encodeURIComponent encodes. npm ERR! A complete log of this run can be found in: /Users/wuwenlu/.npm/…

【MySQL】MySQL索引、事务、用户管理

20岁的男生穷困潦倒&#xff0c;20岁的女生风华正茂&#xff0c;没有人会一直风华正茂&#xff0c;也没有人会一直穷困潦倒… 文章目录 一、MySQL索引特性&#xff08;重点&#xff09;1.磁盘、OS、MySQL&#xff0c;在进行数据IO时三者的关系2.索引的理解3.聚簇索引&#xff0…

仿找靓机链接生成 独立后台管理

教程&#xff1a;修改数据库账号密码直接使用。 源码带有教程! 下载程序&#xff1a;https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3

软考A计划-系统集成项目管理工程师-项目采购管理-下

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

《Java面向对象程序设计》学习笔记

最近因考研专业课&#xff0c;在学习耿祥义老师的《Java面向对象程序设计&#xff08;第3版&#xff09;-微课视频版》 就打算放一些自己的学习笔记&#xff0c;可能不会及时更新&#xff0c;见谅。 计划弄个专栏&#xff0c;书上的每章对应专栏里的一篇文章。 专栏&#xf…

【并发专题】深入理解并发可见性、有序性、原子性与JMM内存模型

目录 课程内容一、JMM模型1.什么是JMM模型2.JMM内存区域模型3.JMM内存模型与硬件内存架构的关系4.JMM存在的必要性5.数据同步八大原子操作6.指令重排现象与并发编程的可见性&#xff0c;原子性与有序性问题 学习总结 课程内容 一、JMM模型 1.什么是JMM模型 Java内存模型&…

eda、gnm、anm究竟是个啥?

安装prody pip install prody -i https://pypi.tuna.tsinghua.edu.cn/simpleeda、anm、gnm eda(essential dynamics analysis) 另一个名字PCA(Principal Component Analysis) 或 NMA(Normal Mode Analysis)。 eda分析可以帮助人们理解生物大分子基本的运动模式和构象变化。…