2

The issue involves sharing a document with my app using the "Copy to ...".

The result of that action is a call to:

    //TODO: This is where we save to the documents folder I beleive.
    func application(_ app: UIApplication, open inputURL: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        // Ensure the URL is a file URL
        guard inputURL.isFileURL else { return false }
        print(#function)

        // Reveal / import the document at the URL
        guard let documentBrowserViewController = window?.rootViewController as? DocumentBrowserViewController else {
            print("DocumentBrowserViewController needs to be RootViewController")
            return false
        }


        documentBrowserViewController.revealDocument(at: inputURL, importIfNeeded: true) { (revealedDocumentURL, error) in

            //TODO: Handle error with alert
            if let error = error {
                print("Error: Failed to reveal the document at URL \(inputURL) with error: '\(error)'")
            } else {
                print("Success.")
            }


            // Present the Document View Controller for the revealed URL
            //documentBrowserViewController.presentDocument(at: revealedDocumentURL!)
        }

        return true
    }

The print statements show the block: documentBrowserViewController.revealDocument gets executed without error.

Per the Documentation:

If importIfNeeded is true, the document browser calls its delegate's documentBrowser(:didImportDocumentAt:toDestinationURL:) method (or its documentBrowser(:failedToImportDocumentAt:error:) method, if an error occurred) before calling the completion handler.

Neither of the 2 methods are getting called though.

NOTES:

  • I have set the documentBrowserViewController as it's own delegate.
  • I am not alone. Apple Forum.

Am I misunderstanding the API? My goal is to save the file to the users Documents when it is imported from an external app using ("copy to"). My plan was to do it in: documentBrowser(_:didImportDocumentAt:toDestinationURL:)

hidden-username
  • 2,610
  • 3
  • 14
  • 19

2 Answers2

1

Apple's documentation here indicates that files shared with an app from outside it are placed in the user's Documents/Inbox directory. I suspect, then, that the reason the UIDocumentBrowserViewControllerDelegate's didImport/failedToImport methods fail to get called after the revealDocument method is called is that the files shared from outside the app have already antecedently been imported (again, into the user's Documents/Inbox directory) by the time the revealDocument method executes.

Unfortunately, that "importing into Documents/Inbox" behavior is not mentioned in any of the places that developers are initially likely to look when they add functionality for importing urls into a document-based app using UIDocumentBrowserViewController. In particular, it is not mentioned in...

(1) The "Enabling Document Sharing" article (https://developer.apple.com/documentation/uikit/view_controllers/adding_a_document_browser_to_your_app/enabling_document_sharing)

(2) The documentation for either UIApplication's openURL:options:completionHandler: method or UIDocumentBrowserViewController's revealDocumentAtURL:importIfNeeded:completion: method.

It would be good for the documentation for (1) and (2) to be updated to reflect the Documents/Inbox directory storage of files from outside the app (specifically, mail attachments) shared with the app. (It would also be good to mention in the (1) and (2) documentation that if the files at the imported urls are to be edited, they need to be moved out of the Documents/Inbox directory first.)

chmohler
  • 41
  • 4
0

My guess is those UIDocumentBroserViewControllerDelegate api methods have to do with moving files around in the files app, not importing with the "Copy to..." method. I don't have time to confirm right now, so I will leave this open. The following code works though. Basically it just gives the user a dialog to select where to import the file.

/// Presents a Picker alowing the user to select a location to import to.
    func application(_ app: UIApplication, open inputURL: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        // Ensure the URL is a file URL
        guard inputURL.isFileURL else { return false }

        // Reveal / import the document at the URL
        guard let documentBrowserViewController = window?.rootViewController as? DocumentBrowserViewController else {
            return false
        }


        documentBrowserViewController.revealDocument(at: inputURL, importIfNeeded: true) { (revealedDocumentURL, error) in

            if let url = revealedDocumentURL {

                let inputPicker = UIDocumentPickerViewController(url: url, in: .moveToService)

                /// Present on our Top View Controller
                if let presented = documentBrowserViewController.presentedViewController {
                    ///presented might be presenting it's own. (if so, dismiss it)
                    if let alreadyPresenting = presented.presentedViewController {
                        alreadyPresenting.dismiss(animated: false)
                    }
                    presented.present(inputPicker, animated: true)
                } else {
                    documentBrowserViewController.present(inputPicker, animated: true)
                }
            }


            //TODO: Handle error with alert
            if let error = error {
                print("Error: Failed to reveal the document at URL \(inputURL) with error: '\(error)'")
            }

        }

        return true
    }
hidden-username
  • 2,610
  • 3
  • 14
  • 19