Search code examples
iosobjective-cswiftprogressphasset

How to use PHAssetResourceRequestOptions progressHandler/PHAssetResourceProgressHandler


I'm trying to retrieve/download the video/frames of Live Photo. As for the API documents there is a possible scenario which the Live Photos will be store at iCloud. In order to retrieve them as well you need to declare

let options = PHAssetResourceRequestOptions()
        options.networkAccessAllowed = true  

I'm trying to create a progress bar while the Live Photo is being download. According to the API, you need to declare this properties:

public var progressHandler: PHAssetResourceProgressHandler?

progress    
A floating-point value indicating the progress of the download. 
A value of 0.0 indicates that the download has just started,
and a value of 1.0 indicates the download is complete. 

I haven't found the correct way to retrieve those yet. Any suggestion?

Full Code :

 let assestResource = PHAssetResource.assetResourcesForAsset(asset)
 let options = PHAssetResourceRequestOptions()
 options.networkAccessAllowed = true
for assetRes in assestResource {
            print(assetRes.type.rawValue)
            if (assetRes.type == .PairedVideo) {
                print("imageTaken")
                manager.writeDataForAssetResource(assetRes, toFile: documentsURL,    options: options, completionHandler: { (error) -> Void in
                    if error == nil
                    {

                    }
                    else
                    {
                        print(error)
                    }
                })

Solution

  • Yes, unfortunately, there is an Apple bug with iCloud downloads + PHAssetResourceManager. I get the following error regardless of the asset type:

    Error: Missing resource download context

    Instead, use PHImageManager. You need to have a unique request for each type of PHAsset:

    - (void)downloadAsset:(PHAsset *)asset toURL:(NSURL *)url completion:(void (^)(void))completion
    {
        if (asset.mediaType == PHAssetMediaTypeImage && (asset.mediaSubtypes & PHAssetMediaSubtypePhotoLive))
        {
            PHLivePhotoRequestOptions *options = [PHLivePhotoRequestOptions new];
            options.networkAccessAllowed = YES;
            [[PHImageManager defaultManager] requestLivePhotoForAsset:asset targetSize:CGSizeZero contentMode:PHImageContentModeAspectFill options:options resultHandler:^(PHLivePhoto * _Nullable livePhoto, NSDictionary * _Nullable info) {
                if ([info objectForKey:PHImageErrorKey] == nil)
                {
                    NSData *livePhotoData = [NSKeyedArchiver archivedDataWithRootObject:livePhoto];
                    if ([[NSFileManager defaultManager] createFileAtPath:url.path contents:livePhotoData attributes:nil])
                    {
                        NSLog(@"downloaded live photo:%@", url.path);
                        completion();
                    }
                }
            }];
        }
        else if (asset.mediaType == PHAssetMediaTypeImage)
        {
            PHImageRequestOptions *options = [PHImageRequestOptions new];
            options.networkAccessAllowed = YES;
            [[PHImageManager defaultManager] requestImageDataForAsset:asset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
                if ([info objectForKey:PHImageErrorKey] == nil
                    && [[NSFileManager defaultManager] createFileAtPath:url.path contents:imageData attributes:nil])
                {
                    NSLog(@"downloaded photo:%@", url.path);
                    completion();
                }
            }];
        }
        else if (asset.mediaType == PHAssetMediaTypeVideo)
        {
            PHVideoRequestOptions *options = [PHVideoRequestOptions new];
            options.networkAccessAllowed = YES;
            [[PHImageManager defaultManager] requestExportSessionForVideo:asset options:options exportPreset:AVAssetExportPresetHighestQuality resultHandler:^(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info) {
                if ([info objectForKey:PHImageErrorKey] == nil)
                {
                    exportSession.outputURL = url;
    
                    NSArray<PHAssetResource *> *resources = [PHAssetResource assetResourcesForAsset:asset];
                    for (PHAssetResource *resource in resources)
                    {
                        exportSession.outputFileType = resource.uniformTypeIdentifier;
                        if (exportSession.outputFileType != nil)
                            break;
                    }
    
                    [exportSession exportAsynchronouslyWithCompletionHandler:^{
                        if (exportSession.status == AVAssetExportSessionStatusCompleted)
                        {
                            NSLog(@"downloaded video:%@", url.path);
                            completion();
                        }
                    }];
                }
            }];
        }
    }