5

I have a PDF file saved in the document directory. The path to the file is stored in a NSString property 'self.URL'. Here is my code to present the activity items:

-(void)presentDocumentInteractionController{
    self.docController = [UIDocumentInteractionController interactionControllerWithURL:self.URL];
    self.docController.delegate = self;
    [_docController setUTI:@"com.adobe.pdf"];
    [_docController presentOptionsMenuFromBarButtonItem:self.activityBarButton animated:YES];
}

Before iOS 8 this code worked fine. The user was presented with a list of items such as print, copy and email to choose from. After upgrading to iOS 8 /XCode 6, I'm getting this runtime error (it doesnt crash the app):

Unknown activity items supplied: (
    "<UITextViewPrintFormatter: 0x7f908ba53ca0>"
)

How can I solve this problem?

amirfl
  • 1,634
  • 2
  • 18
  • 34
  • Log `self.URL`. What is it? – rmaddy Sep 23 '14 at 21:35
  • it is: file:///Users/me/Library/Developer/CoreSimulator/Devices/272C49D3-7D19-4F03-A171‌​-78A7EAE1B02D/data/Containers/Data/Application/F70A1223-EDE0-472E-B94D-0B33AE5370‌​AE/Documents/filename.PDF The file exists in that address. The same URL property is used to load the PDF into a webview and it works there, but not for the document interaction controller. – amirfl Sep 24 '14 at 02:40
  • 1
    use presentOpenInMenuFromBarButtonItem instead presentOptionsMenuFromBarButtonItem – Eugene P Sep 26 '14 at 15:59
  • @EugeneProkoshev didn't make a difference for me with the same problem as user1349768 – Will Oct 21 '14 at 19:34
  • how do you initiate your docController, is it in .h file? what properties do you use for that, maybe ARC is releasing everything when you leave the app to your pdf viewing app? I set it up in .h in interface UIDocumentInteractionController *docController; and @property (strong, nonatomic) then synthesize in .m file then use just docController no self., no _ works fine – Boris Gafurov Nov 06 '14 at 16:12

3 Answers3

5

I have the same problem and have switched to using UIActivityViewController. However this makes the apps capable of opening the PDF no longer show up, so maybe that's not what you want.

Minimal Solution:

If you want to do minimal work, you don't even need to read your PDF into NSData, use a NSURL as activity item and iOS seems to know what to do:

- (void)share:(id)sender
{
    UIActivityViewController *activity =
        [[UIActivityViewController alloc] initWithActivityItems:@[self.URL]
                                          applicationActivities:nil];
    if ([activity respondsToSelector:@selector(popoverPresentationController)]) {
        activity.popoverPresentationController.barButtonItem = <# BAR BUTTON ITEM #>;
    }
    [self presentViewController:activity animated:YES completion:NULL];
}

Original Answer:

Make your view controller adhere to the UIActivityItemSource protocol, then you can do:

- (void)share:(id)sender
{
    self.pdfData = [NSData dataWithContentsOfURL:self.URL];
    UIActivityViewController *activity = [[UIActivityViewController alloc] initWithActivityItems:@[self] applicationActivities:nil];
    if ([activity respondsToSelector:@selector(popoverPresentationController)]) {
        activity.popoverPresentationController.barButtonItem = <# BAR BUTTON ITEM #>;
    }
    [self presentViewController:activity animated:YES completion:NULL];
}

Adhering to the protocol if you have a PDF file is relatively simple. You can of course optimize and return smaller NSData and even a preview image, but minimally do this:

- (id)activityViewControllerPlaceholderItem:(UIActivityViewController *)activityViewController
{
    return _pdfData;
}

- (id)activityViewController:(UIActivityViewController *)activityViewController
    itemForActivityType:(NSString *)activityType
{
    return _pdfData;
}

- (NSString *)activityViewController:(UIActivityViewController *)activityViewController
    subjectForActivityType:(NSString *)activityType
{
    return self.title;
}

- (NSString *)activityViewController:(UIActivityViewController *)activityViewController
    dataTypeIdentifierForActivityType:(NSString *)activityType
{
    return @"com.adobe.pdf";
}
Pascal
  • 16,846
  • 4
  • 60
  • 69
0

This solved the problem for me:

ObjC:

dispatch_async(dispatch_get_main_queue(), ^() {
    [_docController presentOptionsMenuFromRect:button.bounds inView:button animated:YES];
});

Swift:

if let docController = UIDocumentInteractionController(URL: url) {
    dispatch_async(dispatch_get_main_queue()) {
         docController.presentPreviewAnimated(true)
    }
} else {
    // handle nil docController 
}

I don't use swift so this code might not work.

Pacha
  • 51
  • 1
  • 7
  • Please take a close look at http://meta.stackexchange.com/questions/104227/is-it-acceptable-to-add-a-duplicate-answer-to-several-questions. You seem to be answering the same thing to multiple questions which is not the appropriate thing to do. – Luís Cruz Oct 24 '14 at 10:20
  • I'm unsure that your solution works as is for every question, so you need to make sure that your solution solves the issue of each question. If this is the case the correct thing to do is vote to close as duplicate. – Luís Cruz Oct 24 '14 at 10:26
  • can you convert this to swift? `^()` can't use in swift – TomSawyer Nov 07 '14 at 17:40
  • @TomSawyer do you perhaps make use of presentOpenInMenuFromBarButtonItem ? i am not getting it to work correctly – alex Sep 11 '15 at 09:09
0

Use

- (BOOL)presentOpenInMenuFromBarButtonItem:(UIBarButtonItem *)item animated:(BOOL)animated;

Instead of

- (BOOL)presentOptionsMenuFromBarButtonItem:(UIBarButtonItem *)item animated:(BOOL)animated;
Soul Clinic
  • 1,189
  • 12
  • 18