在 iOS 开始在后台播放声音?
Start playing sound in background on iOS?
我正在尝试做类似于 Tile.app 的事情。当它显示通知时,它会播放声音。这看起来很简单——使用 UILocalNotification
并包含声音文件名。但是本地通知将声音限制在不超过 30 秒,而 Tile 的声音持续播放的时间比这长得多。我希望它会循环播放,并且会一直播放,直到我再也无法忍受噪音为止。
即使 phone 的静音开关打开,声音也会播放,本地通知不会发生这种情况。由于这些原因,UILocalNotification
似乎出局了。
我想也许我可以 post 纯文本本地通知并让我的应用程序播放声音。但是使用AVAudioPlayer
,play
方法returns NO
,声音没有播放。
Other questions have suggested that this is by design, that apps aren't supposed to be able to play sounds from the background-- only continue sound that's already playing. I'd accept that reasoning except that Tile does it, so it's obviously possible. One suggested workaround 以某种方式违反了 Apple 的准则,我很确定 Apple 现在会检查。
一些可能相关的细节:
- 我在 Info.plist
中有 audio
背景模式
- 我在音频会话上使用
AVAudioSessionCategoryPlayback
,会话应该是活跃的(至少,setActive:error:
声称成功)。
- 此应用使用蓝牙,但目前不使用
bluetooth-central
后台模式。
来自官方Apple documentation:
"Custom sounds must be under 30 seconds when played. If a custom sound
is over that limit, the default system sound is played instead."
您无法 UILocalNotication
循环播放声音。您可以以 30 秒的时间间隔再次安排它,但那将是另一个警报的安排。
要设置您的自定义通知声音:
notif.soundName = @"sound.caf";
确保声音确实在您的应用程序包中,格式正确(线性 PCM 或 IMA4——几乎所有解释如何为 iOS 转换声音的地方都会告诉您如何操作) , 不到 30 秒。
实际上您可以使用 AudioServices...
函数之一
AudioServicesPlaySystemSound
AudioServicesPlayAlertSound
AudioServicesPlaySystemSoundWithCompletion
开始在后台播放声音。
我不确定可以提交给 AudioServicesCreateSystemSoundID
的声音长度,因为我只用短循环声音检查铃声,但这个 API 与通知无关,所以可以立交桥 30 秒限制。
编辑:
应用程序仍需要 UIBackgroundModes
中的 audio
才能在后台播放
从我的测试项目appDelegate中截取,iOS9.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
启动声音只是作为在另一个项目中在后台执行代码的最简单方法,类似于 registerAndPlaySound
的代码是从 PushKit
回调中调用的,没有后台任务。
我正在尝试做类似于 Tile.app 的事情。当它显示通知时,它会播放声音。这看起来很简单——使用 UILocalNotification
并包含声音文件名。但是本地通知将声音限制在不超过 30 秒,而 Tile 的声音持续播放的时间比这长得多。我希望它会循环播放,并且会一直播放,直到我再也无法忍受噪音为止。
即使 phone 的静音开关打开,声音也会播放,本地通知不会发生这种情况。由于这些原因,UILocalNotification
似乎出局了。
我想也许我可以 post 纯文本本地通知并让我的应用程序播放声音。但是使用AVAudioPlayer
,play
方法returns NO
,声音没有播放。
Other questions have suggested that this is by design, that apps aren't supposed to be able to play sounds from the background-- only continue sound that's already playing. I'd accept that reasoning except that Tile does it, so it's obviously possible. One suggested workaround 以某种方式违反了 Apple 的准则,我很确定 Apple 现在会检查。
一些可能相关的细节:
- 我在 Info.plist 中有
- 我在音频会话上使用
AVAudioSessionCategoryPlayback
,会话应该是活跃的(至少,setActive:error:
声称成功)。 - 此应用使用蓝牙,但目前不使用
bluetooth-central
后台模式。
audio
背景模式
来自官方Apple documentation:
"Custom sounds must be under 30 seconds when played. If a custom sound is over that limit, the default system sound is played instead."
您无法 UILocalNotication
循环播放声音。您可以以 30 秒的时间间隔再次安排它,但那将是另一个警报的安排。
要设置您的自定义通知声音:
notif.soundName = @"sound.caf";
确保声音确实在您的应用程序包中,格式正确(线性 PCM 或 IMA4——几乎所有解释如何为 iOS 转换声音的地方都会告诉您如何操作) , 不到 30 秒。
实际上您可以使用 AudioServices...
函数之一
AudioServicesPlaySystemSound
AudioServicesPlayAlertSound
AudioServicesPlaySystemSoundWithCompletion
开始在后台播放声音。
我不确定可以提交给 AudioServicesCreateSystemSoundID
的声音长度,因为我只用短循环声音检查铃声,但这个 API 与通知无关,所以可以立交桥 30 秒限制。
编辑:
应用程序仍需要 UIBackgroundModes
中的 audio
才能在后台播放
从我的测试项目appDelegate中截取,iOS9.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
启动声音只是作为在另一个项目中在后台执行代码的最简单方法,类似于 registerAndPlaySound
的代码是从 PushKit
回调中调用的,没有后台任务。