我正在尝试做类似于
Tile.app的事情.当它显示通知时,它会发出声音.这似乎很简单 – 使用UILocalNotification并包含声音文件名.但是本地通知将声音限制在不超过30秒,并且Tile的声音持续播放的时间比这长得多.我希望它能够循环播放,并且一直持续到我再也无法忍受噪音了.
即使手机的静音开关打开,声音也会播放,但本地通知不会发生这种情况.由于这些原因,UILocalNotification似乎已经出局.
我想也许我可以发布一个纯文本的本地通知,让我的应用播放声音.但是使用AVAudioPlayer,播放方法返回NO并且声音不播放.
Other questions建议这是设计的,应用程序不应该能够从后台播放声音 – 只能继续播放已经播放的声音.我接受这个推理,除了Tile这样做,所以它显然是可能的.一个suggested workaround违反了Apple的指导方针,我很确定Apple现在会检查.
一些可能相关的细节:
>我在Info.plist中有音频背景模式
>我在音频会话上使用AVAudioSessionCategoryPlayback,会话应该是活动的(至少,setActive:error:声明成功).
>此应用程序使用蓝牙,但目前不使用蓝牙中央后台模式.
最佳答案 实际上你可以使用AudioServices …函数之一
> AudioServicesPlaySystemSound
> AudioServicesPlayAlertSound
> AudioServicesPlaySystemSoundWithCompletion
开始在后台播放声音.
我不确定可以提交给AudioServicesCreateSystemSoundID的声音长度,因为我只检查了短循环声音,但这个API与通知无关,因此可能超过30秒限制.
编辑:
应用程序仍然需要UIBackgroundModes中的音频才能在后台播放
从我的测试项目appDelegate,iOS 9.3.1中删除
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// test sound in foreground.
registerAndPlaySound()
return true
}
func applicationDidEnterBackground(application: UIApplication) {
var task = UIBackgroundTaskInvalid
task = application.beginBackgroundTaskWithName("time for music") {
application.endBackgroundTask(task)
}
// dispatch not required, it's just to simulate "deeper" background
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(5 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
self.registerAndPlaySound()
}
}
func registerAndPlaySound() {
var soundId: SystemSoundID = 0
let bundle = NSBundle.mainBundle()
guard let soundUrl = bundle.URLForResource("InboundCallRing", withExtension: "wav") else {
return
}
AudioServicesCreateSystemSoundID(soundUrl, &soundId)
AudioServicesPlayAlertSound(soundId)
}
更新
在那里,我使用beginBackgroundTask来启动声音,这只是在另一个项目中在后台执行代码的最简单方法.在没有后台任务的情况下,从PushKit回调中调用了类似的registerAndPlaySound代码.