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

iOS AppIntent调用AVPlayer播放流媒体结果不稳定问题排查

iOS Siri快捷指令音频播放不稳定问题解决方案

一、修正AppIntent触发逻辑

当前通过NotificationCenter转发播放指令的方式,在APP后台/杀死状态下可能因视图生命周期未就绪导致失效。直接在AudioPlaybackIntent的perform方法内处理播放逻辑,系统会给予更高的后台优先级:

@available(iOS 16, *)
struct PlayCurrentStationIntent: AudioPlaybackIntent {
    static let title: LocalizedStringResource = "Start playing"
    static let description = IntentDescription("Plays currently selected radio")
    
    func perform() async throws -> some IntentResult & ProvidesDialog {
        let player = Player.shared
        // 直接在Intent中激活音频会话并触发播放
        try await player.activatePlaybackSession()
        player.play()
        return .result(dialog: "Playing \(player.station.title)")
    }
}

二、优化音频会话与AVPlayer配置

针对AVPlayerWaitingToMinimizeStallsReason停滞和状态异常问题,调整缓冲策略并确保音频会话激活可靠:

class Player {
    static let shared = Player()
    private let audioSession = AVAudioSession.sharedInstance()
    private var player: AVPlayer?
    private var statusObservation: AnyCancellable?
    
    func activatePlaybackSession() async throws {
        try audioSession.setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay])
        try await audioSession.setActive(true, options: .notifyOthersOnDeactivation)
    }
    
    func play() {
        guard let url = URL(string: station.streamURL) else { return }
        let playerItem = AVPlayerItem(url: url)
        
        // 关闭自动等待停滞,手动设置预缓冲时长
        playerItem.preferredForwardBufferDuration = 10
        player = AVPlayer(playerItem: playerItem)
        player?.automaticallyWaitsToMinimizeStalling = false
        
        // 监听AVPlayerItem状态变化,处理异常
        statusObservation = playerItem.publisher(for: \.status)
            .sink { [weak self] status in
                guard let self = self else { return }
                switch status {
                case .failed:
                    print("播放失败: \(playerItem.error?.localizedDescription ?? "未知错误")")
                    self.player?.replaceCurrentItem(with: AVPlayerItem(url: url))
                case .unknown:
                    // 主动触发加载,避免停滞
                    self.player?.play()
                default: break
                }
            }
        
        player?.play()
    }
}

三、提升杀死状态下的唤醒可靠性

  1. Info.plist配置:确保正确声明AppIntent扩展,添加NSExtension字典,类型设为com.apple.intents-service,并在IntentsSupported数组中包含PlayCurrentStationIntent类名。
  2. 后台唤醒处理:在App初始化时监听激活事件,确保音频会话状态正确:
@main
struct MyApp: App {
    let player = Player.shared
    
    init() {
        NotificationCenter.default.addObserver(forName: UIApplication.didBecomeActiveNotification, object: nil, queue: .main) { _ in
            Task { try? player.activatePlaybackSession() }
        }
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(player)
        }
    }
}

四、额外排查点

  • 确认APP已开启Background Modes中的Audio, AirPlay, and Picture in Picture权限。
  • 测试流媒体URL是否支持字节范围请求(AVPlayer缓冲必需),排查服务器端是否存在间歇性响应问题。
  • 移除perform方法中的@MainActor修饰,避免主线程阻塞导致Intent处理超时。
  • 必须使用真实设备测试,模拟器的后台行为与真机存在差异。

内容的提问来源于stack exchange,提问作者Krystian Kozerawski

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 12:25:55