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.
Related
I got this problem from this patch of code:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
/*
* get the path to the pdf resource.
*/
NSString *path =
[[NSBundle mainBundle] pathForResource:#"article"
ofType:#"pdf"];
NSURL *docURL = [NSURL fileURLWithPath:path];
/*
* create the Quicklook controller.
*/
QLPreviewController *qlController = [[QLPreviewController alloc] init];
PreviewItem *item =
[[PreviewItem alloc] initPreviewURL:docURL
WithTitle:#"Article"];
self.pdfDatasource =
[[PDFDataSource alloc] initWithPreviewItem:item];
qlController.dataSource = self.pdfDatasource;
/*
* present the document.
*/
[self presentViewController:qlController
animated:YES completion:nil];
}
The line that was causing the problem is the line:
qlController.dataSource = self.pdfDataSource
Also, the iOS app I was trying to make is one that utilizes a QuickLook framework to display a document, if that helps anyone.
I got the code from a guide here.
Any help?
P.S. I can't switch to Swift yet for some reasons, so I'll just keep my app as Objective-C for now.
I'm using UIDocumentInteractionController to share photo on Instagram, I am able to open action sheet (I don't know what should I call) for it, but when I tap on Open in Instagram it just crash, and message will be this,
*** -[UIDocumentInteractionController _openDocumentWithApplication:]: message sent to deallocated instance 0x1743762c0
For a note, I'm using ARC, and also created strong property of UIDocumentInteractionController.
Added retain property to UIDocumentInteractionController,
#property (nonatomic, retain) UIDocumentInteractionController *docController;
This is the code for sharing,
- (UIDocumentInteractionController *)setupControllerWithURL:(NSURL*)fileURL usingDelegate:(id <UIDocumentInteractionControllerDelegate>) interactionDelegate
{
UIDocumentInteractionController *interactionController = [UIDocumentInteractionController interactionControllerWithURL:fileURL];
interactionController.delegate = interactionDelegate;
return interactionController;
}
- (void) instagramShare {
NSURL *instagramURL = [NSURL URLWithString:#"instagram://"];
if ([[UIApplication sharedApplication] canOpenURL:instagramURL])
{
NSString *filePath = [self saveAsIgoFile];
NSURL *igImageHookFile = [[NSURL alloc] initWithString:[[NSString alloc] initWithFormat:#"file://%#", filePath]];
CGRect rect = CGRectMake(0, 0, 0, 0);
self.docController = [self setupControllerWithURL:igImageHookFile usingDelegate:(id)_view];
self.docController.UTI = #"com.instagram.photo";
self.docController.annotation = [NSDictionary dictionaryWithObject:_titleToShare forKey:#"InstagramCaption"];
[self.docController presentOpenInMenuFromRect:rect inView:_view.parentViewController.view animated:YES];
}
else
{
if(_block) {
_block (_shareType, NO, #"Instagram not installed in this device!\nTo share photo/video please install Instagram application.");
}
}
}
I'm doing this in a class, named "ShareClass" which subclass of NSObject.
Note, I've checked some answers with the same issue, but they are for Non-ARC, also I tried setting property to strong or retain both. This doesn't seems to work.
Finally, I sort it out by made shared instance of my custom class, that will remain through app and will not deallocated any instance. Not sure bad or good, but works like a charm. ^_O
What is approach should be used while loading files from remote server on QLPreviewController?
When should we download files using my server API to load them on QLPreviewController.
I am adding QLPreviewController as subview to my current view.
I can use datasource method to make call to download file from server.
- (id<QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
But once file is downloaded i need to reload QLPreviewController, where this should be done
For images i would like to image gallery view so that swipe to view images downloaded from server.
Can anyone point me to any tutorial to load images from remote server URL
To show any file that supports QLPreviewController, the url should
be the fileURL.
(id<QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
It always returns fileURL - if you will use any other URL, it will crash. After downloading is over save the file in documents directory and then push to preview.
- (void)saveFileInDocDirectoryWithFileName:(NSString *)title{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docPath_ = [paths objectAtIndex:0];
NSString *filePath = [ docPath_ stringByAppendingPathComponent:title];
self.fileURL = [NSURL fileURLWithPath:filePath];
[self pushToPreViewWithURL:fileURL];
}
- (void)pushToPreViewWithURL:(NSURL *)filePathURL{
QLPreviewController *previewController = [[QLPreviewController alloc] init];
previewController.dataSource = self;
previewController.delegate = self;
// start previewing the document at the current section index
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self.navigationController pushViewController:previewController animated:YES];
}];
}
Then in delegate method, return fileURL:
- (id)previewController:(QLPreviewController *)previewController previewItemAtIndex:(NSInteger)idx {
return self.fileURL;
}
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"];
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".