UIActivityViewController & UIDocumentInteractionController not showing options - ios

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".

Related

iOS Could not share video to Whatsapp using UIDocumentInteractionController

It successfully redirects to the Whatsapp app.There is no preview frame and when tapped Send, an error messages pops up "This video could not be sent. Please choose a different video.
Here is my code.
- (void)shareVideo {
NSLog(#"[WhatsAppShare] sharing video");
//NSString *nativePath = [[NSString alloc] initWithCString:path encoding:NSASCIIStringEncoding];
NSString *nativePath=[[NSBundle mainBundle] pathForResource:#"video" ofType:#"mp4"];
// Save video to path in documents directory
NSString *savePath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/whatsAppTmp.wam"];
if([[NSFileManager defaultManager] fileExistsAtPath:savePath]){
if([[NSFileManager defaultManager] removeItemAtPath:savePath error:nil]){
[self shareVideoAtNativePath:nativePath SavePath:savePath];
}
} else {
[self shareVideoAtNativePath:nativePath SavePath:savePath];
}}
- (void)shareVideoAtNativePath:(NSString*)nativePath SavePath:(NSString*)savePath{
NSError*error;
BOOL isSuccess=[[NSFileManager defaultManager] copyItemAtPath:nativePath toPath:savePath error:&error];
if(isSuccess){
// Create interaction controller
self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:savePath]];
self.documentInteractionController.UTI = #"net.whatsapp.movie";
self.documentInteractionController.delegate = self;
[self.documentInteractionController presentOpenInMenuFromRect:CGRectMake(0, 0, 1, 1)
inView:[self view]
animated:YES];
} else{
NSLog(#"error %#", error);
}
}
We have observed the exact same problem. Everything was working until a recent update of WhatsApp. This is probably a bug on WhatsApp side.
Here is a workaround for this problem:
Do not use a wam file, use the mp4 file directly. So in your case, just call
[self shareVideoAtNativePath:nativePath SavePath:nativePath];
Change the UTI to public Mpeg4:
self.documentInteractionController.UTI = #"public.mpeg-4";
This seems to have solved our issue. However, there is a drawback that, the share dialog now contains many other apps/services that can open mp4 files.
We've faced the exact same issue.
The official .wam format brings up only WhatsApp in the share dialog, but fails to forward the video.
Using .m4v format is working for us. A few more options are displayed along with WhatsApp (Open in WhatsApp is the option we want). We are displaying an alert saying "Please select Whatsapp on the next screen" before sending user to the share dialog.
File format: m4v
UTI: net.whatsapp.movie
Please refer to the working code below:
UIDocumentInteractionController *documentInteractionController;
-----
-----
- (void)shareVideoViaWhatsApp:(NSURL*)url{
// Creating temp video to share specifically on whatsapp.
NSString *cachesFolder = [NSTemporaryDirectory() stringByAppendingPathComponent: [NSString stringWithFormat:#"video.m4v"]];
NSURL *file = [NSURL fileURLWithPath:cachesFolder];
[[NSData dataWithContentsOfURL:url] writeToURL:file options:NSDataWritingAtomic error:nil];
documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL: file ];
documentInteractionController.UTI = #"net.whatsapp.movie";
documentInteractionController.delegate = self;
[documentInteractionController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
}
// In code Use share GIF and Video for WhatsApp....
NSString *savePath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/whatsAppTmp.wam"];
savePath = [[NSBundle mainBundle] pathForResource:#"Movie" ofType:#"m4v"];
_documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:_videourl];
_documentInteractionController.UTI = #"net.whatsapp.movie";
_documentInteractionController.delegate = (id)self;
[_documentInteractionController presentOpenInMenuFromRect:CGRectMake(0, 0, 0, 0) inView:self.view animated: YES];

presentOpenInMenuFromRect not working DocumentHandler.h - QuickLook

I'm using documenthandler cordova plugin in where if I click the button I get the pdf in the document handler from the url which works fine, so that I can save the pdf into iBooks.
Now, instead of opening the document in the viewer and clicking the share button and then click again to save into iBooks I need to be able to trigger the share button without opening the document. I know this can be done using presentOpenInMenuFromRect instead of presentViewControllerbut it does not work for some reason, code below:
#import "DocumentHandler.h"
#implementation DocumentHandler
- (void)HandleDocumentWithURL:(CDVInvokedUrlCommand*)command;
{
CDVPluginResult *commandResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:#""];
__weak DocumentHandler* weakSelf = self;
dispatch_queue_t asyncQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(asyncQueue, ^{
NSDictionary* dict = [command.arguments objectAtIndex:0];
NSString* urlStr = dict[#"url"];
NSURL* url = [NSURL URLWithString:urlStr];
NSData* dat = [NSData dataWithContentsOfURL:url];
NSString* fileName = [url lastPathComponent];
NSString* path = [NSTemporaryDirectory() stringByAppendingPathComponent: fileName];
NSURL* tmpFileUrl = [[NSURL alloc] initFileURLWithPath:path];
[dat writeToURL:tmpFileUrl atomically:YES];
weakSelf.fileUrl = tmpFileUrl;
dispatch_async(dispatch_get_main_queue(), ^{
QLPreviewController* cntr = [[QLPreviewController alloc] init];
cntr.delegate = weakSelf;
cntr.dataSource = weakSelf;
UIViewController* root = [[[UIApplication sharedApplication] keyWindow] rootViewController];
[root presentViewController:cntr animated:YES completion:nil];//this works fine and open the document with share button
CGRect rect = CGRectMake(0, 0, 1024, 768);
[root presentOpenInMenuFromRect:rect inView:self.view animated:YES]; // this doesn't work where
//I want to see only sharing options
//here are errors,one of them is /Property'view' not found on object of type ''DocumentHandler
});
[weakSelf.commandDelegate sendPluginResult:commandResult callbackId:command.callbackId];
});
}
#pragma mark - QLPreviewController data source
- (NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController *) controller
{
return 1;
}
- (id <QLPreviewItem>) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger) index
{
return self;
}
#pragma mark - QLPreviewItem protocol
- (NSURL*)previewItemURL
{
return self.fileUrl;
}
#end
I need help please :(
EDIT: see the image what I'm trying to achieve:
presentOpenInMenuFromRect is a UIDocumentInteractionController method. I do not think you are using one in this code, unless your root view controller is a UIDocumentInteractionController, which would be very very weird.
Instead of instantiating and presenting a QLPreviewController, instantiate an UIDocumentInteractionController and present the popover from the rect corresponding to the document's icon.
To do this, check out the UIDocumentInteractionController documentation. You'll see there is an interactionControllerWithURL: method that you can use to instantiate an UIDocumentInteractionController pointed at your file. You can then call
presentOpenInMenuFromRect:inView:animated: to show the popover you want.

UI Activity View Errors

I'm quite the beginner to iOS Programming, and I googled how to get the UI Activity View implemented, but I'm getting errors that I do not quite understand. Anyone that can help me figure out what the errors mean in more specific detail and how to fix them, it would be greatly appreciated.
#pragma mark - SHARING OPTIONS (using a DocumentInteractionController) =============
/* =================
NOTE: The following methods work only on real device, not iOS Simulator, and you should have apps like Instagram, iPhoto, etc. already installed into your device!
================= */
-(void)shareImageToAllAppsAvailable {
NSLog(#"This code works only on device. Please test it on iPhone!");
// makes an NSURL file to the processed Image that needs to be saved
NSURL *fileURL;
docIntController.delegate = self;
//Saves the Image to default device directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:#"My Selfie.jpg"];
UIImage *image = combinedImage;
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];
//Load the Image Path
NSString *getImagePath = [documentsDirectory stringByAppendingPathComponent:#"My Selfie.jpg"];
// this blank line here creates error 'use of undeclared identifier 'showActivityViewController''
// Create the URL path to the Image to be saved
fileURL = [[NSURL alloc] initFileURLWithPath:getImagePath];
// Open the Document Interaction controller for Sharing options
-(void)showActivityViewController
{
//-- set up the data objects
NSString *textObject = _aTextView.text;
UIImage *image = [UIImage imageNamed:#"My Selfie.jpg"];
NSArray *activityItems = [NSArray arrayWithObjects:textObject, url, image, nil];
//-- initialising the activity view controller
UIActivityViewController *avc = [[UIActivityViewController alloc]
initWithActivityItems:activityItems
applicationActivities:nil];
//-- define the activity view completion handler
avc.completionHandler = ^(NSString *activityType, BOOL completed){
NSLog(#"Activity Type selected: %#", activityType);
if (completed) {
NSLog(#"Selected activity was performed.");
} else {
if (activityType == NULL) {
NSLog(#"User dismissed the view controller without making a selection.");
} else {
NSLog(#"Activity was not performed.");
}
}
};
}
You're missing a closing } before your -(void)showActivityViewController declaration.
It looks like you're trying to call that method by defining it within another method, which is not valid Objective-C. Use the self construct to reference methods defined in the same class.
#pragma mark - SHARING OPTIONS (using a DocumentInteractionController) =============
/* =================
NOTE: The following methods work only on real device, not iOS Simulator, and you should have apps like Instagram, iPhoto, etc. already installed into your device!
================= */
-(void)shareImageToAllAppsAvailable {
NSLog(#"This code works only on device. Please test it on iPhone!");
// makes an NSURL file to the processed Image that needs to be saved
NSURL *fileURL;
docIntController.delegate = self;
//Saves the Image to default device directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *savedImagePath = [documentsDirectory stringByAppendingPathComponent:#"My Selfie.jpg"];
UIImage *image = combinedImage;
NSData *imageData = UIImagePNGRepresentation(image);
[imageData writeToFile:savedImagePath atomically:NO];
//Load the Image Path
NSString *getImagePath = [documentsDirectory stringByAppendingPathComponent:#"My Selfie.jpg"];
// this blank line here creates error 'use of undeclared identifier 'showActivityViewController''
// Create the URL path to the Image to be saved
fileURL = [[NSURL alloc] initFileURLWithPath:getImagePath];
// Open the Document Interaction controller for Sharing options
[self showActivityViewController]; //added
} //added
-(void)showActivityViewController
{
//-- set up the data objects
NSString *textObject = _aTextView.text;
UIImage *image = [UIImage imageNamed:#"My Selfie.jpg"];
NSArray *activityItems = [NSArray arrayWithObjects:textObject, url, image, nil];
//-- initialising the activity view controller
UIActivityViewController *avc = [[UIActivityViewController alloc]
initWithActivityItems:activityItems
applicationActivities:nil];
//-- define the activity view completion handler
avc.completionHandler = ^(NSString *activityType, BOOL completed){
NSLog(#"Activity Type selected: %#", activityType);
if (completed) {
NSLog(#"Selected activity was performed.");
} else {
if (activityType == NULL) {
NSLog(#"User dismissed the view controller without making a selection.");
} else {
NSLog(#"Activity was not performed.");
}
}
};
}

UIActivityViewController or UIDocumentInteractionController with WhatsApp and FB

I need to have Facebook and WhatsApp as sharing options for my image. I've already implemented UIActivityViewController, where i can share via Facebook and UIDocumentInteractionController where i can share via WhatsApp. I don't know how to merge these things.
UIActivityViewController:
UIActivityViewController *activityViewContoller = [[UIActivityViewController alloc]
initWithActivityItems:#[#"Test", image] applicationActivities:nil];
[self presentViewController:activityViewContoller animated:YES completion:nil];
UIDocumentInteractionController:
NSString *savePath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/whatsAppTmp.wai"];
[UIImageJPEGRepresentation(image, 1.0) writeToFile:savePath atomically:YES];
_documentInteractionController = [UIDocumentInteractionController
interactionControllerWithURL:[NSURL fileURLWithPath:savePath]];
_documentInteractionController.UTI = #"net.whatsapp.image";
_documentInteractionController.delegate = self;
[_documentInteractionController presentOpenInMenuFromRect:CGRectZero
inView:self.view animated:YES];
I want to have both of them in one popover, however I have no idea how to achieve it. Any tip please?
I've checked out StackOverFlow question 1, but it doesn't help me at all. My file is .wai (for WhatsApp) so when i try to send it via FB file is unable to open. Also it shows all options, while i want only 2(FB+WhatsApp) to be visible. Following the StackOverFlow question 2 I can show only FB (working one, because i set normal image) but can't add WhatsApp (no .wai file, i don't know what to do with UTI). Is there any way to solve this issue?
To change type of file:
- (void)share {
NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/tmptmpimg.jpg"];
[UIImageJPEGRepresentation(_img, 1.0) writeToFile:path atomically:YES];
_documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]];
_documentInteractionController.delegate = self;
[_documentInteractionController presentOptionsMenuFromRect:CGRectZero inView:self.view animated:YES];
}
- (void)documentInteractionController:(UIDocumentInteractionController *)controller willBeginSendingToApplication:(NSString *)application {
if ([self isWhatsApplication:application]) {
NSString *savePath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/tmptmpimg.wai"];
[UIImageJPEGRepresentation(_img, 1.0) writeToFile:savePath atomically:YES];
controller.URL = [NSURL fileURLWithPath:savePath];
controller.UTI = #"net.whatsapp.image";
}
}
- (BOOL)isWhatsApplication:(NSString *)application {
if ([application rangeOfString:#"whats"].location == NSNotFound) { // unfortunately, no other way...
return NO;
} else {
return YES;
}
}
This way we can use all options- Facebook, Twitter and custom WhatsApp.
The problem with showing only selected options is still not solved, but it's the minor one.
To exclude non-desired sharing options (the second part of your question), assuming your UIActivityViewController object is called activityController, set the excludedActivityTypes property, like so:
activityController.excludedActivityTypes = #[UIActivityTypeAssignToContact,
UIActivityTypePrint,
UIActivityTypeAddToReadingList,
UIActivityTypeAirDrop];

UIDocumentInteractionController annotation property doesn't copy caption to presented application

Thanks to a couple other posts here , I've successfully be able to use the Instagram iPhone hooks to open Instagram and present it with a photo successfully from my application.
(I've made my ViewController class a delegate of UIDocumentInteractionController, and alloc/init'ed a nonatomic/retain property of UIDocumentInteractionController...
However, the key that I put into my NSDictionary that I place in the document controller annotation property will not seem to carry over to Instagram - the caption area is just empty.
How do I deal with this?
Here is my method:
- (void) uploadImageToInstagram:(UIImage *)imageToUpload {
NSLog(#"postToInstagramInBackground");
NSURL *instagramURL = [NSURL URLWithString:#"instagram://app"];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
// Upscale to 612x612
imageToUpload = [self upscaleImage:imageToUpload];
// Get JPG + IGO Format
NSString *savePath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/generate.igo"];
[UIImageJPEGRepresentation(imageToUpload, 1.0) writeToFile:savePath atomically:YES];
// Paths
NSURL *imageURL = [NSURL fileURLWithPath:savePath];
NSURL *igImageHookFile = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:#"file://%#",savePath]];
// Setup DocController
self.docController.UTI = #"com.instagram.photo";
self.docController = [self setupControllerWithURL:igImageHookFile usingDelegate:self];
self.docController.annotation = [NSDictionary dictionaryWithObject:#"MyApp" forKey:self.caption.text];
[self.docController setURL:imageURL];
[self.docController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES ];
}
else {
NSLog(#"Instagram not installed in this device!\nTo share image please install Instagram.");
}
}
There are a few methods that are called here that I haven't included, one that upscales the image to make sure its 612x612, and one setups the file url for the document controller.
Proper syntax should be
self.docController.annotation = [NSDictionary dictionaryWithObject:self.caption.text forKey:#"InstagramCaption"];

Resources