前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >iOS15 推送动态语音播报解决方案

iOS15 推送动态语音播报解决方案

原创
作者头像
freesan44
发布于 2021-12-29 02:51:31
发布于 2021-12-29 02:51:31
1.2K00
代码可运行
举报
文章被收录于专栏:freesan44freesan44
运行总次数:0
代码可运行

问题

iOS15之后,推送多条语音会产生多条横幅,对于动态金额语音,多条横幅是不可取的

解决方案

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
做版本管理,iOS15以上,用新的解决方案实现,iOS15以下还是沿用旧的推送方案/// !!!!: 推送语音播报总控制逻辑
/// @param sourceURLsArr mp3源文件数组
/// @param bestAttemptContent
/// @param completed
-(void)pushVoiceNotificationWithWithSourceURLs:(NSArray *)sourceURLsArr
                           bestAttemptContent:(UNMutableNotificationContent *)bestAttemptContent
                                    completed:(XSNotificationPushCompleted)completed
{
    if (@available(iOS 15.0, *)) {
        // 合并音频文件生成新的音频
        [self mergeAVAssetWithSourceURLs:sourceURLsArr completed:^(NSString *soundName, NSURL *soundsFileURL) {
            if (!soundName) {
                NSLog(@"声音生成失败!");
                completed();
                return;
            }
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 150000
            if (@available(iOS 15.0, *)) {
                bestAttemptContent.interruptionLevel = UNNotificationInterruptionLevelTimeSensitive;
            }
#endif
            UNNotificationSound * sound = [UNNotificationSound soundNamed:soundName];
            bestAttemptContent.sound = sound;
            completed();
        }];
    }
    else//iOS15以下,改用原来旧方式实现
    {
        [self pushLocalNotificationIniOS14ToApp:0 withArray:sourceURLsArr completed:^{
            completed();
        }];
    }
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
新方案里面,通过NSFileManager把输出音频保存在【AppGroup】的/Library/Sounds/里面,坑点就是,AVAssetExportSession的输出路径必须要保证文件夹存在,不然会提示操作有误,当时直接通过contentsOfDirectoryAtPath来生成两个文件夹,结果不行, 必须要逐个生成,并且要留意生成的文件后缀要符合输出格式要求///在AppGroup中合并音频
- (void)mergeAVAssetWithSourceURLs:(NSArray *)sourceURLsArr completed:(void (^)(NSString * soundName,NSURL * soundsFileURL)) completed{
    //创建音频轨道,并获取多个音频素材的轨道
    AVMutableComposition *composition = [AVMutableComposition composition];
    //音频插入的开始时间,用于记录每次添加音频文件的开始时间
    __block CMTime beginTime = kCMTimeZero;
    [sourceURLsArr enumerateObjectsUsingBlock:^(id  _Nonnull audioFileURL, NSUInteger idx, BOOL * _Nonnull stop) {
        //获取音频素材
        AVURLAsset *audioAsset1 = [AVURLAsset assetWithURL:[NSURL fileURLWithPath:audioFileURL]];
        //音频轨道
        AVMutableCompositionTrack *audioTrack1 = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:0];
        //获取音频素材轨道
        AVAssetTrack *audioAssetTrack1 = [[audioAsset1 tracksWithMediaType:AVMediaTypeAudio] firstObject];
        //音频合并- 插入音轨文件
        [audioTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset1.duration) ofTrack:audioAssetTrack1 atTime:beginTime error:nil];
        // 记录尾部时间
        beginTime = CMTimeAdd(beginTime, audioAsset1.duration);
    }];
    
    
    
    //用动态日期会占用空间
//    NSDateFormatter *formater = [[NSDateFormatter alloc] init];
//    [formater setDateFormat:@"yyyy-MM-dd-HH:mm:ss-SSS"];
//    NSString * timeFromDateStr = [formater stringFromDate:[NSDate date]];
//    NSString *outPutFilePath = [NSHomeDirectory() stringByAppendingFormat:@"/tmp/sound-%@.mp4", timeFromDateStr];
    
    NSURL *groupURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:kAppGroupID];
