在iOS上开始在后台播放声音?

我正在尝试做类似于
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代码.

点赞