gpt4 book ai didi

ios - 有权在 Swift 中读取视频文件但不能读取图像文件?

转载 作者:搜寻专家 更新时间:2023-11-01 06:13:15 26 4
gpt4 key购买 nike

我在 Swift 中编写了一个图像选择器(NOT UIImagePickerController),按下“完成”后,我返回所选 PHAssets(图像或视频或两者)的 URL,然后将它们上传到 Firebase 存储。

图像的 URL 如下所示:file:///var/mobile/Media/DCIM/101APPLE/IMG_1239.PNG

视频的 URL 如下所示:file:///var/mobile/Media/DCIM/101APPLE/IMG_1227.MOV

然后我显示 PHAsset。播放视频 Assets 没有问题:

let player = AVPlayer(url: url)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = view.frame
playerLayer.videoGravity = .resizeAspectFill
view.layer.addSublayer(playerLayer)
player.play()

但是当我尝试使用其 URL 显示图像时,出现“没有读取文件的权限”错误:

do {
let data = try Data(contentsOf: url)
imageView.image = UIImage(data: data)
} catch {
print(error)
}

我确实有权访问用户的照片库,这就是图像选择器工作正常的原因。我只是无法使用它们的 URL 读取图像文件。

我在想,也许我应该将图像 Assets 复制到一个临时文件并从那里读取它,但是为什么视频 Assets 可读但图像 Assets 不可读没有任何意义。

------------更新----------------

这就是我获取 PHAsset 的 url 的方式

extension PHAsset {
func getURL(completionHandler : @escaping ((_ responseURL : URL?) -> Void)) {
if self.mediaType == .image {
let options = PHContentEditingInputRequestOptions()
options.canHandleAdjustmentData = { (adjustmeta: PHAdjustmentData) -> Bool in
return true
}
self.requestContentEditingInput(with: options, completionHandler: { (contentEditingInput: PHContentEditingInput?, info: [AnyHashable : Any]) in
completionHandler(contentEditingInput!.fullSizeImageURL as URL?)
})
} else if self.mediaType == .video {
let options = PHVideoRequestOptions()
options.version = .original
PHImageManager.default().requestAVAsset(forVideo: self, options: options, resultHandler: {(asset: AVAsset?, audioMix: AVAudioMix?, info: [AnyHashable : Any]?) in
if let urlAsset = asset as? AVURLAsset {
let localVideoUrl: URL = urlAsset.url as URL
completionHandler(localVideoUrl)
} else {
completionHandler(nil)
}
})
}
}
}

最佳答案

iOS 中的应用程序以沙盒模式运行,这会阻止它访问其自身范围之外的文件。
一个网址,例如:

file:///var/mobile/Media/DCIM/101APPLE/...

不在您应用的范围内,因此无法通过 Data(contentsOf:) 直接访问。

但是,

AVPlayer 能够访问外部 url,因为它具有特殊的权利,这就是为什么您能够使用 url< 加载视频 Assets 的原因.

要从 url 加载图像,我们会在 PHAssets.fetchAssets(withALAssetURLs:options:) 中使用此 url 来获取返回 PHAsset 以加载它,但该方法已在 iOS 11 中弃用。

作为替代方案,PHAssets.fetchAssets(withLocalIdentifiers:options:) 可用,但要使用它,您需要为其提供 localIdentifier
为此,您应该保存 PHAssetlocalIdentifier,而不是保存 url


总结:

  1. 获取您的PHAsset
  2. 保存 asset.localIdentifier 而不是它们的 url
  3. 需要时,使用 [1] 取回 PHAsset :

    PHAssets.fetchAssets(withLocalIdentifiers:options:)
  4. 根据 mediaType 处理 PHAsset

    • 图片 [2] :

      PHImageManager().requestImageData(for:options:resultHandler:)
    • 视频 [3] :

      PHImageManager().requestAVAsset(forVideo:options:resultHandler:)

一般示例:

警告 fatalError() 已被用于在您的设置出现问题时故意终止应用程序。< br/>如果它崩溃然后检查你的 Info.plist NSPhotoLibraryUsageDescription 和/或通过 PHPhotoLibrary.requestAuthorization(_:)

  1. 获取最新资源(图片/视频;由您决定)的演示功能

    func getLatestAsset(for type: PHAssetMediaType) {
    let fetchOptions = PHFetchOptions()
    fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate",
    ascending: false)]
    fetchOptions.fetchLimit = 2

    let fetchResult: PHFetchResult = PHAsset.fetchAssets(with: type,
    options: fetchOptions)

    guard let asset = fetchResult.firstObject else { fatalError("Unable to fetch photos") }

    //save `localIdentifier` for later use (app relaunch or whatever)
    let assetIdentifier = asset.localIdentifier

    print(assetIdentifier)

    //Just a demo that you can get the same asset based on a local identifier
    loadAsset(identifier: assetIdentifier)
    }
  2. 根据 localIdentifier

    加载 Assets 的函数
    func loadAsset(identifier: String) {
    guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [identifier],
    options: nil).firstObject
    else {
    fatalError("No Asset found with identifier: \(identifier)")
    }

    print(asset.localIdentifier)

    //Do something with the asset now
    if asset.mediaType == .image {
    loadImage(asset: asset)
    }
    else if asset.mediaType == .video {
    loadVideo(asset: asset)
    }
    }
  3. PHAsset 加载图像

    func loadImage(asset: PHAsset) {
    PHImageManager().requestImageData(for: asset, options: nil) { (data, string, orientation, userInfo) in
    guard let data = data else { fatalError("Image Data is nil") }

    DispatchQueue.main.async {
    self.imageView.image = UIImage(data: data)
    }
    }
    }
  4. PHAsset 加载视频

    func loadVideo(asset: PHAsset) {
    PHImageManager().requestAVAsset(forVideo: asset, options: nil) { (avAsset, audioMix, userInfo) in
    guard let avAsset = avAsset else { fatalError("AVAsset is nil") }

    let playerItem = AVPlayerItem(asset: avAsset)
    let player = AVPlayer(playerItem: playerItem)
    let playerLayer = AVPlayerLayer(player: player)
    playerLayer.frame = self.view.frame
    playerLayer.videoGravity = .resizeAspectFill

    DispatchQueue.main.async {
    self.view.layer.addSublayer(playerLayer)
    player.play()
    }
    }
    }

PS:您将不再需要 getURL(completionHandler:),因为您的整个逻辑将基于 localIdentifier 而不是 url我会说那好多了。
Url 只是,有点变幻无常,所以我们至少要避免在这里使用它们。

关于ios - 有权在 Swift 中读取视频文件但不能读取图像文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50670260/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com