Before your files can appear in the Files app, you must indicate that your app supports Open in Place and File Sharing Enabled. These options are configured using keys in your Info.plist file. The first key is UIFileSharingEnabled, which enables iTunes sharing of files in your Documents folder. The second key is LSSupportsOpeningDocumentsInPlace, which grants the local file provider access to files in your Documents folder. Add these keys to your Info.plist and set their values to YES.
import UIKit
class ViewController: UIViewController {
/// Creating UIDocumentInteractionController instance.
let documentInteractionController = UIDocumentInteractionController()
override func viewDidLoad() {
super.viewDidLoad()
/// Setting UIDocumentInteractionController delegate.
documentInteractionController.delegate = self
}
@IBAction func showOptionsTapped(_ sender: UIButton) {
/// Passing the remote URL of the file, to be stored and then opted with mutliple actions for the user to perform
storeAndShare(withURLString: "https://images5.alphacoders.com/581/581655.jpg")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
extension ViewController {
/// This function will set all the required properties, and then provide a preview for the document
func share(url: URL) {
documentInteractionController.url = url
documentInteractionController.uti = url.typeIdentifier ?? "public.data, public.content"
documentInteractionController.name = url.localizedName ?? url.lastPathComponent
documentInteractionController.presentPreview(animated: true)
}
/// This function will store your document to some temporary URL and then provide sharing, copying, printing, saving options to the user
func storeAndShare(withURLString: String) {
guard let url = URL(string: withURLString) else { return }
/// START YOUR ACTIVITY INDICATOR HERE
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else { return }
let tmpURL = FileManager.default.temporaryDirectory
.appendingPathComponent(response?.suggestedFilename ?? "fileName.png")
do {
try data.write(to: tmpURL)
} catch {
print(error)
}
DispatchQueue.main.async {
/// STOP YOUR ACTIVITY INDICATOR HERE
self.share(url: tmpURL)
}
}.resume()
}
}
extension ViewController: UIDocumentInteractionControllerDelegate {
/// If presenting atop a navigation stack, provide the navigation controller in order to animate in a manner consistent with the rest of the platform
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
guard let navVC = self.navigationController else {
return self
}
return navVC
}
}
extension URL {
var typeIdentifier: String? {
return (try? resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier
}
var localizedName: String? {
return (try? resourceValues(forKeys: [.localizedNameKey]))?.localizedName
}
}
Another noteworthy point is what you return in the delegate method documentInteractionControllerViewControllerForPreview . If you are presenting the UIDocumentInteractionController from a controller with a navigational hiearachy (which will generally be the case), you should return the navigationController of the current view controller in order to maintain your navigation hierarchy or you will lose the navigation stack when you switch back to your app after saving the document into iCloud or any other option selected from the action sheet; the root view controller will be shown.