I am having some trouble in sharing videos with airdrop. So, i am using the AssetLibrary like this :
else if (conformsToVideo) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Asset Loaded" message:#"Video One Loaded"
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
self.mediaAsset = [AVAsset assetWithURL:[info objectForKey:UIImagePickerControllerMediaURL]];
UIActivityViewController * controller = [[UIActivityViewController alloc] initWithActivityItems:#[self.mediaAsset] applicationActivities:nil];
[self presentViewController:controller animated:YES completion:nil];
}
Maybe this is just not the way to do it, I don't know and I didn't find any tutorial about it so if you have one, I will gladly take it.
Now my problem is that when i select a video everything works fine until the UIActivityViewController pops out , i don't have any error but I can't use airdrop (nor any other service BTW) the only thing I can do is press the Cancel button of the UIAVController.
I am using iOS 8.3.
Thanks for your help
Ok, eventually I found an answer, maybe not the best but I put it there in case it helps someone cause I didn't find much on sharing video with airdrop :
NSURL * path = [info objectForKey:UIImagePickerControllerReferenceURL];
BOOL conformsToVideo = (UTTypeConformsTo((__bridge_retained CFStringRef) mediaType, kUTTypeAudiovisualContent));
if (conformsToVideo) {
[self.library assetForURL:path
resultBlock:^(ALAsset *asset) {
ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
NSString* outputDirectory = [NSString stringWithFormat:#"%#", NSTemporaryDirectory()];
NSString* pathToCopy = [outputDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#", assetRepresentation.filename]];
NSUInteger size = (NSUInteger)assetRepresentation.size;
NSMutableData* data = [NSMutableData dataWithLength:size];
NSUInteger bytesRead = [assetRepresentation getBytes:data.mutableBytes fromOffset:0 length:size error:nil];
NSURL * url = nil;
if ([data writeToFile:pathToCopy atomically:YES])
{
NSLog(#"Ok");
url = [NSURL fileURLWithPath:pathToCopy];
UIActivityViewController * controller = [[UIActivityViewController alloc] initWithActivityItems:#[url] applicationActivities:nil];
[self presentViewController:controller animated:YES completion:nil];
}
} failureBlock:^(NSError *error) {
NSLog(#"Failure to use the ALAsset");
}
];
}
I found the solution using this question : Share a video from asset library with AirDrop fails
I am merely adding the previous steps to the code given there, hope it can be useful.
Related
I am using UIActivityViewController to share my generated image, it worked fine for certain apps like Whatsapp or sharing via Email, but i also wanted to share it using Messages app. I've tried several ways to do it but i can't display Messages app on it.
Here's my code :
UIImage *receiptStage3 = [CreateReceiptImage putLogo:nil putLabel:TRANSACTION_RECEIPT inImage:receiptStage2];
NSData *imageData = UIImageJPEGRepresentation(receiptStage3,0.5);
// create url
NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyyMMddHHmmss"];
NSString *fileName = [NSString stringWithFormat:#"%#%#%#", #"FormatHere-", [dateFormatter stringFromDate:[NSDate date]],#".jpg"];
NSURL *url = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingString:fileName]];
NSData *data = imageData;
// write data
[data writeToURL:url atomically:NO];
NSArray *activityItems = #[url];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:activityItems applicationActivities:nil];
activityVC.excludedActivityTypes = #[UIActivityTypePostToTencentWeibo, UIActivityTypePostToVimeo, UIActivityTypePostToWeibo, UIActivityTypePostToFlickr, UIActivityTypePostToTwitter, UIActivityTypePostToFacebook, UIActivityTypePrint, UIActivityTypeAssignToContact, UIActivityTypeOpenInIBooks, UIActivityTypeAirDrop,UIActivityTypeSaveToCameraRoll,UIActivityTypeAddToReadingList];
[activityVC setCompletionWithItemsHandler:^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) {
//Delete file
NSError *errorBlock;
if([[NSFileManager defaultManager] removeItemAtURL:url error:&errorBlock] == NO) {
NSLog(#"error deleting file %#",#"error");
return;
}
}];
[self presentViewController:activityVC animated:YES completion:nil];
As i said before i've tried several ways like putting NSUrl #[url] and UIImage *receiptStage3 directly to initWithActivityItems. I've also tried to remove excludedActivityTypes but the Message option wont show. Am i missing something ? or are there another ways to do this ? Thanks before
Your code is completely fine, works to me.
First of all you Messages app may be missing if you have iMessage disabled in your settings. Go to Settings->Messages and make sure it's on:
Also you may not see it in the default items, check out hidden ones:
In my app I have to implement save image feature. I have managed saving like this:
UIImage *image = [UIImage imageNamed:actualBackground];
UIImageWriteToSavedPhotosAlbum(
image, self,
#selector(thisImage:hasBeenSavedInPhotoAlbumWithError:usingContextInfo:),
nil);
/* ... */
- (void)thisImage:(UIImage *)image
hasBeenSavedInPhotoAlbumWithError:(NSError *)error
usingContextInfo:(void *)ctxInfo {
if (!error){
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
[self presentViewController:picker animated:YES completion:nil];
}
}
Unfortunately I have to check if file already exists to prevent redundant saving. Also this is necessary because saving multiple times the same image don't override one file, but it creates copy of it...
Do you know how to solve that problem?
SOLUTION:
According to Shravya Boggarapu answer I'm storing assetUrl in my NSUserDefaults. Complete code:
- (IBAction)onDownloadClick:(UIButton *)sender {
UIImage *image = [UIImage imageNamed:actualBackground];
NSString *key = [NSString stringWithFormat:#"assetsUrl %#", actualBackground];
NSString *savedValue =
[[NSUserDefaults standardUserDefaults] stringForKey:key];
NSURL *url = [NSURL URLWithString:savedValue];
if (url != nil) {
PHFetchResult *fetch =
[PHAsset fetchAssetsWithALAssetURLs:[NSArray arrayWithObject:url]
options:nil];
if ([fetch count]) {
UIAlertView *myAlert = [[UIAlertView alloc]
initWithTitle:nil
message:NSLocalizedString(#"Already downloaded", nil)
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[myAlert show];
return;
}
}
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library
writeImageToSavedPhotosAlbum:image.CGImage
orientation:(ALAssetOrientation)image.imageOrientation
completionBlock:^(NSURL *assetURL, NSError *error) {
[library assetForURL:assetURL
resultBlock:^(ALAsset *asset) {
NSLog(#"assetURL %#", assetURL);
NSString *ass = [assetURL absoluteString];
[[NSUserDefaults standardUserDefaults]
setObject:ass
forKey:key];
[[NSUserDefaults standardUserDefaults] synchronize];
UIAlertView *myAlert = [[UIAlertView alloc]
initWithTitle:nil
message:NSLocalizedString(
#"Image downloaded", nil)
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[myAlert show];
}
failureBlock:^(NSError *error){
}];
}];
}
Hope it will help somebody.
I have a solution but not one that applies to every situation.
The thing about saving image to camera roll is that there is an assetURL created when you add the image to camera roll. Also, this asset URL is new every time, so if you save to camera roll, it will create a copy. The name of the image is also not retained.
If the image is added to the camera roll through your app in the first place, then you can store the assetURL as part of image information.
In my app, a dictionary is maintained for every image containing some critical info. This includes the assetURL of the image if it is saved to camera roll.
Once you have the URL, you can check its existence by using fetchAssetsWithALAssetURLs:options: function.
If the URL is nil or the asset when fetched is nil, it means that the image does not exist in the camera roll. So you can add anew.
There is no easy way to compare two images and if you found one that will surly a heavy task, instead of this we can compare image's meta data which we can write it to image and also read it from images.
You can use this repo for that
And ALAssetLibrary also have some properties to access an images meta info. If you google with this you will surly get some.
Like this one
I want to create custom photo album and save photo to specific album in iOS 7. and I found iOS save photo in an app specific album using ALAssetsLibrary.
But I don't know how to do it using UIActivityViewController.
NSArray* actItems = [NSArray arrayWithObjects: image, nil];
UIActivityViewController *activityView = [[UIActivityViewController alloc]
initWithActivityItems:actItems
applicationActivities:nil];
[activityView setCompletionHandler:^(NSString *activityType, BOOL completed)
{
if ([activityType isEqualToString:UIActivityTypeSaveToCameraRoll])
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"#Saved_title", nil)
message:NSLocalizedString(#"#Saved_message2", nil)
delegate:self
cancelButtonTitle:NSLocalizedString(#"OK", nil)
otherButtonTitles: nil];
[alert show];
}
}];
I realize the question is a few months old and that the OP may have moved on, but I needed to do exactly this, but didn't find another solution, and needed to come up with my own.
It's not fool-proof, as if there are multiple copies of the video/image in Camera Roll that you're wanting to copy, it will copy all of them, which may or may not be desired. Also, for my purposes, I'm considering maintaining a persistent list of asset URLs that I've written to the custom album so that I skip that asset in the future, but I haven't yet coded it because, if the user removes the video/image from the custom album, it'd be nearly impossible to update that list without more iteration through asset groups: something I'd like to avoid.
Last disclaimer: I haven't tested this a whole ton yet, but it works for my purposes, so hopefully someone else out there can benefit from it.
I augmented Marin Todorov's ALAssetsLibrary+CustomPhotoAlbum category, which I found here: https://github.com/yusenhan/Smooth-Line-View/tree/master/ALAssetsLibrary%2BCustomPhotoAlbum. Note: there is no license information provided there, so I'm assuming that modifying the source for this category is ok.
Here is my method which sets up and displays the UIActivityViewController:
- (void)showActivitySheet:(NSString *)path {
NSURL *newURL = [NSURL fileURLWithPath:path];
NSArray *itemsToShare = #[newURL];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:itemsToShare applicationActivities:nil];
activityVC.excludedActivityTypes = #[UIActivityTypePrint, UIActivityTypeAssignToContact, UIActivityTypeAddToReadingList];
// Once the OS has finished with whatever the user wants to do with it,
// we'll begin figuring out if we need to save it to the Album, too!
[activityVC setCompletionHandler:^(NSString *activityType, BOOL completed) {
// If the user selected "Save to Camera Roll"
if ([activityType isEqualToString:UIActivityTypeSaveToCameraRoll]) {
ALAssetsLibrary *lib = [[ALAssetsLibrary alloc] init];
NSURL *tempUrl = [NSURL fileURLWithPath:path];
// saveMovie: below is a method I added to the category, but you can use saveImage:,
// which you'll also likely want to add some kind of parameter to so, in the category,
// you know when you only want to copy to the Album instead of the Album AND Camera Roll
[lib saveMovie:tempUrl toAlbum:#"CUSTOM ALBUM NAME"
withCompletionBlock:^(NSURL *url, NSError *error) {
if (error) {
NSLog(#"Error writing movie to custom album: %#", error.debugDescription);
}
}
onlyWriteToCustomAlbum:YES];
}
}];
[self presentViewController:activityVC animated:YES completion:nil];
}
Here is code you can add to the saveImage: method in the ALAssetsLibrary+CustomPhotoAlbum category so you can save it to your custom Album, too! You could execute this portion only on the YES case of the BOOL which you'll want to add to the category.
NSData *dataToCompareTo = [NSData dataWithContentsOfURL:url]; // This data represents the image/movie which you want to save into the custom album. The one you handed to the UIActivityViewController.
// Note use of self, as this is a category on ALAssetsLibrary; also, this
// assumes that you've already written the photo to the Camera Roll, which
// should be automatically handled by the OS, if the user hit the "Save" button
// on the UIActivityViewController.
// Enumerate through Camera Roll/Saved Photos group.
[self enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos
usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
// Enumerate the assets in each group.
[group enumerateAssetsUsingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
ALAssetRepresentation *rep = [result defaultRepresentation];
// If the asset isn't the same size as the source image/movie
// it shouldn't be the same. Check the size first, since it
// is a less costly operation than byte checking the data itself.
if ([rep size] == [dataToCompareTo length]) {
Byte *buffer = malloc([NSNumber numberWithLongLong:rep.size].unsignedLongValue);
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:[NSNumber numberWithLongLong:rep.size].unsignedLongValue error:nil];
NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];
// If the buffer has more than the null-termination char, free it! I'm doing this in case the above call to dataWithBytesNoCopy fails to free() the buffer.
if (sizeof(buffer) > 4) {
free(buffer);
}
// Ensure they are the same by comparing the NSData instances.
if ([data isEqualToData:dataToCompareTo]) {
NSLog(#"they are the same!!");
[self addAssetURL:[rep url]
toAlbum:albumName
withMovieCompletionBlock:completionBlock];
} else {
NSLog(#"they are different");
}
}
}];
} failureBlock:^(NSError *error) {
NSLog(#"Failed to write to custom album!");
}];
Hope it helps! TLDR? Thought so! ;-)
I am new to UIActivityViewController and perhaps I am missing a basic understanding. What I am trying to do is attached a csv, xml and vcard file to activity controller and show dropbox, google drive etc options. I have downloaded and installed dropbox, google drive etc apps on my iPhone.
Now when I launch UIActivityViewController all I see are default message and email app in my acitivity controller. How can I have other apps show up on their too? Do I need to install each and every apps individual SDKs and somehow incorporate them in my app?
This is what I wold like to see
but this is what I see instead.
Here's the code that I have tried so far
-(IBAction) dropBoxAction
{
paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask ,YES);
NSString* documentsPath = [paths objectAtIndex:0];
//CSV
NSMutableString *fileNameStr = [NSMutableString stringWithFormat:#"test_CSV_Backup.csv"];
NSString* csvDataFileStr = [documentsPath stringByAppendingPathComponent:fileNameStr];
NSData *csvData = [NSData dataWithContentsOfFile:csvDataFileStr];
//EXCEL
NSMutableString *fileNameStr2 = [NSMutableString stringWithFormat:#"test_EXCEL_Backup.xml"];
NSString* excelDataFileStr = [documentsPath stringByAppendingPathComponent:fileNameStr2];
NSData *excelData = [NSData dataWithContentsOfFile:excelDataFileStr];
//VCARD
NSMutableString *fileNameStr3 = [NSMutableString stringWithFormat:#"test_VCARD_Backup.vcf"];
NSString* vcardDataFileStr = [documentsPath stringByAppendingPathComponent:fileNameStr3];
NSData *vcardData = [NSData dataWithContentsOfFile:vcardDataFileStr];
//adding them all together
NSMutableArray *sharingItems = [NSMutableArray new];
[sharingItems addObject:csvData];
[sharingItems addObject:excelData];
[sharingItems addObject:vcardData];
UIActivity *activity = [[UIActivity alloc] init];
NSArray *applicationActivities = #[activity];
UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:sharingItems applicationActivities:applicationActivities];
[self presentViewController:activityController animated:YES completion:nil];
}
As #rmaddy said, you should use UIDocumentInteractionController to replace UIActivityViewController, just like this:
UIDocumentInteractionController *dc = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:fileNameStr]];
[dc presentOptionsMenuFromRect:self.view.bounds inView:self.view animated:YES];
For anyone interested in future, here's the code all in one place. Do rate it up if this helps.
In your *.h file add this
#interface v1BackupComplete : UIViewController <UIDocumentInteractionControllerDelegate>
{
UIDocumentInteractionController *docController;
}
In your *.m file add this
/************************
* Dropbox ACTION
************************/
-(IBAction) dropBoxAction2
{
NSLog(#"dropBoxAction2 ...");
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask ,YES);
NSString* documentsPath = [paths objectAtIndex:0];
NSMutableString *fileNameStr3 = [NSMutableString stringWithFormat:#"test_VCARD_Backup.vcf"];
NSString* vcardDataFileStr = [documentsPath stringByAppendingPathComponent:fileNameStr3];
NSURL *fileURL = [NSURL fileURLWithPath:vcardDataFileStr];
docController = [self setupControllerWithURL:fileURL
usingDelegate:self];
bool didShow = [docController presentOpenInMenuFromRect:self.view.bounds inView:self.view animated:YES];
NSLog(#"didShow %d ...", didShow);
if (!didShow)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"ERROR"
message:#"Sorry. The appropriate apps are not found on this device."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert show];
}
}
#pragma mark - UIDocumentInteractionControllerDelegate
- (UIDocumentInteractionController *) setupControllerWithURL:(NSURL *)fileURL
usingDelegate:(id <UIDocumentInteractionControllerDelegate>) interactionDelegate {
UIDocumentInteractionController *interactionController =
[UIDocumentInteractionController interactionControllerWithURL:fileURL];
interactionController.delegate = interactionDelegate;
return interactionController;
}
- (UIViewController *)documentInteractionControllerViewControllerForPreview:(UIDocumentInteractionController *)controller
{
return self;
}
- (UIView *)documentInteractionControllerViewForPreview:(UIDocumentInteractionController *)controller
{
return self.view;
}
- (CGRect)documentInteractionControllerRectForPreview:(UIDocumentInteractionController *)controller
{
return self.view.frame;
}
UIActivityViewController only shows standard built-in activities plus any custom activities you pass as applicationActivities.
For what you are doing, you don't want UIActivityViewController. You want a UIDocumentInteractionController. If you just want to display existing apps that can open the file, use one of the presentOpenInMenuFrom... methods.
But note that is to be used for just a single file, not three.
Passing three files makes no sense in this context.
I have used your code here to open with dropbox and only after I have used presentPreview method (bellow) It was worked for me.
The pdf was shown as preview and then on the preview share button click (top right) the dropbox option ("open in dropbox") did the job. As it works in the mail app in the attachment preview.
[interactionController presentPreviewAnimated:YES];
When i tried to open with presentOpenInMenuFromRect it was crashed on selecting "open in dropbox".
I would like to post a feed on facebook by using fallback share. It should contain an image and a message. I have tried soo much by changing the params
NSMutableDictionary *postParams =
[[NSMutableDictionary alloc] initWithObjectsAndKeys:
#"http://www.abc.com",#"link",
self.produtObj.productImageURL, #"picture",
self.produtObj.productName, #"name",
self.produtObj.productDescription, #"message",
nil];
[FBRequestConnection
startWithGraphPath:#"me/feed"
parameters:postParams
HTTPMethod:#"POST"
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error) {
NSString *alertText;
if (error) {
alertText = [NSString stringWithFormat:
#"error: domain = %#, code = %d",
error.domain, error.code];
} else {
alertText = [NSString stringWithFormat:
#"Posted action, id: %#",
[result objectForKey:#"id"]];
}
// Show the result in an alert
[[[UIAlertView alloc] initWithTitle:#"Result"
message:alertText
delegate:self
cancelButtonTitle:#"OK!"
otherButtonTitles:nil]
show];
}];
With this code, the feed is displayed in a box and clicking on it is taking me to the link spcified. I just want to have an image thumbnail with the story for it not inside the box. Please help me. This is my first question in SOF. So please forgive me for my mistakes.
Thanks in advance. :)
I really prefer to use the UIActivityItemViewConroller for pushing stuff up to facebook.
The user needs to be logged into facebook on their device. You can do that through settings in the Facebook section.
I make the new controller like this for my stuff:
NSMutableArray *stuff = [[NSMutableArray alloc]init];
NSString *textstring = #"Now is the time for all good men to come to the aid of their country. Lorum Ipsum etc";
UIImage *pic = [UIImage imageNamed:#"Icon-Small-50"];//A local image
NSString *URL = #"http://nwc.co/images/nwc-icon-200.gif";//A link to an image
[stuff addObject:textstring];
[stuff addObject:pic];
[stuff addObject:URL];
UIActivityViewController *vc = [[UIActivityViewController alloc]initWithActivityItems:stuff applicationActivities:nil];
[self.navigationController presentViewController:vc animated:YES completion:^{
//do something here when they are done
}];
If you run the above, you'll notice that the text, the local image, and a link to the online image all appear on the post.
And you can exclude other activities, if you don't want to confuse people when the activity icons pop up:
vc.excludedActivityTypes = #[UIActivityTypePrint, UIActivityTypePostToTwitter, UIActivityTypePostToWeibo, UIActivityTypeMail, UIActivityTypeCopyToPasteboard, UIActivityTypeAssignToContact, UIActivityTypeSaveToCameraRoll];