iOS10技术之实现通知服务扩展(NotificationServiceExtension)

一、简介
在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】添加支持后台播放时,可能会被苹果拒审。

原文地址:https://www.cnblogs.com/yuhao309/p/9914350.html