So I've been trying to accomplish this for quite some time now, but unfortunately none of the solutions posted on stack, or the ones I tried to write myself seem to work. I am building an application that allows users to take pictures and videos, and other users to save these down. I am using AWS services to save the content. Although the returned URL using NSLog, shows me the video when copy/pasting it to a browser, it refuses to save to the camera roll. Saving pictures however works fine.
So far I tried the following:
-(void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
if([mediaType isEqualToString:(NSString *)kUTTypeMovie]) {
NSURL *movieUrl = [info objectForKey:UIImagePickerControllerMediaURL];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeVideoAtPathToSavedPhotosAlbum:movieUrl completionBlock:^(NSURL *assetURL, NSError *error){
if(error) {
NSLog(#"CameraViewController: Error on saving movie : %# {imagePickerController}", error);
} else {
NSLog(#"URL: %#", assetURL);
}
}];
}
}
and also:
if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(self.post.mediaUrl)) {
UISaveVideoAtPathToSavedPhotosAlbum(self.post.mediaUrl, self, #selector(video:finishedSavingWithError:contextInfo:),#selector(video:finishedSavingWithError:contextInfo:));
} else {
NSLog(#"Incompatible File apparently");
}
Any advice? Thanks!
*Updated on April 6, 2016 to make use of modern frameworks
Import the following in wherever you place this method:
#import <AssetsLibrary/AssetsLibrary.h>
#import Photos
Then call method as following:
[yourClass saveMedia:(*your image*) video:(*your video url*)]
Hope this helps people, feel free to comment with questions.
+ (void)saveMedia:(UIImage *)image video:(NSURL *)video_url {
if(image) {
if(!image) {
return;
}
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromImage:image];
NSLog(#"%#", changeRequest.description);
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"saved down");
} else {
NSLog(#"something wrong");
}
}];
} else if (video_url) {
if([video_url absoluteString].length < 1) {
return;
}
NSLog(#"source will be : %#", video_url.absoluteString);
NSURL *sourceURL = video_url;
if([[NSFileManager defaultManager] fileExistsAtPath:[video_url absoluteString]]) {
[[[ALAssetsLibrary alloc] init] writeVideoAtPathToSavedPhotosAlbum:video_url completionBlock:^(NSURL *assetURL, NSError *error) {
if(assetURL) {
NSLog(#"saved down");
} else {
NSLog(#"something wrong");
}
}];
} else {
NSURLSessionTask *download = [[NSURLSession sharedSession] downloadTaskWithURL:sourceURL completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
if(error) {
NSLog(#"error saving: %#", error.localizedDescription);
return;
}
NSURL *documentsURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
NSURL *tempURL = [documentsURL URLByAppendingPathComponent:[sourceURL lastPathComponent]];
[[NSFileManager defaultManager] moveItemAtURL:location toURL:tempURL error:nil];
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:tempURL];
NSLog(#"%#", changeRequest.description);
} completionHandler:^(BOOL success, NSError *error) {
if (success) {
NSLog(#"saved down");
[[NSFileManager defaultManager] removeItemAtURL:tempURL error:nil];
} else {
NSLog(#"something wrong %#", error.localizedDescription);
[[NSFileManager defaultManager] removeItemAtURL:tempURL error:nil];
}
}];
}];
[download resume];
}
}
}
In Objective - C
Add this in .h/.m file
#import <Photos/Photos.h>
Save Video to Camera Roll:
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:videoUrl];
}
completionHandler:^(BOOL success, NSError *error) {
if (success)
{
NSLog(#"Video saved");
}else{
NSLog(#"%#",error.description);
}
}];
Related
In my app I used edit pic and saved in custom folder in Gallery called "Fab". now is there anything to delete that image from folder? I have found different solution but they require asset URL. I used Photos framework so how to get asset url for particular image for deletion ?
PHAsset *tempPhasset = [_arrImageForAssetCameraRoll objectAtIndex:index]; // here pass your PHasset that you want to delete .
NSString *localStr=tempPhasset.localIdentifier;
NSRange range = [localStr rangeOfString:#"/"];
NSString *newString = [localStr substringToIndex:range.location];
NSString *appendedString=[NSString stringWithFormat:#"%#%#%#",#"assets-library://asset/asset.JPG?id=",newString,#"&ext=JPG"];
NSLog(#"%# phasset ",appendedString);
NSURL *deleteurl = [NSURL URLWithString:appendedString];
NSArray *arrDelete = [[NSArray alloc] initWithObjects:deleteurl , nil];
PHFetchResult *asset = [PHAsset fetchAssetsWithALAssetURLs:arrDelete options:nil];
[asset enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#"%#",[obj class]);
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
BOOL req = [obj canPerformEditOperation:PHAssetEditOperationDelete];
if (req) {
NSLog(#"true");
[PHAssetChangeRequest deleteAssets:#[obj]];
}
} completionHandler:^(BOOL success, NSError *error) {
NSLog(#"Finished Delete asset. %#", (success ? #"Success." : error));
if (success) {
NSLog(#"delete successfully");
}else{
NSLog(#"delete Cancel");
}
}];
Any query about my code then put comment .
Happy Coding.
Try this below code
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:[viewImage CGImage] orientation:(ALAssetOrientation)[viewImage imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error){
if (error) {
NSLog(#"error");
} else {
NSLog(#"url %#", assetURL);
}
}];
will return url for saved image.
I want to share both text and URL from host app using sharing extension.
- (BOOL)isContentValid {
for (NSExtensionItem *item in self.extensionContext.inputItems) {
for (NSItemProvider *itemProvider in item.attachments) {
if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeURL ]) {//
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeURL options:nil completionHandler:^(NSURL *url, NSError *error) {
if(url ) {
self.linksURL= [url absoluteString];
}
}];
}
else if ([itemProvider hasItemConformingToTypeIdentifier:(NSString *)kUTTypeText ])
{
[itemProvider loadItemForTypeIdentifier:(NSString *)kUTTypeText options:nil completionHandler:^(NSURL *url, NSError *error) {
if(url ) {
self.linkTitleText= [url absoluteString];
}
}];
}
}
}
self.charactersRemaining=#85;
return YES;
}
Most of this is correct but the implementation of the method is wrong as you will return TRUE before anything has happened. Instead of doing it this way I suggest using a method with a completion handler like so...
-(void)contentURL:(NSExtensionItem *)extension completion:(void (^)(NSURL *url))completion {
for (NSItemProvider *items in self.shareItem.attachments) {
if ([items hasItemConformingToTypeIdentifier:(NSString *)kUTTypeURL]) {
[items loadItemForTypeIdentifier:(NSString *)kUTTypeURL options:nil completionHandler:^(NSURL *url, NSError *error) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
completion(url);
}];
}];
}
}
}
Then create a similar method for the text attribute.
P.S Don't forget to put the operation in a block
For iOS9, ALAssetsLibrary is deprecated. So how to change it as PHPPhotoLibrary instead of ALAssets?
if (RecordedSuccessfully && recording == NO) {
//----- RECORDED SUCESSFULLY -----
NSLog(#"didFinishRecordingToOutputFileAtURL - success");
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:outputFileURL])
{
[library writeVideoAtPathToSavedPhotosAlbum:outputFileURL
completionBlock:^(NSURL *assetURL, NSError *error)
{
if (error)
{
}
}];
}
// i have tried this, but didnt work
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest* createAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:outputFileURL];
NSParameterAssert(createAssetRequest);
}
completionHandler:^(BOOL success, NSError *error) {}];
}
}
// Save to the album
__block PHObjectPlaceholder *placeholder;
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest* createAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:outputFileURL];
placeholder = [createAssetRequest placeholderForCreatedAsset];
} completionHandler:^(BOOL success, NSError *error) {
if (success)
{
NSLog(#"didFinishRecordingToOutputFileAtURL - success for ios9");
}
else
{
NSLog(#"%#", error);
}
}];
Using this chunk of code only for accessing the Adobe files in my iOS project, but how can I upload my pictures in Adobe Assets cloud and save it.
[[AdobeUXAssetBrowser sharedBrowser]popupFileBrowser:^(AdobeSelectionAssetArray *itemSelections) {
NSLog(#"Selected a file");
for(id item in itemSelections) {
AdobeAsset *it = ((AdobeSelectionAsset *)item).selectedItem;
NSLog(#"File name %#", it.name);
[_statuslabel setText:fileDesc];
//If an image, let's draw it locally
NSString *fileType = ((AdobeAssetFile *)it).type;
if([fileType isEqualToString:#"image/jpeg" ] || [fileType isEqualToString:#"image/png" ]) {
NSLog(#"Going to download the image");
[((AdobeAssetFile *)it) getData:NSOperationQueuePriorityHigh
onProgress:^(double fractionCompleted) {
}
onCompletion:^(NSData *data, BOOL fromcache) {
NSLog(#"Done downloaded");
UIImage *preview = [UIImage imageWithData:data];
}
onCancellation:^(void){
}
onError:^(NSError *error) {
}
];
}
}
} onError:^(NSError *error)
{
//do nothing
NSLog(#"Error");
}];
You can find a tutorial on how to upload and download files from Creative Cloud using the CreativeSDK here:
https://creativesdk.adobe.com/docs/ios/#/articles/files/index.html
The code in particular that deals with file uploads is below:
NSData *imgData = UIImageJPEGRepresentation( yourImage, 0.8f );
NSString *dataPath = [NSTemporaryDirectory() stringByAppendingPathComponent:#"foo.jpg"];
NSURL *dataURL = [NSURL fileURLWithPath:dataPath];
NSError *err;
BOOL success = [imgData writeToFile:dataPath options:NSDataWritingAtomic error:&err];
if (success) {
AdobeAssetFolder *root = [AdobeAssetFolder getRootOrderedByField:AdobeAssetFolderOrderByName orderDirection:AdobeAssetFolderOrderDescending];
[AdobeAssetFile create:#"foo.jpg"
inFolder:root
withDataPath:dataURL
withType:kMimeTypeJPEG
withCollisionPolicy:AdobeAssetFileCollisionPolicyAppendUniqueNumber
onProgress:^(double fractionCompleted) {
NSLog(#"Percent complete %f", fractionCompleted);
}
onCompletion:^(AdobeAssetFile *file) {
NSLog(#"Uploaded");
}
onCancellation:nil
onError:^(NSError *error) {
NSLog(#"error uploading %#", error);
}];
}
Im trying to save an AvAsset with multiple videos and merging them into a single video.
That part is taken care of though when the block completes it gives me an error.
My block:
-(void)exportDidFinish:(AVAssetExportSession*)session withCompletionBlock:(void(^)(BOOL success))completion {
self.exportSession = nil;
__block id weakSelf = self;
//delete stored pieces
[self.assets enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(AVAsset *asset, NSUInteger idx, BOOL *stop) {
NSURL *fileURL = nil;
if ([asset isKindOfClass:AVURLAsset.class])
{
AVURLAsset *urlAsset = (AVURLAsset*)asset;
fileURL = urlAsset.URL;
}
if (fileURL)
[weakSelf removeFile:fileURL];
NSLog(#"File Url: %#", fileURL);
}];
[self.assets removeAllObjects];
//[self.delegate removeProgress];
if (session.status == AVAssetExportSessionStatusCompleted) {
NSURL *outputURL = session.outputURL;
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:outputURL]) {
[library writeVideoAtPathToSavedPhotosAlbum:outputURL completionBlock:^(NSURL *assetURL, NSError *error){
//delete file from documents after saving to camera roll
[weakSelf removeFile:outputURL];
if (error) {
completion (NO);
} else {
completion (YES);
}
}];
}
}
//Upload service
completion(YES);
[self.assets removeAllObjects];
}
This is the exact error I am receiving:
I would like to say I have a lot of experience with AVFoundation and the Assets though I do not and cant figure out why the completion block is failing.
What could be the issue and if you need anymore information let me know and i can update the question.
Turns out i had named my IBAction for the save button the name of the completionBlock so it was calling itself and failing.
Changed the name, and now it all works very good.