从Assets.xcassets加载视频

时间:2018-02-13 13:13:44

标签: ios swift video avplayer

TL; DR:如果我将视频存储在Assets.xcassets中,我该如何播放视频?

我想在应用中存储大约50个视频。然后我将使用按需资源获取来使我的应用程序大小更轻。但我只能通过将视频保存在Assets.xcassets中来实现这一目标。而且我找不到从那里加载视频的方法,因为AVPlayer似乎只接受网址,而我真的不确定如何才能获得像这样的本地存储资产。

更新

所以我做了进一步的挖掘,发现它实际上无法将视频存储在资产目录中,仍然可以使用它们。我最终不得不将它们从资产目录中移出。至于随需应变资源提取,目录之外的资源仍然可能。您可以找到类似的方法here

3 个答案:

答案 0 :(得分:1)

尝试使用Apple Developer Documentation中所述的 AVAsset

AVPlayerItem可以加载AVAsset并播放它。有关加载AVAssets的文档的片段:

func prepareToPlay() {
    let url: URL = // Local or Remote Asset URL
    let asset = AVAsset(url: url)

    let assetKeys = [
        "playable",
        "hasProtectedContent"
    ]
    // Create a new AVPlayerItem with the asset and an
    // array of asset keys to be automatically loaded
    playerItem = AVPlayerItem(asset: asset,
                              automaticallyLoadedAssetKeys: assetKeys)

    // Register as an observer of the player item's status property
    playerItem.addObserver(self,
                           forKeyPath: #keyPath(AVPlayerItem.status),
                           options: [.old, .new],
                           context: &playerItemContext)

    // Associate the player item with the player
    player = AVPlayer(playerItem: playerItem)
}

获取资产的网址可能看起来像这样:

let urlpath     = Bundle.main.path(forResource: "myvideo", ofType: "mp4")
let url         = NSURL.fileURL(withPath: urlpath!)

答案 1 :(得分:0)

您可以在资产目录中存储所需的任何数据。但是,您只能将其加载为NSDataAsset,这会给您NSData。结果,您做了一些URL资源处理程序,以获取直接从NSData读取的URL。

它是这样的。

let videoUrl = URL(string: "my-custom-scheme-not-important://\(assetName)")!
let asset = AVURLAsset(url: videoUrl)
guard let dataAsset = NSDataAsset(name: assetName) else {
    fatalError("Data asset not found with name \(assetName)")
}
let resourceDelegate = DataAssetAVResourceLoader(dataAsset: dataAsset)
assetLoaderDelegate = resourceDelegate
asset.resourceLoader.setDelegate(resourceDelegate, queue: .global(qos: .userInteractive))

let item = AVPlayerItem(asset: asset)

...

@objc
fileprivate class DataAssetAVResourceLoader: NSObject, AVAssetResourceLoaderDelegate {
    let dataAsset: NSDataAsset
    let data: Data
    
    init(dataAsset: NSDataAsset) {
        self.dataAsset = dataAsset
        data = dataAsset.data
    }
    
    @objc
    public func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {
        if let infoRequest = loadingRequest.contentInformationRequest {
            infoRequest.contentType = kUTTypeQuickTimeMovie as String
            infoRequest.contentLength = Int64(data.count)
            infoRequest.isByteRangeAccessSupported = true
        }
        if let dataRequest = loadingRequest.dataRequest {
            let range = Range(NSRange(location: Int(dataRequest.requestedOffset), length: dataRequest.requestedLength))!
            dataRequest.respond(with: data.subdata(in:range))
            loadingRequest.finishLoading()
            return true
        }
        
        return false
    }
}

答案 2 :(得分:0)

现在可以将视频加载到Assets.xcassets中,并且仍然可以播放它们。 在Xcode 12.0.1 Swift 5上测试

import UIKit
import AVKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    func createLocalUrl(for filename: String, ofType: String) -> URL? {
        let fileManager = FileManager.default
        let cacheDirectory = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)[0]
        let url = cacheDirectory.appendingPathComponent("\(filename).\(ofType)")
        
        guard fileManager.fileExists(atPath: url.path) else {
            guard let video = NSDataAsset(name: filename)  else { return nil }
            fileManager.createFile(atPath: url.path, contents: video.data, attributes: nil)
            return url
        }
        
        return url
    }
    
    @IBAction func playLocalVideo(_ sender: Any) {
        guard let videoURL = createLocalUrl(for: "video", ofType: "mp4") else {
            return
        }
        
        // Create an AVPlayer, passing it the local video url path
        let player = AVPlayer(url: videoURL as URL)
        let controller = AVPlayerViewController()
        controller.player = player
        present(controller, animated: true) {
            player.play()
        }
    }
}

Assets.xcassets image

相信如何创建本地网址:https://stackoverflow.com/a/39748919/4267092