I working on sharing array of images from gallery using share extension. i can get image inside share extension using
- (void)getImageFromExtension:(NSExtensionItem *)extensionItem
{
for(NSItemProvider *attachment in extensionItem.attachments)
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if([attachment hasItemConformingToTypeIdentifier:(NSString *)kUTTypeImage])
{
[attachment loadItemForTypeIdentifier:(NSString *)kUTTypeImage options:nil completionHandler:^(id<NSSecureCoding> item, NSError *error) {
NSURL *image = (NSURL *)item;
if(error)
{
NSLog(@"Error retrieving image");
} else {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"*** ### %@",[UIImage imageWithData:[NSData dataWithContentsOfURL:image]]);
});
}
}];
}
});
}
}
What i actually need is, i need to pass image url to container applciation. But not able to get image from that URL. The url format is file:///var/mobile/Media/DCIM/101APPLE/IMG_1705.JPG
The data from this url is always null. how to get the image from this URL?
You probably call getImageFromExtension
from didSelectPost
. At the end of didSelectPost
you are supposed to call completeRequestReturningItems:completionHandler:
to tell the host app to complete the app extension request with an array of result items. When that method is called the whole ShareViewController is dismissed and deallocated. When you call this at the end of didSelectPost
, it gets executed before the NSItemProvider
could retrieve the image URL. Because that happens asynchronously. To fix this you have to call completeRequestReturningItems:completionHandler:
after NSItemProvider
has retrieved the imageURL.
Here is how it should work:
- (void)didSelectPost {
NSString *typeIdentifier = (NSString *)kUTTypeImage
NSExtensionItem *item = self.extensionContext.inputItems.firstObject;
NSItemProvider *itemProvider = item.attachments.firstObject;
if ([itemProvider hasItemConformingToTypeIdentifier:typeIdentifier]) {
[itemProvider loadItemForTypeIdentifier:typeIdentifier
options:nil
completionHandler:^(NSURL *url, NSError *error) {
NSURL *imageURL = (NSURL *)item
self.saveImage(imageURL)
[self.extensionContext completeRequestReturningItems:@[]
completionHandler:nil];
}];
}
}
By the way, there is no need to use dispatch_async
when working with NSItemProvider as the provider is already doing his work asynchronously.
I've written a blog post about this, if you want to read a bit more about this.
EDIT
You can now load the image with the file path that you just retrieve. This works only in the extension! If you want to access the image from the containing app you cannot use the file URL you just retrieved. The share extension saves the selected image in a folder that is not accessible by the containing app.
To make the image available to the containing app you have to activate App Groups
in you containing app and the extension. Then the extension saves the image to the shared container and the containing app can retrieve it:
func saveImage(url: NSURL) {
guard let imageData = NSData(contentsOfURL: url) else { return }
let selectedImage = UIImage(data: imageData)
let fileManager = NSFileManager.defaultManager()
if let sharedContainer = fileManager.containerURLForSecurityApplicationGroupIdentifier("YOUR_GROUP_IDENTIFIER") {
if let dirPath = sharedContainer.path {
let sharedImageFilePath = dirPath + "/image.png"
let binaryImageData = UIImagePNGRepresentation(selectedImage!)
binaryImageData?.writeToFile(sharedImageFilePath, atomically: true)
// send the sharedImageFilePath to the containing app
}
}
}