iOS开发 - NotificationService语音播报

iOS NotificationService语音播报

最近碰到个接收到推送要实现语音播报的需求,需要后台推送通知,APP客户端收到通知之后语音播放:“您的账户收到一笔巨款”的功能。

因为工程之前已经集成了极光推送服务。这里直接使用Notification Service Extension通知服务扩展

Notification Service Extension 简单说我们在收到推送且在弹框展示之前,对通知内容进行修改(只针对远程推送)。

一 主工程需要如下配置:

设置Background Modes

iOS开发 - NotificationService语音播报_第1张图片

二 IOS 10 创建Notification Service Extension

创建Notification Service Extension的target

iOS开发 - NotificationService语音播报_第2张图片

创建后系统会生成NotificationService.h和NotificationService.m两个文件。

设置下Targets中的NotificationService的 Push Notifications

iOS开发 - NotificationService语音播报_第3张图片

三 使用AVSpeechUtterance

在NotificationService中代码


#import "NotificationService.h"
#import 
#import 

@interface NotificationService ()

@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);

@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;

@property (nonatomic, strong) AVSpeechSynthesisVoice *synthesisVoice;
@property (nonatomic, strong) AVSpeechSynthesizer *synthesizer;

@end

@implementation NotificationService

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    
    // 这个info 内容就是通知信息携带的数据,后面我们取语音播报的文案,通知栏的title,以及通知内容都是从这个info字段中获取
    NSString *type = self.bestAttemptContent.userInfo[@"type"];
    
    NSString *typeStr = [NSString stringWithFormat:@"%@",type];
    // 语音播报
    if (7 == typeStr.integerValue) {
        // 类型为7
        NSString *info = self.bestAttemptContent.userInfo[@"content"];
        // 播报语音
        [self playVoiceWithContent:info];
    }
    
    
    // 这行代码需要注释,当我们想解决当同时推送了多条消息,这时我们想多条消息一条一条的挨个播报,我们就需要将此行代码注释
    //    self.contentHandler(self.bestAttemptContent);
}

- (void)playVoiceWithContent:(NSString *)content {
    if (!(content && [content isKindOfClass:[NSString class]] && content.length > 0)) {
        return;
    }
    
    AVSpeechUtterance *utterance = [AVSpeechUtterance speechUtteranceWithString:content];
    utterance.rate = 0.5;
    utterance.voice = self.synthesisVoice;
    [self.synthesizer speakUtterance:utterance];
}

// 新增语音播放代理函数,在语音播报完成的代理函数中,我们添加下面的一行代码
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer didFinishSpeechUtterance:(AVSpeechUtterance *)utterance {    
    // 每一条语音播放完成后,我们调用此代码,用来呼出通知栏
    self.contentHandler(self.bestAttemptContent);
}

- (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);
}

// 调试,代替debug
- (void)playVoice:(NSString *)info {
    AVSpeechSynthesizer *av = [[AVSpeechSynthesizer alloc] init];
    AVSpeechSynthesisVoice *voice = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
    AVSpeechUtterance *utterance = [[AVSpeechUtterance alloc] initWithString:info];
    utterance.rate = 0.5;
    utterance.voice= voice;
    [av speakUtterance:utterance];
}

- (AVSpeechSynthesisVoice *)synthesisVoice {
    if (!_synthesisVoice) {
        _synthesisVoice = [AVSpeechSynthesisVoice voiceWithLanguage:@"zh-CN"];
    }
    return _synthesisVoice;
}

- (AVSpeechSynthesizer *)synthesizer {
    if (!_synthesizer) {
        _synthesizer = [[AVSpeechSynthesizer alloc] init];
        _synthesizer.delegate = self;
    }
    return _synthesizer;
}

@end

四 IOS 10之前版本在AppDelegate中的设置


- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    DebugLog(@"收到通知:%@", userInfo);
    
    [[DFAVSpeechManager sharedInstance] playAVSpeechUserInfo:userInfo completion:nil];
    
    completionHandler(UIBackgroundFetchResultNewData);
}

五 IOS 设置app打开的时候在前台的推送栏显示

如果是语音播报,这里我设置需要显示推送栏。


#pragma mark - IOS10 LaterNotification UNUserNotificationCenterDelegate Methods
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
    DebugLog(@"willPresentNotification");
    
    NSDictionary * userInfo = notification.request.content.userInfo;
    UNNotificationRequest *request = notification.request; // 收到推送的请求
    UNNotificationContent *content = request.content; // 收到推送的消息内容
    NSNumber *badge = content.badge;  // 推送消息的角标
    NSString *body = content.body;    // 推送消息体
    UNNotificationSound *sound = content.sound;  // 推送消息的声音
    NSString *subtitle = content.subtitle;  // 推送消息的副标题
    NSString *title = content.title;  // 推送消息的标题
    
    if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        DebugLog(@"iOS10 前台收到远程通知:%@",userInfo);
    } else {
        // 判断为本地通知
        DebugLog(@"iOS10 前台收到本地通知:{nbody:%@,ntitle:%@,nsubtitle:%@,nbadge:%@,nsound:%@,nuserInfo:%@n}",body,title,subtitle,badge,sound,userInfo);
    }
    
    BOOL needShowPushColum = [[DFAVSpeechManager sharedInstance] canShowPushColumn:userInfo];
    if (needShowPushColum) {
        //前台接到推送展示 则需要执行这个方法,选择是否提醒用户,有Badge、Sound、Alert三种类型可以设置
        completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);
    } else {
        //前台接到推送不展示
        completionHandler(0);
    }
}

六 在极光后台设置进行推送

在极光后台设置进行推送

当然特别需要注意的地方是如果服务器推送语音播报,需要设置mutable-content为1 或 true

iOS开发 - NotificationService语音播报_第4张图片

你可能感兴趣的:(iphone开发,移动开发,Objective-c,ios,cocoa,macos)