//    NSURL * soundsURL = [groupURL URLByAppendingPathComponent:@"/Library/Sounds/" isDirectory:YES];
    //建立文件夹
    NSURL * soundsURL = [groupURL URLByAppendingPathComponent:@"Library/" isDirectory:YES];
    if (![[NSFileManager defaultManager] contentsOfDirectoryAtPath:soundsURL.path error:nil]) {
        [[NSFileManager defaultManager] createDirectoryAtPath:soundsURL.path withIntermediateDirectories:YES attributes:nil error:nil];
    }
    //建立文件夹
    NSURL * soundsURL2 = [groupURL URLByAppendingPathComponent:@"Library/Sounds/" isDirectory:YES];
    if (![[NSFileManager defaultManager] contentsOfDirectoryAtPath:soundsURL2.path error:nil]) {
        [[NSFileManager defaultManager] createDirectoryAtPath:soundsURL2.path withIntermediateDirectories:YES attributes:nil error:nil];
    }
    // 新建文件名,如果存在就删除旧的
    NSString * soundName = [NSString stringWithFormat:@"sound.m4a"];
    NSString *outPutFilePath = [NSString stringWithFormat:@"Library/Sounds/%@", soundName];
    NSURL * soundsFileURL = [groupURL URLByAppendingPathComponent:outPutFilePath isDirectory:NO];
//    NSString * filePath = soundsURL.absoluteString;
    if ([[NSFileManager defaultManager] fileExistsAtPath:soundsFileURL.path]) {
        [[NSFileManager defaultManager] removeItemAtPath:soundsFileURL.path error:nil];
    }
    
    
    
    
    //导出合并后的音频文件
    //音频文件目前只找到支持m4a 类型的
    AVAssetExportSession *session = [[AVAssetExportSession alloc]initWithAsset:composition presetName:AVAssetExportPresetAppleM4A];
    // 音频文件输出
    session.outputURL = soundsFileURL;
    session.outputFileType = AVFileTypeAppleM4A; //与上述的`present`相对应
    session.shouldOptimizeForNetworkUse = YES;   //优化网络
    [session exportAsynchronouslyWithCompletionHandler:^{
        if (session.status == AVAssetExportSessionStatusCompleted) {
            NSLog(@"合并成功----%@", outPutFilePath);
            if (completed) {
                completed(soundName,soundsFileURL);
            }
        } else {
            // 其他情况, 具体请看这里`AVAssetExportSessionStatus`.
            NSLog(@"合并失败----%ld", (long)session.status);
            if (completed) {
                completed(nil,nil);
            }
        }
    }];
}
iOS15以下方案不变,通过循环递归推送多条语音信息来实现////循环调用本地通知,播放音频文件
-(void)pushLocalNotificationIniOS14ToApp:(NSInteger)index withArray:(NSArray *)tmparray completed:(XSNotificationPushCompleted)completed{
    __block NSInteger tmpindex = index;
    if(tmpindex < [tmparray count]){
        NSString *audioFileURL = tmparray[tmpindex];
        NSString * mp3Name = [audioFileURL lastPathComponent];
        
        
        AVURLAsset *audioAsset=[AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:audioFileURL] options:nil];
        //获取本地mpe3e文件时长
        CMTime audioDuration = audioAsset.duration;
        float audioDurationSeconds = CMTimeGetSeconds(audioDuration);
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];

        UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; //标题
        content.sound = [UNNotificationSound soundNamed:[NSString stringWithFormat:@"%@",mp3Name]];
        content.body = @"";

        // repeats,是否重复,如果重复的话时间必须大于60s,要不会报错
        UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:0.01  repeats:NO];
        /* */
        //添加通知的标识符,可以用于移除,更新等搡作
        NSString * identifier = [[NSUUID UUID] UUIDString];
        UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger];
        [center addNotificationRequest:request withCompletionHandler:^(NSError *_Nullable error) {
            //第一条推送成功后,递归执行
            float time = audioDurationSeconds+0.1;
            if (![mp3Name containsString:@"pre"]) {
                time = 0.4;
            }
            tmpindex = tmpindex+1;
            dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, time * NSEC_PER_SEC);
            dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
                [self pushLocalNotificationIniOS14ToApp:tmpindex withArray:tmparray  completed:completed];
            });
        }];
    }else{
        completed();
    }
}

参考:

https://www.jianshu.com/p/a01c0b59b9c4

