iOS开发:MPVolumeView无法稳定显示听筒与扬声器选项问题
问题解决方案
问题1:无法始终显示iPhone听筒与扬声器选项
调整音频会话配置
当前音频会话的选项组合不足以让系统稳定显示听筒和扬声器选项,修改配置以支持多路由输出切换:
audioSession = AVAudioSession.sharedInstance() do { // 结合.playAndRecord与多选项,确保支持蓝牙、默认扬声器输出,同时允许AirPlay try audioSession?.setCategory(.playAndRecord, options: [.allowBluetooth, .defaultToSpeaker, .allowAirPlay]) try audioSession?.setActive(true) } catch { print("Failed to set audio session category: \(error)") } NotificationCenter.default.addObserver(self, selector: #selector(routeChangeEventHandle), name: AVAudioSession.routeChangeNotification, object: nil)
优化MPVolumeView初始化逻辑
避免手动遍历子视图查找按钮,直接使用系统提供的routeButton属性,同时确保视图布局正确:
let volumeView = MPVolumeView(frame: CGRect(x: 0, y: 0, width: 40, height: 40)) volumeView.showsVolumeSlider = false volumeView.tintColor = .gray // 直接配置系统路由按钮 if let routeButton = volumeView.routeButton { let symbolConfiguration = UIImage.SymbolConfiguration(pointSize: 40, weight: .regular) let sfSymbol = UIImage(systemName: "airplayvideo.circle.fill", withConfiguration: symbolConfiguration) routeButton.setImage(sfSymbol, for: .normal) routeButton.frame = volumeView.bounds } self.vwMV.addSubview(volumeView)
路由变化时刷新视图
在路由切换通知回调中触发视图布局更新,确保选项实时同步:
@objc func routeChangeEventHandle(notification: Notification) { volumeView.setNeedsLayout() volumeView.layoutIfNeeded() }
问题2:切换到扬声器后对话框显示“iPhone”需改为中文
系统默认MPVolumeView的弹窗文字无法直接修改,建议通过自定义路由选择弹窗完全控制选项文字:
1. 获取可用音频路由并映射中文名称
func getAvailableAudioRoutes() -> [(name: String, route: AVAudioSessionPortDescription)] { guard let outputs = AVAudioSession.sharedInstance().currentRoute.outputs else { return [] } var routes = [(name: String, route: AVAudioSessionPortDescription)]() for output in outputs { switch output.portType { case .builtInReceiver: routes.append((name: "听筒", route: output)) case .builtInSpeaker: routes.append((name: "扬声器", route: output)) case .bluetoothA2DP, .bluetoothHFP: routes.append((name: output.portName, route: output)) case .airPlay: routes.append((name: "AirPlay", route: output)) default: routes.append((name: output.portName, route: output)) } } return routes }
2. 自定义按钮触发弹窗
隐藏原MPVolumeView的路由按钮,用自定义按钮替代:
// 创建自定义路由选择按钮 let customRouteButton = UIButton(frame: CGRect(x: 0, y: 0, width: 40, height: 40)) let symbolConfiguration = UIImage.SymbolConfiguration(pointSize: 40, weight: .regular) let sfSymbol = UIImage(systemName: "airplayvideo.circle.fill", withConfiguration: symbolConfiguration) customRouteButton.setImage(sfSymbol, for: .normal) customRouteButton.tintColor = .gray customRouteButton.addTarget(self, action: #selector(showCustomRoutePicker), for: .touchUpInside) self.vwMV.addSubview(customRouteButton) // 隐藏系统默认路由按钮 volumeView.routeButton?.isHidden = true
3. 弹窗显示中文选项并切换路由
@objc func showCustomRoutePicker() { let routes = getAvailableAudioRoutes() guard !routes.isEmpty else { return } let alert = UIAlertController(title: "选择音频输出", message: nil, preferredStyle: .actionSheet) for route in routes { alert.addAction(UIAlertAction(title: route.name, style: .default, handler: { [weak self] _ in self?.switchToAudioRoute(route.route) })) } alert.addAction(UIAlertAction(title: "取消", style: .cancel)) // iPad适配(按需添加) if let popover = alert.popoverPresentationController { popover.sourceView = customRouteButton popover.sourceRect = customRouteButton.bounds } present(alert, animated: true) } func switchToAudioRoute(_ route: AVAudioSessionPortDescription) { do { try AVAudioSession.sharedInstance().setPreferredOutputPort(route) } catch { print("Failed to switch audio route: \(error)") } }
内容的提问来源于stack exchange,提问作者aaa111
相关产品推荐
相关产品推荐

