为何不同蓝牙音箱在iOS的AVAudioSession中表现存在差异?
Hey there! Let's dig into those edge cases for your iOS audio app—they're easy to miss but make all the difference for a polished user experience. Since you already have the basic AVAudioSession setup in your AppDelegate, let's break down the key scenarios you should test and tweak:
Incoming calls, system alerts, or other apps grabbing audio focus will interrupt your playback. You need to listen for these events and respond appropriately:
- Add a notification observer in your AppDelegate's
didFinishLaunchingWithOptionsto catch interruptions:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Your base AVAudioSession setup (adjust category/options to match your app's needs) do { let session = AVAudioSession.sharedInstance() try session.setCategory(.playback, mode: .default, options: .mixWithOthers) try session.setActive(true) } catch { print("Audio session setup failed: \(error.localizedDescription)") } // Listen for interruptions NotificationCenter.default.addObserver(self, selector: #selector(handleAudioInterruption(_:)), name: AVAudioSession.interruptionNotification, object: nil) return true } @objc private func handleAudioInterruption(_ notification: Notification) { guard let info = notification.userInfo, let typeValue = info[AVAudioSessionInterruptionTypeKey] as? UInt, let type = AVAudioSession.InterruptionType(rawValue: typeValue) else { return } switch type { case .began: // Pause playback immediately when interruption starts yourAudioPlayer?.pause() case .ended: guard let optionValue = info[AVAudioSessionInterruptionOptionKey] as? UInt else { return } let options = AVAudioSession.InterruptionOptions(rawValue: optionValue) // Only resume if the system signals it's safe (e.g., user dismissed the call) if options.contains(.shouldResume) { yourAudioPlayer?.play() } @unknown default: break } }
- Pro tip: If your app supports background playback, don't forget to add the
audiovalue toUIBackgroundModesin yourInfo.plist.
When users plug in headphones, switch to a Bluetooth speaker, or disconnect audio devices, your app should adapt:
- Add a route change notification observer and handle common scenarios:
// Add this in didFinishLaunchingWithOptions NotificationCenter.default.addObserver(self, selector: #selector(handleRouteChange(_:)), name: AVAudioSession.routeChangeNotification, object: nil) @objc private func handleRouteChange(_ notification: Notification) { guard let info = notification.userInfo, let reasonValue = info[AVAudioSessionRouteChangeReasonKey] as? UInt, let reason = AVAudioSession.RouteChangeReason(rawValue: reasonValue) else { return } switch reason { case .oldDeviceUnavailable: // Pause playback when headphones are unplugged to avoid accidental loudspeaker output yourAudioPlayer?.pause() case .newDeviceAvailable: // Optional: Resume playback automatically when a new audio device is connected // yourAudioPlayer?.play() default: break } }
- Note: iOS 14+ has a "Headphone Safety" feature that may auto-pause on unplug, but handling it manually ensures consistency across all iOS versions.
Different app types need different audio behaviors—make sure your session category aligns with your use case:
- Background music apps: Use
AVAudioSession.Category.playbackwith the.mixWithOthersoption to let your audio play alongside other apps (like a user listening to your app while scrolling TikTok). - Podcast/audio book apps: Use
.playbackwithout.mixWithOthersto interrupt other audio, but ensure your app resumes correctly after the interrupting app finishes. - Voice recording + playback apps: Use
.playAndRecordand configure options like.defaultToSpeakerif needed.
Some apps (like navigation apps) will force audio focus temporarily—your interruption handler should pause playback and resume once the focus is returned.
For a premium experience, make sure your app works smoothly when the device is locked or in the background:
- Update now-playing info: Use
MPNowPlayingInfoCenterto show track details and playback controls on the lock screen/Control Center:
import MediaPlayer func updateNowPlayingInfo() { var nowPlayingInfo = [String: Any]() nowPlayingInfo[MPMediaItemPropertyTitle] = "Your Track Title" nowPlayingInfo[MPMediaItemPropertyArtist] = "Artist Name" nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = yourAudioPlayer?.currentTime nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = yourAudioPlayer?.duration nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = yourAudioPlayer?.isPlaying ? 1.0 : 0.0 MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo }
- Handle remote controls: Let users control playback via headphone buttons or lock screen taps:
// Add this in didFinishLaunchingWithOptions UIApplication.shared.beginReceivingRemoteControlEvents() // Override in AppDelegate override func remoteControlReceived(with event: UIEvent?) { guard let event = event, event.type == .remoteControl else { return } switch event.subtype { case .remoteControlPlay: yourAudioPlayer?.play() case .remoteControlPause: yourAudioPlayer?.pause() case .remoteControlNextTrack: // Handle next track logic case .remoteControlPreviousTrack: // Handle previous track logic default: break } updateNowPlayingInfo() }
Don't ignore errors when activating/deactivating your session—other apps may hold exclusive audio focus:
// When activating do { try AVAudioSession.sharedInstance().setActive(true) } catch { print("Failed to activate audio session: \(error.localizedDescription)") // Optional: Show an alert to the user asking them to close other audio apps } // When your app is terminating, clean up the session func applicationWillTerminate(_ application: UIApplication) { do { try AVAudioSession.sharedInstance().setActive(false) } catch { print("Failed to deactivate audio session: \(error.localizedDescription)") } }
Be sure to test all these scenarios thoroughly: plug/unplug headphones, simulate incoming calls, switch between apps, lock the screen, and test with other audio apps running. Small tweaks here will make your app feel robust and user-friendly.
内容的提问来源于stack exchange,提问作者Nerdy Bunz




