How to check if UIDocumentInteractionController will fail to open document due to missing external application on iPad?
Asked Answered
G

5

19

I am using UIDocumentInteractionController for showing popover menu "Open In..." so that user can open a document in other application.

Method presentOpenInMenuFromBarButtonItem:animated: returns NO in case there is no application able to open given document (menu will not show). But it is too late for me to wait until getting so far. I would like to disable the button initiating that opening if it is not possible instead of raising expectations of an user and then say "sorry, it is not possible to open it".

Is it possible to query system to see if there is at least one application registered for particular document type? I have checked canPreviewItem: in QLPreviewController, but it seems it doesn't support the same document types which UIDocumentInteractionController can handle.

Greenery answered 10/2, 2011 at 13:58 Comment(0)
G
11

[EDIT] Not working for iOS 6.0 (see comment)

It seems that dismissMenuAnimated (with no animation at all) is the key:

-(BOOL)canOpenDocumentWithURL:(NSURL*)url inView:(UIView*)view {
    BOOL canOpen = NO;
    UIDocumentInteractionController* docController = [UIDocumentInteractionController 
                                                   interactionControllerWithURL:url];
    if (docController)
    {
        docController.delegate = self;
        canOpen = [docController presentOpenInMenuFromRect:CGRectZero
                                   inView:self.view animated:NO];                   
        [docController dismissMenuAnimated:NO];
    }
    return canOpen;
}

It will return YES if at least one application is able to open the file pointed by url. At least it's working in my case (KMZ files), testing with/without Dropbox app on iPhone iOS 4.3.
Actually, it seems to work even if url is not pointing to an actual file (i.e. @"test.kmz"), but I wouldn't rely on it for all file types.

Gownsman answered 11/5, 2011 at 13:42 Comment(5)
This was the solution I adopted previously, but a word of warning for iOS 6. It seems that presenting and dismissing the controller in this way causes some side effects to UITabBar - specifically, the 'UITabBarButton's (private API) that make up the tab bar are hidden but not unhidden. From a bit of digging it seems to be that the buttons are set to 0 alpha, then hidden in an animation completion block on calling the 'present' method. Unfortunately the animation completion block is executed after the 'dismiss' method is called so the buttons remain hidden.Tachometer
Any solution to this problem..?Jinja
I got the same issue as @Weaverfish, so what I did was to present in the window instead of the view. [docController presentOptionsMenuFromRect:window.bounds inView:window animated:NO];Pterodactyl
UIView *v = [[UIView alloc] init]; canOpen = [docController presentOpenInMenuFromRect:CGRectZero inView:v animated:NO];Dehnel
This looks like a neat trick. Unfortunately, if you have DropBox or OneDrive installed they claim to open anything. You can also now add anything to Notes.Bonnie
L
5

I came up with a less hacky way of doing things, but there is a limitation that you can only detect whether there's a compatible app after the user has selected to open in an app. This will enable you to provide the same user experience as the Dropbox app.

All you need to do is set up the UIDocumentInteractionControllerDelegate and create a boolean flag property that holds whether or not the menu was presented.

In the interface:

/**
 The document interaction controller used to present the 'Open with' dialogue.
 */
@property (nonatomic,strong) UIDocumentInteractionController *documentInteractionController;

/**
 Boolen that holds whether or not there are apps installed that can open the URL.
 */
@property (nonatomic) BOOL hasCompatibleApps;

In the implementation:

- (void)shareFileAtURL:(NSURL*)fileURL
{
    [self setDocumentInteractionController:[UIDocumentInteractionController interactionControllerWithURL:fileURL]];
    [[self documentInteractionController] setDelegate:self];

    [self setHasCompatibleApps:NO];

    [[self documentInteractionController] presentOpenInMenuFromRect:[self popoverRect] inView:[self popoverView] animated:YES];

    if (![self hasCompatibleApps])
    {
        // Show an error message to the user.
    }
}

#pragma mark - UIDocumentInteractionControllerDelegate methods

- (void)documentInteractionControllerWillPresentOpenInMenu:(UIDocumentInteractionController *)controller
{
    [self setHasCompatibleApps:YES];
}

I hope that helps some people.

Leonelleonelle answered 7/5, 2013 at 20:12 Comment(0)
T
3

This works for me:

   self.docController = [UIDocumentInteractionController interactionControllerWithURL:url];
   UIView *v = [[UIView alloc] init];
   BOOL isAnAppAvalaible = [self.docController presentOpenInMenuFromRect:CGRectZero inView:v animated:NO];
Tamasha answered 29/7, 2014 at 10:21 Comment(0)
K
1
NSURL *url = [NSURL URLWithString:@"path_to_the_file"];
UIDocumentInteractionController *controller =
    [UIDocumentInteractionController interactionControllerWithURL:url];
BOOL openResult = [controller presentPreviewAnimated:NO];

If you use presentPreviewAnimated: for showing files you can use openResult to detect if it was opened successfully.

Kwapong answered 4/5, 2015 at 11:58 Comment(1)
presentPreviewAnimated: always returns NO for me. I will stick with presentOpenInMenuFromRect:inView:animated: where it is presented in view moved off-screen.Greenery
D
-4

-[UIApplication canOpenURL:] should do the job.

Dropping answered 10/2, 2011 at 14:10 Comment(3)
It seems canOpenURL resolves only schemes of URL. In this case I have always file:// and I would like to check different document types (pdf, jpeg, ...)Greenery
In any case, doesn't canOpenURL: determine if your application can open the document, not if OTHER applications you have installed can do so?Dorcus
Uh, we know what files our program we're writing can open, right? Because it's us who are writing the app? canOpenURL: determines if there are OTHER apps which can open the scheme, see the comment in the official documentation linked above. On OS X this functionality is in NSWorkspace and it is separate from NSApplication. But somehow Apple decided to combine them on iOS. Strange.Dropping

© 2022 - 2024 — McMap. All rights reserved.