请求解决MPMoviePlayerController路由通知及蓝牙耳机路由事件失效问题
Hey there! I get it—trying to catch Bluetooth hands-free route changes with MPMoviePlayerController can be tricky when the basic AVAudioSessionRouteChange notification doesn't cut it. Let's break down the solution step by step:
1. First, Correctly Configure Your Audio Session
MPMoviePlayerController sometimes overrides audio session settings, so you need to explicitly set up the session to allow Bluetooth hands-free (HFP) devices before initializing the player:
func setupAudioSession() { let audioSession = AVAudioSession.sharedInstance() do { // Use .playback category for video audio, enable Bluetooth HFP support try audioSession.setCategory(.playback, mode: .moviePlayback, options: .allowBluetooth) try audioSession.setActive(true) } catch { print("Failed to configure audio session: \(error.localizedDescription)") } }
Call this method before you initialize your MPMoviePlayerController to ensure the session settings stick.
2. Upgrade Your Route Change Observer Logic
The default notification works, but you need to dig into the userInfo dictionary to specifically detect Bluetooth HFP events. Replace your existing observer setup with the modern notification name (for iOS 10+ compatibility) and update the handler:
Observer Setup
// Add this in your viewDidLoad or initialization code NotificationCenter.default.addObserver(self, selector: #selector(handleRouteChange), name: .audioSessionRouteChange, object: AVAudioSession.sharedInstance())
Route Change Handler
@objc func handleRouteChange(_ notification: Notification) { guard let userInfo = notification.userInfo else { return } // Extract the route change reason guard let reasonRawValue = userInfo[AVAudioSessionRouteChangeReasonKey] as? UInt, let reason = AVAudioSession.RouteChangeReason(rawValue: reasonRawValue) else { return } switch reason { case .newDeviceAvailable: // Check if the new device is a Bluetooth hands-free let currentRoute = AVAudioSession.sharedInstance().currentRoute for output in currentRoute.outputs { if output.portType == .bluetoothHFP { print("Bluetooth hands-free connected!") // Add your custom logic here (e.g., update UI, adjust playback) } } case .oldDeviceUnavailable: // Check if the disconnected device was a Bluetooth hands-free if let previousRoute = userInfo[AVAudioSessionRouteChangePreviousRouteKey] as? AVAudioSessionRouteDescription { for output in previousRoute.outputs { if output.portType == .bluetoothHFP { print("Bluetooth hands-free disconnected!") // Handle post-disconnection logic here } } } default: // Handle other route change reasons if needed break } }
3. Clean Up the Observer
Don't forget to remove the observer when your view controller or object is deallocated to avoid memory leaks:
deinit { NotificationCenter.default.removeObserver(self, name: .audioSessionRouteChange, object: AVAudioSession.sharedInstance()) }
Why This Works
The key issue was likely two-fold:
- Your audio session wasn't configured to explicitly allow Bluetooth HFP devices.
- You weren't checking the specific port type in the route change notification payload—generic route change events don't automatically distinguish between Bluetooth headphones and hands-free devices.
By targeting the .bluetoothHFP port type in the route description, you'll catch exactly the hands-free events you need, even when using MPMoviePlayerController.
内容的提问来源于stack exchange,提问作者MobileGeek

