You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 18:18:50