I am using the UIImagePickerController in two cases
In the first
If we use the ALAssetsLibrary, it is very simple to save a picture in the Photo Album and get its URL:
// Get the image
UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];
// Add the image in the Photo Library
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum: [image CGImage]
orientation: (ALAssetOrientation)[image imageOrientation]
completionBlock: ^(NSURL *assetURL, NSError *error)
{
if (error)
{
NSLog( @"error: %@", error );
}
else
{
NSLog( @"assetURL = %@", assetURL );
}
}];
But surprisingly it seems not possible to do the same thing with the new PHPhotoLibrary!
A solution to have the same result with PHPhotoLibrary is always welcome.
I didn't find the way to get URL, but maybe localIdentifier can help you do the same work.
use
NSString* localId = [[assetChangeRequest placeholderForCreatedAsset] localIdentifier];
to get the local ID and get the image later.
__block NSString* localId;
// Add it to the photo library
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
if (self.assetCollection) {
PHAssetCollectionChangeRequest *assetCollectionChangeRequest = [PHAssetCollectionChangeRequest changeRequestForAssetCollection:self.assetCollection];
[assetCollectionChangeRequest addAssets:@[[assetChangeRequest placeholderForCreatedAsset]]];
}
localId = [[assetChangeRequest placeholderForCreatedAsset] localIdentifier];
} completionHandler:^(BOOL success, NSError *error) {
PHFetchResult* assetResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[localId] options:nil];
if (!success) {
NSLog(@"Error creating asset: %@", error);
} else {
PHFetchResult* assetResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[localId] options:nil];
PHAsset *asset = [assetResult firstObject];
[[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
UIImage* newImage = [UIImage imageWithData:imageData];
self.imageView.image = newImage;
}];
}
}];
I don't like this fix, as this could result in a race condition. So far I can't think of a better solution. If someone does I'd love to hear it :) Either way, here is a Swift-version of Rigel Chen's answer
import Photos
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
var localId:String?
let imageManager = PHPhotoLibrary.sharedPhotoLibrary()
imageManager.performChanges({ () -> Void in
let request = PHAssetChangeRequest.creationRequestForAssetFromImage(image)
localId = request.placeholderForCreatedAsset?.localIdentifier
}, completionHandler: { (success, error) -> Void in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if let localId = localId {
let result = PHAsset.fetchAssetsWithLocalIdentifiers([localId], options: nil)
let assets = result.objectsAtIndexes(NSIndexSet(indexesInRange: NSRange(location: 0, length: result.count))) as? [PHAsset] ?? []
if let asset = assets.first {
// Do something with result
}
}
})
})
}
}
Swift 4 solution that works for me to get the url of last image in Photo Library:
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
let fetchResult = PHAsset.fetchAssets(with: .image, options: fetchOptions).lastObject
PHImageManager().requestAVAsset(forVideo: fetchResult!, options: nil, resultHandler { (avurlAsset, _, _) in
if let newObj = avurlAsset as? AVURLAsset {
print(newObj.url)
}
})
Hope it helps!
Retrieve image URL:
- (void)processImage:(UIImage*)image type:(NSString*)mimeType forCallbackId:(NSString*)callbackId
{
__block NSString* localId;
// Add it to the photo library
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *assetChangeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
localId = [[assetChangeRequest placeholderForCreatedAsset] localIdentifier];
} completionHandler:^(BOOL success, NSError *err) {
if (!success) {
NSLog(@"Error saving image: %@", [err localizedDescription]);
} else {
PHFetchResult* assetResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[localId] options:nil];
PHAsset *asset = [assetResult firstObject];
[[PHImageManager defaultManager] requestImageDataForAsset:asset
options:nil
resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
NSURL *fileUrl = [info objectForKey:@"PHImageFileURLKey"];
if (fileUrl) {
NSLog(@"Image path: %@", [fileUrl relativePath]);
} else {
NSLog(@"Error retrieving image filePath, heres whats available: %@", info);
}
}];
}
}];
}
[Swift 4] This method can handle both image and video, enjoy :)
func getURL(of asset: PHAsset, completionHandler : @escaping ((_ responseURL : URL?) -> Void)) {
if asset.mediaType == .image {
let options: PHContentEditingInputRequestOptions = PHContentEditingInputRequestOptions()
options.canHandleAdjustmentData = {(adjustmeta: PHAdjustmentData) -> Bool in
return true
}
asset.requestContentEditingInput(with: options, completionHandler: { (contentEditingInput, info) in
completionHandler(contentEditingInput!.fullSizeImageURL)
})
} else if asset.mediaType == .video {
let options: PHVideoRequestOptions = PHVideoRequestOptions()
options.version = .original
PHImageManager.default().requestAVAsset(forVideo: asset, options: options, resultHandler: { (asset, audioMix, info) in
if let urlAsset = asset as? AVURLAsset {
let localVideoUrl = urlAsset.url
completionHandler(localVideoUrl)
} else {
completionHandler(nil)
}
})
}
}