1

We have an iOS application that manages documents via Core Data. The actual files reside in the app's shared container so that the app's file provider extension can also access them for Files.app support. We want to give the user the option to open these files in third-party apps so that they can edit them in-place instead of sending a copy to the other app.

We provide a UIActivityViewController for sharing files with other apps. We also provide a UIActivity that shows a UIDocumentInteractionController which seems to work better in some cases. We give the UIActivityViewController the document's file URL, the raw text content, and printable data.

This works but all third-party editors are shown as Copy to … instead of Open in …

We've also set the UIFileSharingEnabled and LSSupportsOpeningDocumentsInPlace properties to YES in the app's info.plist but they seem to be only relevant for open-in-place when sharing files residing in the app's Documents folder.

Now we've stumbled upon the NSItemProviderFileOptionOpenInPlace option for NSItemProvider. As we're already supporting a file provider extension and from Apple's documentation this seemed like a great place to accomplish just what we want.

Adding a "pure" NSItemProvider works, in a way, but shows fewer options than when also sharing the file URL and text in addition (which is expected). However, when we use -[NSItemProvider registerFileRepresentationForTypeIdentifier:fileOptions:visibility:loadHandler:] with the said option (or just zero, same result) and return the file URL in the loadHandler's completionHandler() nothing is shared anymore. E.g., Mail no longer attaches the file, Messages doesn't show the document for sending.

These are the relevant bits of the code:

NSMutableArray *items = [NSMutableArray array];
NSMutableArray <UIActivity *> *activities = [NSMutableArray array];

NSURL *fileURL = self.record.metadata.fileURL;
NSString *fileUTI = self.record.metadata.uti;
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithItem: fileURL typeIdentifier: fileUTI];
[itemProvider registerFileRepresentationForTypeIdentifier:fileUTI fileOptions:NSItemProviderFileOptionOpenInPlace visibility:YES loadHandler:^NSProgress * _Nullable(void (^ _Nonnull completionHandler)(NSURL * _Nullable, BOOL, NSError * _Nullable))
{
    if (fileURL)
        completionHandler(fileURL, YES, nil);
    else
        completionHandler(nil, YES, [NSError errorWithDomain:NSCocoaErrorDomain code:NSURLErrorFileDoesNotExist userInfo:nil]);
    return nil;
}];
[items addObject:itemProvider];

self.activityViewController = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:activities];
[UIAppDelegate.splitViewController presentViewController:self.activityViewController animated:YES completion:nil];

The using the Share menu the item provider's load handler is correctly called and the file's actual URL returned.

Is that not how NSItemProviderFileOptionOpenInPlace is intended to be used? Or are we using it simply wrong? Apple's description is extremely sparse and we couldn't find any information elsewhere on the internet except for the official documentation.

eboehnisch
  • 21
  • 1
  • 4
  • Please read this link https://stackoverflow.com/questions/3981199/adding-open-in-option-to-ios-app might be helpful – Gagan_iOS Oct 24 '19 at 14:15
  • Thank you, @Gagan_iOS. However, that already works fine. People can open their documents in our app. We want to show other apps from within ours and allow open-in-place. We don't make an editor, we make the storage. – eboehnisch Oct 24 '19 at 16:33
  • I've found out what my problem was: Not deep enough understanding of the relationship between the activity view controller and file providers. – eboehnisch May 05 '20 at 13:49

1 Answers1

1

I've found out what my problem was: Not deep enough understanding of the relationship between the activity view controller and file providers.

As all my files reside in the shared container and are published also through the file provider extension, what I need to share through the activity view controller is the exact same URL that is shared through the file provider extension. Technically then the app that opens the file accesses it through there file provider mechanism.

eboehnisch
  • 21
  • 1
  • 4
  • Were you able to access those files? Im trying to do something similar and cant figure out how to access those files from inside my app. Basically we want to allow users to send word docs out to word for editing without the terrible local copy save being needed. If we can actually send a doc using the UIActivityViewController with the url being to the shared location does that work, and do we have to use the File Provider extension in the parent app. – blandman1990 Aug 24 '21 at 21:24
  • Yes, using the correct file path in the shared container our app can always access its own files. And for sharing we're creating a temporary copy (not a symlink, that won't work it seems) and share that copy so we get a nicely named file URL. – eboehnisch Aug 30 '21 at 07:51