I have this code in a UIViewController
that confirms to UIDocumentPickerDelegate
:
- (void)openTextFilePicker {
NSArray *UTIs = [NSArray arrayWithObjects:@"public.text", nil];
[self openFilePicker:UTIs];
}
- (void)openFilePicker:(NSArray *)UTIs {
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:UTIs inMode:UIDocumentPickerModeImport];
documentPicker.delegate = self;
documentPicker.popoverPresentationController.barButtonItem = self.importButton;
[self presentViewController:documentPicker animated:TRUE completion:nil];
}
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURLs:(NSArray<NSURL *> *)urls {
[self documentPicker:controller didPickDocumentAtURL:[urls firstObject]];
}
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url {
NSLog(@"picked document %@", url);
}
- (void)documentPickerWasCancelled:(UIDocumentPickerViewController *)controller {
NSLog(@"cancelled");
}
This allows users to select a file anywhere on their system and import its contents into the app. It works if I have the App Sandbox > User Selected File capability set to Read/Write. But I'm only reading data in from the file, I don't need to update the file or save anything outside of the sandbox. So I changed the capability to Read Only, but then I get this error in the console, and didPickDocumentsAtURLs
isn't called:
Failed to create an FPSandboxingURLWrapper for [path]. Error: Error Domain=NSPOSIXErrorDomain Code=1 "couldn't issue sandbox extension com.apple.app-sandbox.read-write for '[path]': Operation not permitted"
Does that seem right, or should I be able to read files with just the Read Only entitlement? It's easy enough to switch it to Read/Write if needed, but my first submission was rejected for using unnecessary entitlements, and I want to be prepared to justify this to the review team if it is in fact needed.
For anyone searching for this, I did not get granted app approval by stating my case - instead I was forced to find the following solution - which uses a UIDocumentBrowserViewController (Read only!) vs a UIDocumentPickerViewController (which requires read-write)
import Foundation
import UIKit
extension ViewController: UIDocumentBrowserViewControllerDelegate, UIDocumentPickerDelegate {
@objc func presentDocumentPicker() {
if operatingSystem == .macintosh {
let documentPicker = UIDocumentBrowserViewController(forOpening: [.pdf])
documentPicker.delegate = self
documentPicker.allowsDocumentCreation = false
documentPicker.allowsPickingMultipleItems = false
// Present the document picker.
present(documentPicker, animated: true, completion: nil)
} else {
let documentsPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.pdf])
documentsPicker.delegate = self
documentsPicker.allowsMultipleSelection = false
documentsPicker.modalPresentationStyle = .fullScreen
self.present(documentsPicker, animated: true, completion: nil)
}
}
func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentsAt documentURLs: [URL]) {
guard let url = documentURLs.first, url.startAccessingSecurityScopedResource() else { return }
defer {
DispatchQueue.main.async {
url.stopAccessingSecurityScopedResource()
}
}
debugPrint("[DocumentPicker] Selected Item with URL : ", url)
controller.dismiss(animated: true)
}
public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard let url = urls.first, url.startAccessingSecurityScopedResource() else { return }
defer {
DispatchQueue.main.async {
url.stopAccessingSecurityScopedResource()
}
}
debugPrint("[DocumentPicker] Selected Item with URL : ", url)
controller.dismiss(animated: true)
}
public func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
controller.dismiss(animated: true)
}
}
I went ahead and changed the entitlement to Read/Write, and submitted it with a note in the App Sandbox Information field explaining how the file access is used. The app was approved.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With