本文字数:4293字
预计阅读时间:33分钟
一:背景
iOS 推送播放语音的需求调研,即收到推送后,播放推送的文案,文案的内容不固定。类似于支付宝和微信的收款到账语音。
-
只有iOS10以上才支持app被唤醒后在后台/锁屏状态下播放音频。所以iOS10以下的设备,在收到VoIP Push后只能在local push上设定一段固定铃声,这也是为什么iOS10以下只有“微信支付收款到账”。
-
iOS 12.0之前,后台播放音频未被限制,直接使用Notification Service Extension (iOS 10.0以后才支持) 功能使用系统提供的功能AVSpeechSynthesizer即可。
-
iOS 12.0之后,Notification Service Extension后台播放音频功能被限制,所以播放实现起来比较困难。
-
如果要上架商店,只有播放固定的音频,或固定拼接的音频,通过设置通知的声音或者发送本地通知设置本地通知的声音来播放。
-
如果无需上架商店,可以手动打开Notification Service Extension的后台播放。
二:开发过程
a. Notification Service Extension
项目添加了Notification Service Extension之后的逻辑,和没添加之前有所不同。如下图:添加了之后,接受到推送时,会触发Notification Service Extension中的方法,在这个方法中,可以修改推送的标题、内容、声音。然后把修改后的推送展示出来。
通知栏的生命周期:
-
从通知叮一下展示(触发代码:self.contentHandler(self.bestAttemptContent);)出来到通知被收起(系统控制),大概有6秒左右的时间。
-
如果收到通知后,没有呼出通知栏,最多30s系统会调用serviceExtensionTimeWillExpire方法中的self.contentHandler(self.bestAttemptContent)来呼出通知栏。
要注意的是,Notification Service Extension和主项目不是同一个Target,所以主项目的文件和这个Target文件是不共享的。
-
创建新文件的时候要注意勾选要添加到的Target
-
比如添加推送播放语音的类,需要勾选到Notification Service Extension Target下;
-
拷贝播放语音的第三方SDK,需要勾选到Notification Service Extension Target下;
-
在第三方平台创建新应用时,要填写的bundleID也应该是Notification Service Extension Target对应的bundleID。,这点尤其要注意,因为百度的测试账号离线SDK的添加只能添加一次,错了的话,就要用新的账号再去注册,血泪的教训,????。
-
-
bundle目录的访问也不是同一个,可以通过App Group共享数据。
-
打开后台播放时,其实也应该是Notification Service Extension Target下的后台播放,这个后面详细说明。
创建步骤如下:
-
创建Notificaiton Service Extension Target,选中Xcode项目,点击File -> New -> Target,选中Notification Service Extension Target。有两个很相似的,注意选对,如下图:
-
点击Next,输入Product Name
-
点击完成,点击Activate
-
打开NotificationService.m中的文件,这个类就是Notificaiton Service Extension添加后自动创建的类,添加了之后,接受到推送的处理都可以在这个位置修改
-
其中修改推送铃声时要注意:
-
多条推送处理的问题,在didReceiveNotificationRequest:withContentHandler:方法中调用self.contentHandler(self.bestAttemptContent);,即会展示对应的通知,如果不调用此方法,最多30s系统会自动调用此方法,假设一次性来了10条通知,会发现,通知并没有弹出10次,也没有按顺序一次次展示,所以多条推送如果没有处理,播放语音时就会出现问题。
-
语音的文件类型:自定义铃声支持的声音格式包括,aiff、wav以及wav格式,铃声的长度必须小于30s,否则系统会播放默认的铃声。
-
音频文件存储的目录和读取的优先级,主应用中的Library/Sounds文件夹中、AppGroups共享目录中的Library/Sounds文件夹中、main bundle
-
在系统播放类AVSpeechSynthesizer的代理方法中,有播放完成的回掉speechSynthesizer:didFinishSpeechUtterance:,把呼出通知栏的代码self.contentHandler(self.bestAttemptContent)从didReceiveNotificationRequest:withContentHandler:方法中,移到播放完成的回掉方法中调用,即可保证语音按顺序一条条展示。(或者添加到数组或着OperationQueue中,播放完成继续下一条)
-
didReceiveNotificationRequest:withContentHandler:方法,其中的bestAttemptContent中的userInfo即包含了推送的详细信息。如果想要修改展示的标题和内容或者推送的语音,都在这个方法最后回掉前操作,
-
@interface NotificationService ()
@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;
@end
@implementation NotificationService
- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
self.contentHandler = contentHandler;
self.bestAttemptContent = [request.content mutableCopy];
// Modify the notification content here...
// 修改推送的标题
// self.bestAttemptContent.title = [NSString stringWithFormat:@"%@ [modified]", self.bestAttemptContent.title];
// 修改推送的声音,自定义铃声支持的声音格式包括,aiff、wav以及wav格式,铃声的长度必须小于30s,否则系统会播放默认的铃声。
// se