You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 17:36:18