如何正确处理 AVPlayer HTTP 错误?

How to correctly handle AVPlayer HTTP error?

当请求从网络服务器播放 mp3 文件时,如果该服务器 returns 403 禁止,则不清楚在检查 AVPlayer 当前项目错误时如何处理错误。

来自 AVPlayer 的错误消息并未表明它是 403...

2019-01-05 13:08:33.908316-0500 Runner[84043:3269818] Optional(Error Domain=AVFoundationErrorDomain Code=-11828 "Cannot Open" UserInfo={NSLocalizedFailureReason=This media format is not supported., NSLocalizedDescription=Cannot Open, NSUnderlyingError=0x600000781290 {Error Domain=NSOSStatusErrorDomain Code=-12847 "(null)"}})

错误提示媒体不受支持,但从未访问过媒体。有没有办法看到来自 AVPlayer 请求的 HTTP 错误代码?

在 Android 上测试同一个文件时,我能够正确地看到来自 Android 本机 MediaPlayer 的 403 错误代码(来自 Android 的错误更好比 iOS 的 AVPlayer 更有用)。

由于缺乏正确的错误消息,很难优雅地向用户显示准确的错误。

任意代码示例:

    let url = URL(string: "some 403 server url")
    let playerItem:AVPlayerItem = AVPlayerItem(url: url!)
    player = AVPlayer(playerItem: playerItem)
    player.play()

检查错误将打印上面引用的消息。

NSLog("\(String(describing: player.currentItem?.error))")

这是一个可能的解决方案,而不是用 url

初始化 AVPlayerItem

你可以试试这个方法

  1. 使用AVURLAsset并设置AVAssetResourceLoaderDelegate

  2. 使用委托方法 func resourceLoader(_ resourceLoader:AVAssetResourceLoader, didCancel authenticationChallenge: URLAuthenticationChallenge)

  3. 继续创建播放器并播放音频,委托方法会在出现403错误时通知您。

这是示例代码

class ResourceLoadingDelegate:NSObject, AVAssetResourceLoaderDelegate {
      func resourceLoader(_ resourceLoader: AVAssetResourceLoader,
                    didCancel authenticationChallenge:  URLAuthenticationChallenge) {
    /// handle the authentication challenge
    print(authenticationChallenge.error.debugDescription)
   }
}

   let asset = AVURLAsset(url: URL(string: "some 403 url")!)

   asset.resourceLoader.setDelegate(ResourceLoadingDelegate(), queue:  DispatchQueue.global(qos: .userInitiated))

使用KVO观察playItem的状态是这样的:

self.playItem.addObserver(self, forKeyPath: "status", options: .new, context: nil)

然后在方法中:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        let playerItem = object as! AVPlayerItem
        if keyPath == "status", playerItem.status == .failed{
            if let error = playerItem.error as NSError? {
                let errorCode = error.code
            }
        }
}

您可以在此处找到代码定义: documentation