iOS 后台语音播报功能开发过程中的那些坑

  上个版本的开发计划中产品同学建议在我们的商家版App中做后台语音播报功能,在评审的时候我就在想,完全可以通过Push静默推送来实现后台播放音频来实现(后续事实证明,这是个大坑)。
  关于静默推送 推荐大家看一下https://www.jianshu.com/p/c211bd295d58
  好了,最后通过pushbackGroundModes实现了在后台语言播放的功能,工程的配置:

iOS 后台语音播报功能开发过程中的那些坑_第1张图片
547D3DE966C4637E807605E0ED326C91.jpg

  关于BackGroundModes推荐大家看一下 https://www.jianshu.com/p/121fc5b7f2d3
  测试环境一切正常,testflight也一切正常,然后提交审核,然后就悲剧了。被拒的原因的大概意思就是你开启了后台挂起播放音频的功能需要演示视频。
  然后我周末跑去公司录制了视频上传到YouTuBe,为了安心我还上传到了优酷,两个链接扔上去,提交审核,这些稳了吧。然后又被拒了。
iOS 后台语音播报功能开发过程中的那些坑_第2张图片
18DBCB5F5E6178B5EFAB1D17F7F4BD5F.jpg

  然后被拒原因大概是我还是看不到你哪里用了后台播放音频呀。
iOS 后台语音播报功能开发过程中的那些坑_第3张图片
image.png

  然后我就懵逼了,查了一天的资料,终于大概理解了苹果审核人员的意思,静默推送苹果爸爸的初衷是用了在后台的时候处理数据刷新相关的,静默、静默的意思就是不打扰用户,然后我用它来做语音播报显然是违背了静默推送的初衷,然后只能换思路了。
  在iOS 10 UNNotificationServiceExtension 刚出现的时候了解过,然后在后续没有用到就忘的差不多了,在对它进一步了解之后,我发现它完全能够在不开启后台运行相关功能的情况下来实现语音播报功能,好吧,开始动手:
  在你的功能首先创建UNNotificationServiceExtension target
iOS 后台语音播报功能开发过程中的那些坑_第4张图片
image.png

Service ExtensionBundle Identifier不能和Main Target(也就是你自己的App Target)的Bundle Identifier相同,否则会报BundeID重复的错误。
Service Extension的Bundle Identifier需要在Main Target的命名空间下,比如说Main Target的BundleID为io.jpush.xxx,那么Service Extension的BundleID应该类似与io.jpush.xxx.yyy这样的格式。如果不这么做,你可能会遇到一个错误。
  创建好了把相关音频文件导入:
image.png

在下面方法做相关数据处理

- (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];
    
    [[AVAudioSession sharedInstance] setActive:YES error:NULL];
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    NSDictionary *userInfo = self.bestAttemptContent.userInfo;
    NSDictionary * aps = [userInfo objectForKey:@"aps"];
    NSString * soundCommand = [aps valueForKey:@"soundCommand"];
    [self playSoundsWithSoundCommand:soundCommand];
    self.contentHandler(self.bestAttemptContent);
}
/*播放*/
-(void)playWithFileUrlString:(NSString *)fileURLString{
    if (![fileURLString length]) {
        return;
    }
    AVAudioSession * session = [AVAudioSession sharedInstance];
    [session setActive:YES error:nil];
    BOOL ret =  [session setCategory:AVAudioSessionCategoryPlayback error:nil];
    NSLog(@"%d",ret);
    NSURL *fileURL = [[NSBundle mainBundle]URLForResource:fileURLString withExtension:@".mp3"];
    
    static SystemSoundID soundID = 0;
    
    AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(fileURL), &soundID);
    
    AudioServicesPlayAlertSoundWithCompletion(soundID, ^{
        NSLog(@"播放完成");
    });
}

  记住了在做完相关操作之后再调用self.contentHandler(self.bestAttemptContent);方法 进入墓碑模式(不执行应用程序的任何代码)
  还有很重要的一点,记住push的试试让后台同学要加入一个参数"mutable-content" = 1;,不然我们的扩展类方法是拦截不到推送的哦,要和alert 同级的,位置不要错。

iOS 后台语音播报功能开发过程中的那些坑_第5张图片
image.png

  接下来运行-测试,完美实现。打包,然后又报错了,看了原因是因为扩展target和我的原来工程的签名不是同一team,这时候就要用的appid创建的时候创建一个通配符appid了。
  在你开发者中心创建一个通配符appid包含到你的扩展应用下,然后生成相关开发和生成Profile文件,下载下来,然后打包。成功!!!
  接下来就是等待苹果爸爸的审核了,不过十拿九稳啦~
  参考文档:https://www.jianshu.com/p/db9c4aec2b93

重要补充:

  在iOS12.1之后苹果爸爸禁用了UNNotificationServiceExtension 在后台使用AVAudioSession播放语音文件,解决方法是我们拿到- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler方法里面的bestAttemptContent给他的sound赋值一下就OK了。

self.bestAttemptContent.sound = [UNNotificationSound soundNamed:[NSString stringWithFormat:@"%@.mp3",fileURLString]];

  这里提一下如果用这种方法播放语音文件相应的语音资源需要导入到主程序中,不能放在UNNotificationServiceExtension中。
  再次补充这种方法只能在后台播放语音,前台播放需要另外到主程序中去实现。

你可能感兴趣的:(iOS 后台语音播报功能开发过程中的那些坑)