Xcode9 Swift4下播放服务返回的无扩展名视频URL解决方案咨询
解决无扩展名视频URL无法在AVPlayer中播放的问题
我之前也碰到过一模一样的情况——AVPlayer默认会依赖URL的扩展名来识别媒体类型,没有扩展名的话,系统就没法判断该怎么解码视频,自然播放不了。针对你在Xcode9+Swift4环境下的场景,我整理了几个可行的解决方案:
方法一:已知视频格式时,手动指定媒体类型
如果已经明确视频的实际格式(比如是MP4、MOV或者HLS流),可以直接在创建AVURLAsset时,通过选项告诉系统媒体类型,这样AVPlayer就能正确加载了。
修改后的代码示例:
import AVKit import AVFoundation class ViewController: UIViewController { @IBOutlet weak var player_View: UIView! // 这里做了安全处理,避免URL为nil导致崩溃 let videoURL = URL(string: "http://45.58.42.105:82/Handlers/ImageHandler.ashx?fileReference=67f0dce7-a5f5-4894-a8fd-5996f135626c")! var playerVC: AVPlayerViewController! var player: AVPlayer! override func viewDidLoad() { super.viewDidLoad() // 假设你的视频是MP4格式,对应MIME类型为"video/mp4" // 如果是HLS流,改成"application/x-mpegURL"即可 let assetOptions: [String: Any] = [ AVURLAssetMediaTypeKey: AVMediaType.video.rawValue, // 确保能获取精确的视频时长和时序信息 AVURLAssetPreferPreciseDurationAndTimingKey: true ] let asset = AVURLAsset(url: videoURL, options: assetOptions) let playerItem = AVPlayerItem(asset: asset) player = AVPlayer(playerItem: playerItem) playerVC = AVPlayerViewController() playerVC.player = player // 将播放器视图嵌入到你的player_View中 addChild(playerVC) playerVC.view.frame = player_View.bounds player_View.addSubview(playerVC.view) playerVC.didMove(toParent: self) // 开始播放 player.play() } }
方法二:通用方案——用ResourceLoader拦截请求补充MIME类型
如果不确定视频格式,或者想兼容多种格式,最好的方式是用AVAssetResourceLoaderDelegate拦截AVPlayer的加载请求,自己去获取视频数据,并在返回时补充正确的MIME类型(可以从服务器响应头里取,或者默认设置常用类型)。
首先创建一个自定义的资源加载器类:
import AVFoundation class VideoResourceLoader: NSObject, AVAssetResourceLoaderDelegate { private let session: URLSession override init() { session = URLSession(configuration: .default) super.init() } func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool { guard let targetURL = loadingRequest.request.url else { loadingRequest.finishLoading(with: NSError(domain: "VideoLoaderError", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效的视频URL"])) return false } // 用URLSession自己请求视频数据 let task = session.dataTask(with: targetURL) { [weak self] data, response, error in guard let self = self else { return } if let error = error { loadingRequest.finishLoading(with: error) return } guard let httpResponse = response as? HTTPURLResponse, let videoData = data else { loadingRequest.finishLoading(with: NSError(domain: "VideoLoaderError", code: -2, userInfo: [NSLocalizedDescriptionKey: "未获取到视频数据或响应"])) return } // 优先从服务器响应头取Content-Type,如果没有则默认设为MP4 var contentType = httpResponse.allHeaderFields["Content-Type"] as? String ?? "video/mp4" if contentType.isEmpty { contentType = "video/mp4" } // 给AVPlayer提供必要的内容信息 loadingRequest.contentInformationRequest?.contentType = contentType loadingRequest.contentInformationRequest?.contentLength = Int64(videoData.count) loadingRequest.contentInformationRequest?.isByteRangeAccessSupported = true // 返回视频数据并完成加载 loadingRequest.dataRequest?.respond(with: videoData) loadingRequest.finishLoading() } task.resume() return true } }
然后在ViewController中使用这个加载器:
import AVKit import AVFoundation class ViewController: UIViewController { @IBOutlet weak var player_View: UIView! let videoURL = URL(string: "http://45.58.42.105:82/Handlers/ImageHandler.ashx?fileReference=67f0dce7-a5f5-4894-a8fd-5996f135626c")! var playerVC: AVPlayerViewController! var player: AVPlayer! var resourceLoader: VideoResourceLoader! override func viewDidLoad() { super.viewDidLoad() resourceLoader = VideoResourceLoader() // 创建一个自定义URL scheme,让AVAsset把加载请求交给我们的loader处理 let customAssetURL = URL(string: "custom-video://play")! let asset = AVURLAsset(url: customAssetURL) asset.resourceLoader.setDelegate(resourceLoader, queue: DispatchQueue.main) let playerItem = AVPlayerItem(asset: asset) player = AVPlayer(playerItem: playerItem) playerVC = AVPlayerViewController() playerVC.player = player // 嵌入播放器视图 addChild(playerVC) playerVC.view.frame = player_View.bounds player_View.addSubview(playerVC.view) playerVC.didMove(toParent: self) player.play() } }
额外建议:让后端补充响应头
如果有条件的话,最好和后端开发同学沟通,让他们在返回视频时,在HTTP响应头中正确设置Content-Type字段(比如MP4设为video/mp4)。这样即使URL没有扩展名,AVPlayer也能自动识别媒体类型,不需要前端做额外处理,这是最省心的方案。
内容的提问来源于stack exchange,提问作者Demi Ali
相关产品推荐
相关产品推荐

