Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get an ALAsset URL from a PHAsset?

You can do it sneakily† using the undocumented PHAsset.ALAssetURL property, but I'm looking for something documented.


† In Objective-C, this will help

@interface PHAsset (Sneaky)

@property (nonatomic, readonly) NSURL *ALAssetURL;

@end
like image 214
Clay Bridges Avatar asked Mar 05 '15 21:03

Clay Bridges


4 Answers

Create the assetURL by leveraging the localidentifier of the PHAsset. Example: PHAsset.localidentifier returns 91B1C271-C617-49CE-A074-E391BA7F843F/L0/001

Now take the 32 first characters to build the assetURL, like:

assets-library://asset/asset.JPG?id=91B1C271-C617-49CE-A074-E391BA7F843F&ext=JPG

You might change the extension JPG depending on the UTI of the asset (requestImageDataForAsset returns the UTI), but in my testing the extensions of the assetURL seems to be ignored anyhow.

like image 70
holtmann Avatar answered Oct 13 '22 14:10

holtmann


I wanted to be able to get a URL for an asset too. However, I have realised that the localIdentifier can be persisted instead and used to recover the PHAsset.

PHAsset* asset = [PHAsset fetchAssetsWithLocalIdentifiers:@[localIdentifier] options:nil].firstObject;

Legacy asset URLs can be converted using:

PHAsset* legacyAsset = [PHAsset fetchAssetsWithALAssetUrls:@[assetUrl] options:nil].firstObject;
NSString* convertedIdentifier = legacyAsset.localIdentifier;

(before that method gets obsoleted...)

(Thanks holtmann - localIdentifier is hidden away in PHObject.)

like image 32
Matt Avatar answered Oct 13 '22 14:10

Matt


Here is working code tested on iOS 11 both simulator and device

PHFetchResult *result = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:nil];
    [result enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        PHAsset *asset = (PHAsset *)obj;
        [asset requestContentEditingInputWithOptions:nil completionHandler:^(PHContentEditingInput * _Nullable contentEditingInput, NSDictionary * _Nonnull info) {
            NSLog(@"URL:%@",  contentEditingInput.fullSizeImageURL.absoluteString);
            NSString* path = [contentEditingInput.fullSizeImageURL.absoluteString substringFromIndex:7];//screw all the crap of file://
            NSFileManager *fileManager = [NSFileManager defaultManager];
            BOOL isExist = [fileManager fileExistsAtPath:path];
            if (isExist)
                NSLog(@"oh yeah");
            else {
                NSLog(@"damn");
            }
        }];
    }];
like image 2
Lance Mao Avatar answered Oct 13 '22 13:10

Lance Mao


Read the bottom!

The resultHandler for PHImageManager.requestImage returns 2 objects: result and info.

You can get the original filename for the PHAsset (like IMG_1043.JPG) as well as its full path on the filesystem with:

let url = info?["PHImageFileURLKey"] as! URL

This should work right, but for some reason it doesn't. So basically, you have to copy your image to a file then access that then delete it.

The PHImageFileURLKey is usable to get the original file name, but you cannot actually access that file. It probably has to do with the fact that code in the background can access the file while other apps can delete it.

like image 2
Andrew Hodel Avatar answered Oct 13 '22 13:10

Andrew Hodel