https://juejin.cn/post/7026639897289031687

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
一篇教会你写90%的shell脚本!
shell是外壳的意思,就是操作系统的外壳。我们可以通过shell命令来操作和控制操作系统,比如Linux中的Shell命令就包括ls、cd、pwd等等。总结来说,Shell是一个命令解释器,它通过接受用户输入的Shell命令来启动、暂停、停止程序的运行或对计算机进行控制。
用户7118337
2020/04/12
1.9K0
shell-编写shell脚本所需的基础语法
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
洋仔聊编程
2019/09/18
9190
shell-编写shell脚本所需的基础语法
Shell 学习[通俗易懂]
Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。
全栈程序员站长
2022/09/09
6920
Linux的Shell编程语法集锦
【GiantPandaCV导语】相信在linux服务器环境下完成算法开发和部署的同学,都有使用shell来实现部分自动化功能的经历,本文就来给大家分享我总结的一些shell语法知识,希望对大家有帮助。
BBuf
2021/08/19
1.7K0
Shell base用法描述
bash中的字符串可以用单引号和双引号,其区别就是,单引号内不能解释变量,而双引号内可以解释变量
郭顺发
2023/07/06
3630
Shell
vim调试,/{匹配字符}可以查找相应的位置,N往后查找下一个,shift+N往前。
matt
2022/10/25
1.3K0
Shell 编程语法基础
在Shell脚本中,定义变量直接赋值即可,使用变量时需要在变量名前加美元符号$,注意定义变量时变量名和等号之间不能有空格。 变量名的命名必须遵循以下规则:
嵌入式视觉
2022/09/05
2.3K0
Shell 编程语法基础
shell基础编程(一)
引言:之前的初识shell的内容简单的介绍了一下shell,帮助大家认识了一下shell 的组成,这篇文章就具体的讲解shell有关的知识。如果大家有编程基础的话。接下来几篇的文章读起来都会非常容易。没有的话也没有关系,我尽最大的可能讲的通俗易懂。那么现在就开始吧
找Bug
2022/12/14
4640
shell基础编程(一)
高级shell脚本编程指南_python的快速入门
什么是shell呢?shell是用C语言编写的程序,它是用户使用 Linux 的桥梁。Shell既是一种命令语言,又是一种程序设计语言。简单来说Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。也可以这样认为,linux中的shell就是linux内核的一个外层保护工具,并负责完成用户与内核之间的交互
全栈程序员站长
2022/11/09
3.2K0
高级shell脚本编程指南_python的快速入门
Mac下Shell脚本基础用法
因为不常用shell,老是边用边查,现在做个小笔记。所有内容来源:Shell 教程
傅_hc
2020/11/03
4.9K0
Mac下Shell脚本基础用法
一篇文章让你彻底掌握 Shell
Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。
硬件开源小站
2023/04/07
2.2K0
4. shell 语法
shell脚本可以直接在命令行中执行,也可以将一套逻辑组织成一个文件,方便复用。 Terminal中的命令行可以看成是一个“shell脚本在逐行执行”。
浪漫主义狗
2022/09/28
2.5K0
Shell基础入门
Shell基础入门 linux系统是如何操作计算机硬件CPU,内存,磁盘,显示器等?使用linux的内核操作计算机的硬件Shell介绍... Shell计算命令 Shell计算命令:expr命令
乐心湖
2021/01/18
2.4K0
Shell基础入门
Linux命令(二)——shell编程
Unix/Linux上常见的Shell脚本解释器有bash、sh、csh、ksh等,习惯上把它们称作一种Shell。我们常说有多少种Shell,其实说的是Shell脚本解释器。
不愿意做鱼的小鲸鱼
2022/09/26
3.9K0
shell 基本语法
jenkins 上构建项目时,经常需要借助 shell 脚本,最近也经常跟服务器打交道,顺便记录些常用命令,方便查阅
请叫我大苏
2019/11/27
1.3K1
Shell编程快速入门指南
字符串可以使用单引号和双引号,单引号中不能包含单引号,即使转义单引号也不次那个,双引号则可以,双引号也可以使用字符串。
用户1515472
2019/07/24
7500
一文掌握shell脚本的基本语法
欢迎大家star我的GitHub:https://github.com/SolerHo/geeks-shell,建议直接使用GitHub来查看排版,发现markdown有错位的情况。
阳光罗诺
2022/01/03
4.2K0
一文掌握shell脚本的基本语法
Shell 快速指南
本文介绍了Linux Shell 的基础知识,包括基本概念、常用命令、快捷键和实用技巧。同时,还介绍了如何通过脚本和工具实现自动化和效率提升。
静默虚空
2018/01/05
3.4K0
Linux Shell编程入门
注意:bash是 Bourne Again Shell 的缩写,是linux标准的默认shell ,它基于Bourne shell,吸收了C shell和Korn shell的一些特性。bash完全兼容sh,也就是说,用sh写的脚本可以不加修改的在bash中执行。
程裕强
2022/05/06
3.1K0
linux shell指令大全整理
所有程序, 包括shell启动的程序, 都能访问环境变量, 在c中通过system()函数执行的结果可以通过环境变量传递回来
全栈程序员站长
2022/11/02
1.7K0
相关推荐
一篇教会你写90%的shell脚本!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验