PhotoKit获取iCloud离线资产高清预览问题求助
解决方案
问题出在当isNetworkAccessAllowed设为false时,PhotoKit默认只会返回本地缓存的最小尺寸缩略图(120px左右),而系统相册App有特殊权限可以访问更高清的本地占位预览图。要在自研App中获取同样的高清占位图,需要通过PHAssetResourceManager直接获取资产的本地预览资源,而非依赖PHImageManager的默认请求。
具体步骤
- 先获取目标资产对应的
PHAssetResource,筛选出本地可用的预览资源; - 使用
PHAssetResourceManager读取该资源的数据,转换为UIImage并按需缩放。
修改后的代码示例
extension UIImageView { func fetchImageAsset(_ asset: PHAsset?, targetSize size: CGSize, contentMode: PHImageContentMode = .aspectFill, completionHandler: ((Bool) -> Void)?) { guard let asset = asset else { completionHandler?(false) return } // 1. 获取本地预览资源 let resources = PHAssetResource.assetResources(for: asset) guard let previewResource = resources.first(where: { $0.type == .photoPreview || ($0.type == .fullSizePhoto && $0.isLocallyAvailable) }) else { // 无本地预览资源,降级到原逻辑 let options = PHImageRequestOptions() options.deliveryMode = .opportunistic options.resizeMode = .none options.isNetworkAccessAllowed = false PHImageManager.default().requestImage(for: asset, targetSize: size, contentMode: contentMode, options: options) { [weak self] image, info in self?.image = image completionHandler?(true) } return } // 2. 读取预览资源数据 let manager = PHAssetResourceManager.default() _ = manager.requestData(for: previewResource, options: nil) { [weak self] data, error in guard let data = data, error == nil, let image = UIImage(data: data) else { completionHandler?(false) return } // 按目标尺寸和内容模式调整图片 let scaledImage = self?.scaleImage(image, to: size, contentMode: contentMode) self?.image = scaledImage ?? image completionHandler?(true) } } // 辅助方法:按目标尺寸和内容模式缩放图片 private func scaleImage(_ image: UIImage, to targetSize: CGSize, contentMode: PHImageContentMode) -> UIImage? { let aspectRatio = image.size.width / image.size.height let targetRatio = targetSize.width / targetSize.height var drawSize: CGSize switch contentMode { case .aspectFill: drawSize = aspectRatio > targetRatio ? CGSize(width: image.size.width, height: image.size.width / targetRatio) : CGSize(width: image.size.height * targetRatio, height: image.size.height) case .aspectFit: drawSize = aspectRatio > targetRatio ? CGSize(width: targetSize.width, height: targetSize.width / aspectRatio) : CGSize(width: targetSize.height * aspectRatio, height: targetSize.height) @unknown default: drawSize = targetSize } UIGraphicsBeginImageContextWithOptions(drawSize, false, UIScreen.main.scale) image.draw(in: CGRect(origin: .zero, size: drawSize)) let scaledImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return scaledImage } }
补充说明
PHAssetResource的photoPreview类型对应系统相册显示的高清占位图,尺寸远大于120px;- 如果
photoPreview不可用,可降级到本地已缓存的fullSizePhoto资源; - 若必须禁用网络访问,此方法是目前唯一能获取更高清本地占位图的合规方式;
- 禁止使用
privateFileURL等私有API,会导致App审核被拒。
内容的提问来源于stack exchange,提问作者Falco Winkler
相关产品推荐
相关产品推荐

