如何让背景音乐继续播放而我的应用程序在使用 Swift 时仍然播放其声音
Posted
技术标签:
【中文标题】如何让背景音乐继续播放而我的应用程序在使用 Swift 时仍然播放其声音【英文标题】:How can I allow background music to continue playing while my app still plays its sounds while using Swift 【发布时间】:2015-03-13 03:17:32 【问题描述】:我创建了一个应用程序,我试图让用户在玩我的游戏时继续听他们的音乐,但只要他们点击“播放”并且游戏中的声音出现,它就会停止背景音乐。我正在使用 Swift 在 ios 上进行开发。这是一段启动游戏声音的代码。
func playSpawnedDot()
var alertSound: NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("spawnDot", ofType: "mp3")!)!
var error:NSError?
audioPlayer = AVAudioPlayer(contentsOfURL: alertSound, error: &error)
audioPlayer.prepareToPlay()
if volumeBool
audioPlayer.play()
【问题讨论】:
【参考方案1】:您需要将AVAudioSession
类别设置为以下值之一:https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVAudioSession_ClassReference/index.html(AVAudioSession 类参考)。
默认值设置为AVAudioSessionCategorySoloAmbient
。如您所见:
[...] 使用此类别意味着您的应用程序的音频是不可混合的——激活您的会话将中断任何其他同样不可混合的音频会话。要允许混合,请改用
AVAudioSessionCategoryAmbient
类别。
在播放声音之前,您必须更改类别。这样做:
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient, error: nil)
AVAudioSession.sharedInstance().setActive(true, error: nil)
您无需在每次播放声音时都调用这些线路。你可能只想做一次。
【讨论】:
这在 swift 2.0 中不再有效。有更新的代码吗? 这对我有用 try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient) try AVAudioSession.sharedInstance().setActive(true) catch let error as NSError print(error) 跨度> 如果您无法将此代码适应新版本的 Swift,请尝试使用以下代码:try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient)
【参考方案2】:
Swift 4 版本:
try? AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient)
try? AVAudioSession.sharedInstance().setActive(true)
【讨论】:
别忘了import AVFoundation
一旦你的声音播放完毕,不要忘记将setActive
设置为false,否则,即使播放完成,背景音乐也会保留。【参考方案3】:
这就是我在 Swift 3.0 中的做法
var songPlayer : AVAudioPlayer?
func SetUpSound()
if let path = Bundle.main.path(forResource: "TestSound", ofType: "wav")
let filePath = NSURL(fileURLWithPath:path)
songPlayer = try! AVAudioPlayer.init(contentsOf: filePath as URL)
songPlayer?.numberOfLoops = -1 //logic for infinite loop
songPlayer?.prepareToPlay()
songPlayer?.play()
let audioSession = AVAudioSession.sharedInstance()
try!audioSession.setCategory(AVAudioSessionCategoryPlayback, with: AVAudioSessionCategoryOptions.duckOthers) //Causes audio from other sessions to be ducked (reduced in volume) while audio from this session plays
您可以在此处查看更多 AVAudioSessionCategoryOptions:https://developer.apple.com/reference/avfoundation/avaudiosessioncategoryoptions
【讨论】:
将 (let audioSession...) AND (try!audioSession...) 行移到 if 条件之上以获得更好的结果。背景音乐也不会第一次停止。 (我在按钮操作中插入了 func SetUpSound() 代码) @Hamid Reza Ansari - 你的评论拯救了我的一天。谢谢!【参考方案4】:这是我在 Swift 2.0 中使用的:
let sess = AVAudioSession.sharedInstance()
if sess.otherAudioPlaying
_ = try? sess.setCategory(AVAudioSessionCategoryAmbient, withOptions: .DuckOthers)
_ = try? sess.setActive(true, withOptions: [])
请注意,如果您不想降低背景音乐并在上面播放,可以将.DuckOthers
替换为[]
。
【讨论】:
【参考方案5】:lchamp 的解决方案非常适合我,适用于 Objective-C:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
【讨论】:
【参考方案6】:**
为 Swift 3.0 更新
**
我正在播放的声音的名称是 shatter.wav
func shatterSound()
if let soundURL = Bundle.main.url(forResource: "shatter", withExtension: "wav")
var mySound: SystemSoundID = 0
AudioServicesCreateSystemSoundID(soundURL as CFURL, &mySound)
AudioServicesPlaySystemSound(mySound);
然后你想在哪里播放声音呼叫
shatterSound()
【讨论】:
【参考方案7】:因为他们似乎无法从一个版本到另一个版本下定决心。这是在 Swift 5.0 中
do
try AVAudioSession.sharedInstance().setCategory(.ambient)
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
catch
NSLog(error.localizedDescription)
【讨论】:
【参考方案8】:如果你想播放提示音:
public func playSound(withFileName fileName: String)
if let soundUrl = Bundle.main.url(forResource: fileName, withExtension: "wav")
do
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient, with:[.duckOthers])
try AVAudioSession.sharedInstance().setActive(true)
var soundId: SystemSoundID = 0
AudioServicesCreateSystemSoundID(soundUrl as CFURL, &soundId)
AudioServicesAddSystemSoundCompletion(soundId, nil, nil, (soundId, clientData) -> Void in
AudioServicesDisposeSystemSoundID(soundId)
do
// This is to unduck others, make other playing sounds go back up in volume
try AVAudioSession.sharedInstance().setActive(false)
catch
DDLogWarn("Failed to set AVAudioSession to inactive. error=\(error)")
, nil)
AudioServicesPlaySystemSound(soundId)
catch
DDLogWarn("Failed to create audio player. soundUrl=\(soundUrl) error=\(error)")
else
DDLogWarn("Sound file not found in app bundle. fileName=\(fileName)")
如果你想播放音乐:
导入 AVFoundation
var audioPlayer:AVAudioPlayer?
public func playSound(withFileName fileName: String)
if let soundUrl = Bundle.main.url(forResource: fileName, withExtension: "wav")
do
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryAmbient, with:[.duckOthers])
try AVAudioSession.sharedInstance().setActive(true)
let player = try AVAudioPlayer(contentsOf: soundUrl)
player.delegate = self
player.prepareToPlay()
DDLogInfo("Playing sound. soundUrl=\(soundUrl)")
player.play()
// ensure the player does not get deleted while playing the sound
self.audioPlayer = player
catch
DDLogWarn("Failed to create audio player. soundUrl=\(soundUrl) error=\(error)")
else
DDLogWarn("Sound file not found in app bundle. fileName=\(fileName)")
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool)
self.audioPlayer?.stop()
do
// This is to unduck others, make other playing sounds go back up in volume
try AVAudioSession.sharedInstance().setActive(false)
catch
DDLogWarn("Failed to set AVAudioSession inactive. error=\(error)")
【讨论】:
【参考方案9】:对于 Swift(Objective-C 也是这样)
您可以使用this 链接获得最佳答案,如果您没有时间观看 10 分钟,最好的做法是在 didFinishLaunchingWithOptions
中的 AppDelegate
中的代码下方 copy
,然后选择你的project's target
然后转到Capabilities
最后在Background modes
检查Audio, AirPlay and Picture in Picture
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
// Override point for customization after application launch.
let session = AVAudioSession.sharedInstance()
do
try session.setCategory(AVAudioSessionCategoryPlayback)
catch
【讨论】:
【参考方案10】:我不认为只是将 AVAudioSession 设置为 AVAudioSessionCategoryOptions.duckOthers 会起作用,但确实如此。这是我的完整代码,可以帮助像我这样的新手。
Swift 4 - 完整示例:
var audioPlayer = AVAudioPlayer()
func playSound(sound: String)
let path = Bundle.main.path(forResource: sound, ofType: nil)!
let url = URL(fileURLWithPath: path)
let audioSession = AVAudioSession.sharedInstance()
try!audioSession.setCategory(AVAudioSessionCategoryPlayback, with: AVAudioSessionCategoryOptions.duckOthers)
do
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer.play()
catch
print("couldn't load the file")
我仍然需要弄清楚 setActive (I was looking at this blog post),但是当我离开应用程序时音频停止闪避,因此它适用于我的应用程序。
【讨论】:
【参考方案11】:Swift 5 版本基于 lchamp 的回答。
try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.ambient)
try? AVAudioSession.sharedInstance().setActive(true)
【讨论】:
【参考方案12】:这对我来说非常适合 iOS 14.4 和 Swift 5。使用.duckOthers
选项与其他人的答案有点不同(如果您愿意,也可以直接与声音混合使用.mixWithOthers
),但它在播放音乐时完美运行。它将降低音乐音量,播放“哔”声,然后将音乐音量恢复到正常水平。如果出现问题,它还会使用 Google Firebase Crashlytics 捕获错误数据,并尝试在出现错误时将音量提高到正常水平。
此代码也可以在您的声音的第一次和所有其他播放中完美运行,而不会停止音乐。
func playSound()
do
if let path = Bundle.main.path(forResource: "beep", ofType: "mp3")
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: .duckOthers)
try AVAudioSession.sharedInstance().setActive(true)
let filePath = NSURL(fileURLWithPath:path)
songPlayer = try AVAudioPlayer.init(contentsOf: filePath as URL)
songPlayer?.numberOfLoops = 0
songPlayer?.prepareToPlay()
songPlayer?.play()
try AVAudioSession.sharedInstance().setActive(false)
catch (let error)
try? AVAudioSession.sharedInstance().setActive(false)
Crashlytics.crashlytics().setCustomValue(error.localizedDescription, forKey: "audio_playback_error")
【讨论】:
这不会立即停用音频会话而不播放声音吗?【参考方案13】:其他答案没有的重要一点是,您需要在停用时使用 .notifyOthers 标志调用 false:
try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)
这样做的原因是,当您停用您的应用程序时,其他在后台播放音乐的应用程序会知道何时重新打开其音频。否则,如果您关闭会话,您的背景音乐将不会重新打开。
【讨论】:
以上是关于如何让背景音乐继续播放而我的应用程序在使用 Swift 时仍然播放其声音的主要内容,如果未能解决你的问题,请参考以下文章
在 Swift 中,如何让其他应用在我的应用打开时继续播放音频?