SwiftUI中如何检测AirPlay状态并响应进出投屏模式事件
监听AirPlay连接状态的实现方案
核心是通过系统原生的AVAudioSession路由变更通知,实时获取当前音视频输出设备的类型,判断是否处于AirPlay投屏状态,结合SwiftUI的响应式状态机制就能自动切换UI显示。
第一步:创建状态观察者
写一个可被SwiftUI观测的状态类,在内部监听系统路由变化通知,实时更新AirPlay连接状态,代码如下:
import AVKit import SwiftUI class AirPlayStatusObserver: ObservableObject { @Published var isAirPlayActive: Bool = false init() { // 初始化时先同步一次当前状态 updateCurrentAirPlayStatus() // 注册路由变化监听 NotificationCenter.default.addObserver( self, selector: #selector(handleRouteChange), name: AVAudioSession.routeChangeNotification, object: nil ) } @objc private func handleRouteChange() { updateCurrentAirPlayStatus() } private func updateCurrentAirPlayStatus() { let currentOutputs = AVAudioSession.sharedInstance().currentRoute.outputs // 遍历当前输出端口,判断是否存在AirPlay类型设备 let isConnected = currentOutputs.contains { $0.portType == .airPlay } DispatchQueue.main.async { self.isAirPlayActive = isConnected } } deinit { NotificationCenter.default.removeObserver(self) } }
第二步:在视图中根据状态切换UI
在播放页初始化状态观察者,在原视频区域根据连接状态判断是显示视频层还是AirPlay连接提示,你之前写的AirPlayView组件不需要做任何修改,直接复用即可。
struct PlaybackView: View { @StateObject private var airPlayObserver = AirPlayStatusObserver() // 这里保留你原有的视频播放器、播放控制等相关属性 var body: some View { VStack { // 原有AirPlay按钮 AirPlayView() .frame(width: 44, height: 44) // 原视频显示区域 ZStack { if airPlayObserver.isAirPlayActive { // AirPlay连接时显示提示内容 VStack(spacing: 12) { Image(systemName: "airplayvideo") .font(.system(size: 48)) Text("已连接AirPlay设备") .font(.headline) Text("视频正在外接屏幕上播放") .font(.caption) .opacity(0.7) } .foregroundColor(.white) .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color.black) } else { // 未投屏时显示原视频播放组件 // 替换为你自己的VideoPlayer/自定义播放层 Color.black } } .aspectRatio(16/9, contentMode: .fit) .clipped() // 原有播放控制UI } } } // 原有AirPlay按钮组件无需修改 struct AirPlayView: UIViewRepresentable { func makeUIView(context: Context) -> UIView { let routePickerView = AVRoutePickerView() routePickerView.backgroundColor = UIColor.clear routePickerView.activeTintColor = UIColor.red routePickerView.tintColor = UIColor.white return routePickerView } func updateUIView(_ uiView: UIView, context: Context) {} }
注意事项
- 该方案对使用
AVPlayer的原生播放场景完全适配,系统触发AirPlay投屏时会自动把视频流输出到外接设备,本地播放器区域会自动渲染空白,直接覆盖提示层即可 - 所有状态变更都已做主线程派发,不会触发SwiftUI的UI线程警告
- 观察者初始化时会自动同步当前路由状态,不会出现首次进入页面状态显示错误的问题
- 观察者销毁时会自动移除通知监听,不会造成内存泄漏
内容的提问来源于stack exchange,提问作者soleil
相关产品推荐
相关产品推荐

