一、简介
在iOS 10 之前,苹果没有提供通知扩展类的时候,如果想要实现杀进程也可以正常播报语音消息很难,从ios 10添加了这一个通知扩展类后,实现杀进程播报语音就相对简单很多了。
Notification Service Extension 就是苹果在 iOS 10的新系统中为我们添加的新特性,这个新特性就能帮助我们用来解决杀死进程正常语音播报。流程如下:
Server-Side App —》Notification Payload —》APNS —》Server Extension —》Modified Payload —》Notification Content
二、实现详细步骤
1、创建一个通知扩展类
Xcode -> File -> New -> Target -> Notification Service Extension
2、添加语音播报逻辑代码
【1】使用苹果官方提供的AVFoundation框架里面的AVSpeechSynthesizer,AVSpeechSynthesisVoice,AVSpeechUtterance。打开NotificationSE文件夹,在NotificationService.m 文件中,添加语音播报逻辑代码。
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
//修改通知内容
self.bestAttemptContent.title = [NSString stringWithFormat:@"%@ [modified]", self.bestAttemptContent.title];
//如果想解决当同时推送了多条消息,这时我们想多条消息一条一条的挨个播报,我们就需要将此行代码注释
//self.contentHandler(self.bestAttemptContent);
//获取通知信息数据:语音播报的文案 + 通知栏的title + 以及通知内容
NSDictionary* infoDict=self.bestAttemptContent.userInfo;
//调用语音合成并播放出语音方法
[self playVoiceWithContent:infoDict[@"content"]];
}
- (void)serviceExtensionTimeWillExpire {
self.contentHandler(self.bestAttemptContent);
}
-(void)playVoiceWithContent:(NSString *)content{
AVSpeechUtterance* utterance=[AVSpeechUtterance speechUtteranceWithString:content];
utterance.rate = 0.5;
utterance.voice = self.synthesisVoice;
[self.synthesizer speakUtterance:utterance];
}
#pragma mark - <AVSpeechSynthesizerDelegate>
// 新增语音播放代理函数,在语音播报完成的代理函数中,我们添加下面的一行回调代码
-(void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance
{
self.contentHandler(self.bestAttemptContent);
}
#pragma mark - Lazy Loading
- (AVSpeechSynthesisVoice *)synthesisVoice {
if (!_synthesisVoice) {
_synthesisVoice = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
}
return _synthesisVoice;
}
- (AVSpeechSynthesizer *)synthesizer {
if (!_synthesizer) {
_synthesizer = [[AVSpeechSynthesizer alloc] init];
_synthesizer.delegate = self;//设置委托
}
return _synthesizer;
}
3、设置支持后台播放
Xcode -> Targets -> Capabilities -> Background Modes -> 勾选第一项和最后两项
4、iOS10 以下系统如何实现串行播报
在AppDelegate.m文件中,添加如下代码:
//监听通知函数中调用添加数据到队列
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
[self addOperation:@"语音内容"];
}
#pragma mark - 推送通知(主队列管理)
- (void)addOperation:(NSString *)title {
[[self mainQueue] addOperation:[self customOperation:title]];
}
- (NSOperationQueue *)mainQueue {
return [NSOperationQueue mainQueue];
}
- (NSOperation *)customOperation:(NSString *)content {
NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:^{
AVSpeechUtterance *utterance = nil;
@autoreleasepool {
utterance = [AVSpeechUtterance speechUtteranceWithString:content];
utterance.rate = 0.5;
}
utterance.voice = self.voiceConfig;//合成的语音
[self.synthConfig speakUtterance:utterance];//播放的语音
}];
return operation;
}
#pragma mark - Lazy Loading
- (AVSpeechSynthesisVoice *)voiceConfig {
if (_voiceConfig == nil) {
_voiceConfig = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
}
return _voiceConfig;
}
- (AVSpeechSynthesizer *)synthConfig {
if (_synthConfig == nil) {
_synthConfig = [[AVSpeechSynthesizer alloc] init];
}
return _synthConfig;
}
5、注意事项
【1】当通知栏收起时,扩展类就会被系统终止,扩展内里面的代码也会终止执行,只有当下一个通知栏弹出来,扩展类就恢复功能。苹果规定,当一条通知达到后,如果在30秒内,还没有呼出通知栏,我就系统强制调用self.contentHandler(self.bestAttemptContent) 来呼出通知栏。
【2】上面的通知扩展类最低支持iOS系统为 10及10 以上,所以所 iOS10以下的系统,是不支持使用通知扩展的.
【3】添加支持后台播放时,可能会被苹果拒审。