UIDocumentInteractionController annotation property doesn't copy caption to presented application - ios

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"];

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];

Open Instagram in IOS 9 with UIDocumentInteractionController

Hi this is my code to open Instagram App directly with an image. As stated in Apple document relative to UIDocumentInteractionController and in Instagram hook page this snippet of code should open instagram directly with the image, but in all testing conditions it open the action sheet with all the app compatible with the extension saved.
I've also whitelisted instagram in LSApplicationQueriesSchemes.
How can i achive this result? It's a bug or a new security feature of IOS 9?
Thanks in advance for your help
NSURL *instagramURL = [NSURL URLWithString:#"instagram:/"];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL])
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *getImagePath = [documentsDirectory stringByAppendingPathComponent:#"savedImage.ig"];
[UIImagePNGRepresentation(capturedImage) writeToFile:getImagePath atomically:YES];
NSURL *imageFileURL =[NSURL fileURLWithPath:getImagePath];
NSLog(#"imag %#",imageFileURL);
self.dic.delegate = self;
self.dic.UTI = #"com.instagram.photo";
self.dic = [self setupControllerWithURL:imageFileURL usingDelegate:self];
[self.dic presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
} else //prompt for app missing
- (UIDocumentInteractionController *) setupControllerWithURL: (NSURL*) fileURL
usingDelegate: (id <UIDocumentInteractionControllerDelegate>) interactionDelegate {
UIDocumentInteractionController *interactionController =
[UIDocumentInteractionController interactionControllerWithURL: fileURL];
interactionController.delegate = interactionDelegate;
return interactionController;
}
if you save the image as .igo the only apps i see in the actionsheet are "Instagram" "Notes" and "other.
edit: I have't found a way to open Instagram directly with an image it only seems possible to open it directly with
NSURL *instagramURL = [NSURL URLWithString:#"instagram://location?id=1"];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
[[UIApplication sharedApplication] openURL:instagramURL];
}
but you can't add an image with that
edit2: I forgot to add that for the .igo format you need to use self.dic.UTI = "com.instagram.exclusivegram"

Caption does not appear on Instagram photo after setting UIDocumentInteractionController's annotation property

My app can successfully upload photos to Instagram using UIDocumentInteractionController, but I am unable to successfully upload the photo with a caption.
The Instagram docs tell you to do this:
To include a pre-filled caption with your photo, you can set the
annotation property on the document interaction request to an
NSDictionary containing an NSString under the key "InstagramCaption".
Note: this feature will be available on Instagram 2.1 and later.
I have tried this five times now. I have tried creating an NSDictionary several different ways including using literal syntax but I still cannot get it to work so it has to be something wrong with Instagram.
Here is a sample of my code that sets up the document and opens the photo in the Instagram iOS app:
UIImage *screenShot = finalImage;
NSString *savePath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/Test.igo"];
[UIImagePNGRepresentation(screenShot) writeToFile:savePath atomically:YES];
CGRect rect = CGRectMake(0 ,0 , 0, 0);
NSString *jpgPath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/Test.igo"];
NSURL *igImageHookFile = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:#"file://%#", jpgPath]];
self.dic.UTI = #"com.instagram.photo";
self.dic.annotation = #{#"InstagramCaption" : #"Here's my caption!"};
self.dic = [self setupControllerWithURL:igImageHookFile usingDelegate:self];
self.dic=[UIDocumentInteractionController interactionControllerWithURL:igImageHookFile];
[self.dic presentOpenInMenuFromRect:rect inView:self.view animated:YES];
NSURL *instagramURL = [NSURL URLWithString:#"instagram://media?id=MEDIA_ID"];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
[self.dic presentOpenInMenuFromRect: rect inView: self.view animated: YES ];
} else {
NSLog(#"No Instagram Found");
}
}
Notice how I am setting self.dic.annotation properly and follow Instagram's guidelines.
The photo opens up fine in the Instagram iOS app and will successfully upload to the user's profile, but the caption is never included.
It looks like people were having this same problem back in 2013, but then the issue was fixed.
I just figured it out.
All I did was move my statement where I define self.dic.annotation underneath the following statement:
self.dic = [UIDocumentInteractionController interactionControllerWithURL:igImageHookFile];
The above statement is returning a new instance of UIDocumentInteractionController and obviously none of it's properties are set.
EDIT: I would advise not to use the original code I posted unless you are willing to make changes. I just noticed that there are two statements returning a UIDocumentInteractionController instance and they are both right next to each other:
self.dic = [self setupControllerWithURL:igImageHookFile usingDelegate:self];
self.dic = [UIDocumentInteractionController interactionControllerWithURL:igImageHookFile];
This code came from a tutorial so I cannot vouch for it's quality. If you want to use it, make sure to analyze it line for line so you don't run into any of the confusion that I did.
EDIT 2:
Here is the final code sample that works perfectly. You should be able to use this with no errors:
UIImage *screenShot = finalImage;
NSString *savePath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/Test.igo"];
[UIImagePNGRepresentation(screenShot) writeToFile:savePath atomically:YES];
CGRect rect = CGRectMake(0 ,0 , 0, 0);
NSString *jpgPath = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents/Test.igo"];
NSURL *igImageHookFile = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:#"file://%#", jpgPath]];
self.dic = [UIDocumentInteractionController interactionControllerWithURL:igImageHookFile];
self.dic.UTI = #"com.instagram.photo";
self.dic.annotation = [NSDictionary dictionaryWithObject:#"Enter your caption here" forKey:#"InstagramCaption"];
[self.dic presentOpenInMenuFromRect:rect inView:self.view animated:YES];
NSURL *instagramURL = [NSURL URLWithString:#"instagram://media?id=MEDIA_ID"];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL]) {
[self.dic presentOpenInMenuFromRect: rect inView: self.view animated: YES ];
} else {
NSLog(#"No Instagram Found");
}

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];

UIActivityViewController & UIDocumentInteractionController not showing options

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

Resources