I'm developing a loan related app where user upload his documents like pay-slips, it-returns, etc. For that I should show the user all the documents he/she having in his/her iPhone. How to show a picker for documents?
UIDocumentPickerViewController is what you are looking for.
You init one with a list of document types you want to be able to pick, and a mode, which is usually .open to get access to a file in a cloud provider directly. You can also use .import which will copy the file to your container instead of giving you access to the file in the cloud provider's container directly, if the goal is just to upload it (you can remove the copy after uploading).
Once you have created your picker, you present it, and implement the delegate method didPickDocumentsAt to retrieve the list of files chosen by the user.
Check out the Particles sample code and this years WWDC session « Managing Documents in your iOS Apps »
just call openDocumentPicker method when you want to upload document in your application..
import MobileCoreServices
func openDocumentPicker() {
let importMenu = UIDocumentMenuViewController(documentTypes: [kUTTypePDF as String], in: .import)
importMenu.delegate = self
self.present(importMenu, animated: true, completion: nil)
}
create your viewcontroller extension
extension ViewController: UIDocumentMenuDelegate {
func documentMenu(_ documentMenu: UIDocumentMenuViewController, didPickDocumentPicker documentPicker: UIDocumentPickerViewController) {
documentPicker.delegate = self
present(documentPicker, animated: true, completion: nil)
}
func documentMenuWasCancelled(_ documentMenu: UIDocumentMenuViewController) {
print("we cancelled")
dismiss(animated: true, completion: nil)
}
}
extension ViewController: UIDocumentPickerDelegate {
internal func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
do {
let fileAttributes = try FileManager.default.attributesOfItem(atPath: url.path)
let fileSizeNumber = fileAttributes[FileAttributeKey.size] as! NSNumber
let fileSizea = fileSizeNumber.doubleValue
let fileSize = fileSizea/1000000.0
if fileSize > 5.0 {
appDelegate.displayAlert(Title: "", Message: "Selected File are too big,Please select file less than 5.0 mb")
} else {
let documentData = try Data(contentsOf: url, options: .dataReadingMapped)
}
} catch let error {
print(error.localizedDescription)
}
}
}
above this code only you can access pdf if you want to access anpther document than just use this code
/*
let pdf = String(kUTTypePDF)
let spreadsheet = String(kUTTypeSpreadsheet)
let movie = String(kUTTypeMovie)
let aviMovie = String(kUTTypeAVIMovie)
let docs = String(kUTTypeCompositeContent)
let img = String(kUTTypeImage)
let png = String(kUTTypePNG)
let jpeg = String(kUTTypeJPEG)
let txt = String(kUTTypeText)
let zip = String(kUTTypeZipArchive)
let msg1 = String(kUTTypeEmailMessage)
let msg2 = String(kUTTypeMessage)
let types = [pdf, spreadsheet, movie, aviMovie, img, png, jpeg, txt, docs, zip, msg1, msg2]
*/
iOS 11 or later
let importMenu = UIDocumentPickerViewController.init(documentTypes: ["public.item"], in: UIDocumentPickerMode.import)
self.present(importMenu, animated: true) {
}
Please Refer the following link for more description
https://www.techotopia.com/index.php/An_iOS_Document_Browser_Tutorial
iOS 10 or earlier
You can write the below function when your document picker opens. it will work for all the file types which you want to upload.
func openDocumentPicker() {
let importMenu = UIDocumentMenuViewController(documentTypes: ["public.item"], in: .import)
importMenu.delegate = self
importMenu.modalPresentationStyle = .formSheet
self.present(importMenu, animated: true, completion: nil)
}
I want to pick a file of any type(.pdf, .docs, .xlsx, .jpeg, .txt, .rtf, etc) functionality in my iOS app. On clicking on Upload button, I want my app to open a directory and select files(DocumentsPicker)
#IBAction pickDocument(sender: UIButton) {
//Open Document Picker
}
Any approach to do so in Swift?
Update for iOS 14: You do not need any capabilities. Just create a UIDocumentPickerViewController with the appropriate types, implement the delegate, and you are done.
More info in this answer. Code from there:
import UIKit
import MobileCoreServices
import UniformTypeIdentifiers
func selectFiles() {
let types = UTType.types(tag: "json",
tagClass: UTTagClass.filenameExtension,
conformingTo: nil)
let documentPickerController = UIDocumentPickerViewController(
forOpeningContentTypes: types)
documentPickerController.delegate = self
self.present(documentPickerController, animated: true, completion: nil)
}
From your project's capabilities, enable both the iCloud and the Key-Sharing.
Import MobileCoreServices in your class and then extend the following three classes inside your UIViewController:
UIDocumentMenuDelegate,UIDocumentPickerDelegate,UINavigationControllerDelegate
Implement the following functions:
public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard let myURL = urls.first else {
return
}
print("import result : \(myURL)")
}
public func documentMenu(_ documentMenu:UIDocumentMenuViewController, didPickDocumentPicker documentPicker: UIDocumentPickerViewController) {
documentPicker.delegate = self
present(documentPicker, animated: true, completion: nil)
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
print("view was cancelled")
dismiss(animated: true, completion: nil)
}
How do you call all of this? Add the following bit of code to your click function:
func clickFunction(){
let importMenu = UIDocumentMenuViewController(documentTypes: [String(kUTTypePDF)], in: .import)
importMenu.delegate = self
importMenu.modalPresentationStyle = .formSheet
self.present(importMenu, animated: true, completion: nil)
}
Click your button. The following menu will pop up ..
In the case of Dropbox. Upon clicking on any item. You will be redirected back to your app and the URL will be logged in your terminal.
Manipulate the documentTypes to your need. In my app, Users permitted to Pdf only. So, suit yourself.
kUTTypePDF
kUTTypePNG
kUTTypeJPEG
...
Also if you feel like customizing your own menu bar. Add the following code and customize your own function inside the handler
importMenu.addOption(withTitle: "Create New Document", image: nil, order: .first, handler: { print("New Doc Requested") })
Enjoy it.
You can use UIDocumentPickerViewController to get the files from the Files apps or iCloud Drive.
Activate the Key-value storage and iCloud Documents from iCloud capability:
Import the following framework on the view controller you want to open the document picker:
import MobileCoreServices
// For iOS 14+
import UniformTypeIdentifiers
Implement the following method from UIDocumentPickerDelegate:
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
// you get from the urls parameter the urls from the files selected
}
Create an UIDocumentPickerViewController to display the File picker or iCloud Drive:
// Use this code if your are developing prior iOS 14
let types: [String] = [kUTTypePDF as String]
let documentPicker = UIDocumentPickerViewController(documentTypes: types, in: .import)
documentPicker.delegate = self
documentPicker.modalPresentationStyle = .formSheet
self.present(documentPicker, animated: true, completion: nil)
// For iOS 14+
let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [UTType.item], asCopy: false)
documentPicker.delegate = self
documentPicker.modalPresentationStyle = .formSheet
self.present(documentPicker, animated: true, completion: nil)
If you want the user can import more types of files to your app, you have to add more UTTypes to the types NSArray. To see all the types available, you can check the UTType Docs
When the document picker opens on iOS 11 and you try to select a file inside the Google Drive, it is possible the file is disable due a bug: http://www.openradar.me/24187873
The UIDocumentMenuViewController is deprecated since iOS11. I also found it buggy when presented from a modal view controller.
Here's a direct way of using the picker:
import MobileCoreServices
private func attachDocument() {
let types = [kUTTypePDF, kUTTypeText, kUTTypeRTF, kUTTypeSpreadsheet]
let importMenu = UIDocumentPickerViewController(documentTypes: types as [String], in: .import)
if #available(iOS 11.0, *) {
importMenu.allowsMultipleSelection = true
}
importMenu.delegate = self
importMenu.modalPresentationStyle = .formSheet
present(importMenu, animated: true)
}
extension AViewController: UIDocumentPickerDelegate, UINavigationControllerDelegate {
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
viewModel.attachDocuments(at: urls)
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
controller.dismiss(animated: true, completion: nil)
}
}
As usual don't forget to add iCloud support:
UIDocumentPickerViewController(documentTypes: [String], in: UIDocumentPickerMode) was deprecated in iOS 14.0
It is now UIDocumentPickerViewController(forOpeningContentTypes: [UTType])
ContentTypes being and array any or the combination of the following:
UTType.image, UTType.text, UTType.plainText, UTType.utf8PlainText, UTType.utf16ExternalPlainText, UTType.utf16PlainText, UTType.delimitedText, UTType.commaSeparatedText, UTType.tabSeparatedText, UTType.utf8TabSeparatedText, UTType.rtf, UTType.pdf, UTType.webArchive, UTType.image, UTType.jpeg, UTType.tiff, UTType.gif, UTType.png, UTType.bmp, UTType.ico, UTType.rawImage, UTType.svg, UTType.livePhoto, UTType.movie, UTType.video, UTType.audio, UTType.quickTimeMovie, UTType.mpeg, UTType.mpeg2Video, UTType.mpeg2TransportStream, UTType.mp3, UTType.mpeg4Movie, UTType.mpeg4Audio, UTType.avi, UTType.aiff, UTType.wav, UTType.midi, UTType.archive, UTType.gzip, UTType.bz2, UTType.zip, UTType.appleArchive, UTType.spreadsheet, UTType.epub
This is how it works for me:
let supportedTypes = [myArrayFromAnyOfTheAbove]
func openDocument() {
let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: supportedTypes, asCopy: true)
documentPicker.delegate = self
documentPicker.allowsMultipleSelection = false
documentPicker.shouldShowFileExtensions = true
present(documentPicker, animated: true, completion: nil)
}
let docsTypes = ["public.text",
"com.apple.iwork.pages.pages",
"public.data",
"kUTTypeItem",
"kUTTypeContent",
"kUTTypeCompositeContent",
"kUTTypeData",
"public.database",
"public.calendar-event",
"public.message",
"public.presentation",
"public.contact",
"public.archive",
"public.disk-image",
"public.plain-text",
"public.utf8-plain-text",
"public.utf16-external-plain-text",
"public.utf16-plain-text",
"com.apple.traditional-mac-plain-text",
"public.rtf",
"com.apple.ink.inktext",
"public.html",
"public.xml",
"public.source-code",
"public.c-source",
"public.objective-c-source",
"public.c-plus-plus-source",
"public.objective-c-plus-plus-source",
"public.c-header",
"public.c-plus-plus-header",
"com.sun.java-source",
"public.script",
"public.assembly-source",
"com.apple.rez-source",
"public.mig-source",
"com.apple.symbol-export",
"com.netscape.javascript-source",
"public.shell-script",
"public.csh-script",
"public.perl-script",
"public.python-script",
"public.ruby-script",
"public.php-script",
"com.sun.java-web-start",
"com.apple.applescript.text",
"com.apple.applescript.script",
"public.object-code",
"com.apple.mach-o-binary",
"com.apple.pef-binary",
"com.microsoft.windows-executable",
"com.microsoft.windows-dynamic-link-library",
"com.sun.java-class",
"com.sun.java-archive",
"com.apple.quartz-composer-composition",
"org.gnu.gnu-tar-archive",
"public.tar-archive",
"org.gnu.gnu-zip-archive",
"org.gnu.gnu-zip-tar-archive",
"com.apple.binhex-archive",
"com.apple.macbinary-archive",
"public.url",
"public.file-url",
"public.url-name",
"public.vcard",
"public.image",
"public.fax",
"public.jpeg",
"public.jpeg-2000",
"public.tiff",
"public.camera-raw-image",
"com.apple.pict",
"com.apple.macpaint-image",
"public.png",
"public.xbitmap-image",
"com.apple.quicktime-image",
"com.apple.icns",
"com.apple.txn.text-multimedia-data",
"public.audiovisual-content",
"public.movie",
"public.video",
"com.apple.quicktime-movie",
"public.avi",
"public.mpeg",
"public.mpeg-4",
"public.3gpp",
"public.3gpp2",
"public.audio",
"public.mp3",
"public.mpeg-4-audio",
"com.apple.protected-mpeg-4-audio",
"public.ulaw-audio",
"public.aifc-audio",
"public.aiff-audio",
"com.apple.coreaudio-format",
"public.directory",
"public.folder",
"public.volume",
"com.apple.package",
"com.apple.bundle",
"public.executable",
"com.apple.application",
"com.apple.application-bundle",
"com.apple.application-file",
"com.apple.deprecated-application-file",
"com.apple.plugin",
"com.apple.metadata-importer",
"com.apple.dashboard-widget",
"public.cpio-archive",
"com.pkware.zip-archive",
"com.apple.webarchive",
"com.apple.framework",
"com.apple.rtfd",
"com.apple.flat-rtfd",
"com.apple.resolvable",
"public.symlink",
"com.apple.mount-point",
"com.apple.alias-record",
"com.apple.alias-file",
"public.font",
"public.truetype-font",
"com.adobe.postscript-font",
"com.apple.truetype-datafork-suitcase-font",
"public.opentype-font",
"public.truetype-ttf-font",
"public.truetype-collection-font",
"com.apple.font-suitcase",
"com.adobe.postscript-lwfn-font",
"com.adobe.postscript-pfb-font",
"com.adobe.postscript.pfa-font",
"com.apple.colorsync-profile",
"public.filename-extension",
"public.mime-type",
"com.apple.ostype",
"com.apple.nspboard-type",
"com.adobe.pdf",
"com.adobe.postscript",
"com.adobe.encapsulated-postscript",
"com.adobe.photoshop-image",
"com.adobe.illustrator.ai-image",
"com.compuserve.gif",
"com.microsoft.bmp",
"com.microsoft.ico",
"com.microsoft.word.doc",
"com.microsoft.excel.xls",
"com.microsoft.powerpoint.ppt",
"com.microsoft.waveform-audio",
"com.microsoft.advanced-systems-format",
"com.microsoft.windows-media-wm",
"com.microsoft.windows-media-wmv",
"com.microsoft.windows-media-wmp",
"com.microsoft.windows-media-wma",
"com.microsoft.advanced-stream-redirector",
"com.microsoft.windows-media-wmx",
"com.microsoft.windows-media-wvx",
"com.microsoft.windows-media-wax",
"com.apple.keynote.key",
"com.apple.keynote.kth",
"com.truevision.tga-image",
"com.sgi.sgi-image",
"com.ilm.openexr-image",
"com.kodak.flashpix.image",
"com.j2.jfx-fax",
"com.js.efx-fax",
"com.digidesign.sd2-audio",
"com.real.realmedia",
"com.real.realaudio",
"com.real.smil",
"com.allume.stuffit-archive",
"org.openxmlformats.wordprocessingml.document",
"com.microsoft.powerpoint.ppt",
"org.openxmlformats.presentationml.presentation",
"com.microsoft.excel.xls",
"org.openxmlformats.spreadsheetml.sheet",
]
let documentPicker = UIDocumentPickerViewController(documentTypes: Utils.docsTypes, in: .import)
documentPicker.delegate = self
documentPicker.allowsMultipleSelection = true
present(documentPicker, animated: true, completion: nil)
this will help you to implement download/upload functionality
UIDocumentMenuViewController *importMenu = [[UIDocumentMenuViewController alloc] initWithDocumentTypes:#[#"public.item"] inMode:UIDocumentPickerModeImport | UIDocumentPickerModeExportToService];
For more read Apple Documentation
iCloud access all type of files #
func openiCloudDocuments(){
let importMenu = UIDocumentPickerViewController(documentTypes: [String("public.data")], in: .import)
importMenu.delegate = self
importMenu.modalPresentationStyle = .formSheet
self.present(importMenu, animated: true, completion: nil)
}
Something I struggled with was how to specify some specific formats for the PickerView, such as .pptx & .xlsx files. Here's some code to create a PickerView with some commonly required types...
let types: [String] = [
kUTTypeJPEG as String,
kUTTypePNG as String,
"com.microsoft.word.doc",
"org.openxmlformats.wordprocessingml.document",
kUTTypeRTF as String,
"com.microsoft.powerpoint.ppt",
"org.openxmlformats.presentationml.presentation",
kUTTypePlainText as String,
"com.microsoft.excel.xls",
"org.openxmlformats.spreadsheetml.sheet",
kUTTypePDF as String,
kUTTypeMP3 as String
]
let documentPicker = UIDocumentPickerViewController(documentTypes: types, in: .import)
documentPicker.delegate = self
documentPicker.modalPresentationStyle = .formSheet
self.present(documentPicker, animated: true, completion: nil)
There are two places that I found useful in putting together this list:
https://developer.apple.com/library/archive/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html
https://escapetech.eu/manuals/qdrop/uti.html
Hope that helps somebody!
Here's a SwiftUI version of UIDocumentPickerViewController.
Credit goes to this blog post: https://capps.tech/blog/read-files-with-documentpicker-in-swiftui
I'm just posting the code here in case the blog post disappears so it's preserved.
(I adjusted the code slightly to copy the selected certificate file and write the Data to the Library folder; in the blog, it copies the contents of a text file.)
import SwiftUI
struct ContentView: View {
#State var fileContent:Data = Data()
#State var showDocumentPicker = false
var body: some View {
Button() {
showDocumentPicker = true
} label: {
Text("click me to show file browser")
}
.sheet(isPresented: self.$showDocumentPicker) {
DocumentPicker(fileContent: $fileContent)
}
}
}
struct DocumentPicker: UIViewControllerRepresentable {
#Binding var fileContent: Data
func makeCoordinator() -> DocumentPickerCoordinator {
return DocumentPickerCoordinator(fileContent: $fileContent)
}
func makeUIViewController(context:
UIViewControllerRepresentableContext<DocumentPicker>) ->
UIDocumentPickerViewController {
//The file types like ".pkcs12" are listed here:
//https://developer.apple.com/documentation/uniformtypeidentifiers/system_declared_uniform_type_identifiers?changes=latest_minor
let controller: UIDocumentPickerViewController = UIDocumentPickerViewController(forOpeningContentTypes: [.pkcs12], asCopy: true)
controller.delegate = context.coordinator
return controller
}
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: UIViewControllerRepresentableContext<DocumentPicker>) {
print("update")
}
} //struct
class DocumentPickerCoordinator: NSObject, UIDocumentPickerDelegate, UINavigationControllerDelegate {
#Binding var fileContent: Data
init(fileContent: Binding<Data>) {
_fileContent = fileContent
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
let fileURL = urls[0]
let certData = try! Data(contentsOf: fileURL)
if let documentsPathURL = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first {
let certURL = documentsPathURL.appendingPathComponent("certFile.pfx")
try? certData.write(to: certURL)
}
}
}
You could implement what you describe using NSURLSession.
You will have to limit the target directory you show to your app's documents directory. Apps do not have full access to the file system.
Is there a way to choose file from iCloud Drive similar way to UIImagePickerController()?
You can present controller the following way:
import MobileCoreServices
let documentPickerController = UIDocumentPickerViewController(documentTypes: [String(kUTTypePDF), String(kUTTypeImage), String(kUTTypeMovie), String(kUTTypeVideo), String(kUTTypePlainText), String(kUTTypeMP3)], inMode: .Import)
documentPickerController.delegate = self
presentViewController(documentPickerController, animated: true, completion: nil)
In your delegate implement the method:
func documentPicker(controller: UIDocumentPickerViewController, didPickDocumentAtURL url: NSURL)
Note that you don't need to set up iCloud Entitlement to use UIDocumentPickerViewController. Apple provides sample code that demonstrates how to use this controller here
Swift 5, iOS 13
Jhonattan's and Ashu's answers are definitely on the right track for the core functionality, there are a number of issues with multiple-document-selection, error outcomes and deprecated document picker API.
The code below shows a modern start-to-finish version of a common use case: pick an external iCloud document to import into app and do something with it.
Note that you have to have your app's Capabilities set up to use iCloud documents and have a ubiquity container set up in your app's .plist... See for example:
Swift write/save/move a document file to iCloud drive
class ViewController: UIViewController {
#IBAction func askForDocument(_ sender: Any) {
if FileManager.default.url(forUbiquityContainerIdentifier: nil) != nil {
let iOSPickerUI = UIDocumentPickerViewController(documentTypes: ["public.text"], in: .import)
iOSPickerUI.delegate = self
iOSPickerUI.modalPresentationStyle = .formSheet
if let popoverPresentationController = iOSPickerUI.popoverPresentationController {
popoverPresentationController.sourceView = sender as? UIView
}
self.present(iOSPickerUI, animated: true, completion: nil)
}
}
func processImportedFileAt(fileURL: URL) {
// ...
}
}
extension ViewController: UIDocumentPickerDelegate, UINavigationControllerDelegate {
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
dismiss(animated: true, completion: nil)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
if controller.allowsMultipleSelection {
print("WARNING: controller allows multiple file selection, but coordinate-read code here assumes only one file chosen")
// If this is intentional, you need to modify the code below to do coordinator.coordinate
// on MULTIPLE items, not just the first one
if urls.count > 0 { print("Ignoring all but the first chosen file") }
}
let firstFileURL = urls[0]
let isSecuredURL = (firstFileURL.startAccessingSecurityScopedResource() == true)
print("UIDocumentPickerViewController gave url = \(firstFileURL)")
// Status monitoring for the coordinate block's outcome
var blockSuccess = false
var outputFileURL: URL? = nil
// Execute (synchronously, inline) a block of code that will copy the chosen file
// using iOS-coordinated read to cooperate on access to a file we do not own:
let coordinator = NSFileCoordinator()
var error: NSError? = nil
coordinator.coordinate(readingItemAt: firstFileURL, options: [], error: &error) { (externalFileURL) -> Void in
// WARNING: use 'externalFileURL in this block, NOT 'firstFileURL' even though they are usually the same.
// They can be different depending on coordinator .options [] specified!
// Create file URL to temp copy of file we will create:
var tempURL = URL(fileURLWithPath: NSTemporaryDirectory())
tempURL.appendPathComponent(externalFileURL.lastPathComponent)
print("Will attempt to copy file to tempURL = \(tempURL)")
// Attempt copy
do {
// If file with same name exists remove it (replace file with new one)
if FileManager.default.fileExists(atPath: tempURL.path) {
print("Deleting existing file at: \(tempURL.path) ")
try FileManager.default.removeItem(atPath: tempURL.path)
}
// Move file from app_id-Inbox to tmp/filename
print("Attempting move file to: \(tempURL.path) ")
try FileManager.default.moveItem(atPath: externalFileURL.path, toPath: tempURL.path)
blockSuccess = true
outputFileURL = tempURL
}
catch {
print("File operation error: " + error.localizedDescription)
blockSuccess = false
}
}
navigationController?.dismiss(animated: true, completion: nil)
if error != nil {
print("NSFileCoordinator() generated error while preparing, and block was never executed")
return
}
if !blockSuccess {
print("Block executed but an error was encountered while performing file operations")
return
}
print("Output URL : \(String(describing: outputFileURL))")
if (isSecuredURL) {
firstFileURL.stopAccessingSecurityScopedResource()
}
if let out = outputFileURL {
processImportedFileAt(fileURL: out)
}
}
}
The document picker calls the delegate’s documentPicker:didPickDocumentAtURL: method when the user selects a destination outside your app’s sandbox. The system saves a copy of your document to the specified destination. The document picker provides the copy’s URL to indicate success; however, your app does not have access to the file referred to by this URL. Link
This code work for me:
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
let url = urls[0]
let isSecuredURL = url.startAccessingSecurityScopedResource() == true
let coordinator = NSFileCoordinator()
var error: NSError? = nil
coordinator.coordinate(readingItemAt: url, options: [], error: &error) { (url) -> Void in
_ = urls.compactMap { (url: URL) -> URL? in
// Create file URL to temporary folder
var tempURL = URL(fileURLWithPath: NSTemporaryDirectory())
// Apend filename (name+extension) to URL
tempURL.appendPathComponent(url.lastPathComponent)
do {
// If file with same name exists remove it (replace file with new one)
if FileManager.default.fileExists(atPath: tempURL.path) {
try FileManager.default.removeItem(atPath: tempURL.path)
}
// Move file from app_id-Inbox to tmp/filename
try FileManager.default.moveItem(atPath: url.path, toPath: tempURL.path)
YourFunction(tempURL)
return tempURL
} catch {
print(error.localizedDescription)
return nil
}
}
}
if (isSecuredURL) {
url.stopAccessingSecurityScopedResource()
}
navigationController?.dismiss(animated: true, completion: nil)
}
This changed once again in iOS 14!!
Working example for JSON:
import UIKit
import MobileCoreServices
import UniformTypeIdentifiers
func selectFiles() {
let types = UTType.types(tag: "json",
tagClass: UTTagClass.filenameExtension,
conformingTo: nil)
let documentPickerController = UIDocumentPickerViewController(
forOpeningContentTypes: types)
documentPickerController.delegate = self
self.present(documentPickerController, animated: true, completion: nil)
}
Swift 4.X
You need to enable iCloud entitlements in XCode Capabilities. Also you have to turn on iCloud in you app bundle in developer account of Apple. Once you do this, you are able to present document picker controller by following way:
Use UIDocumentPickerDelegate methods
extension YourViewController : UIDocumentMenuDelegate, UIDocumentPickerDelegate,UINavigationControllerDelegate {
func documentMenu(_ documentMenu: UIDocumentMenuViewController, didPickDocumentPicker documentPicker: UIDocumentPickerViewController) {
documentPicker.delegate = self
self.present(documentPicker, animated: true, completion: nil)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
print("url = \(url)")
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
dismiss(animated: true, completion: nil)
}
}
Add below code for Button Action
#IBAction func didPressAttachment(_ sender: UIButton) {
let importMenu = UIDocumentMenuViewController(documentTypes: [String(kUTTypePDF)], in: .import)
importMenu.delegate = self
importMenu.modalPresentationStyle = .formSheet
if let popoverPresentationController = importMenu.popoverPresentationController {
popoverPresentationController.sourceView = sender
// popoverPresentationController.sourceRect = sender.bounds
}
self.present(importMenu, animated: true, completion: nil)
}
iCloudUrl.startAccessingSecurityScopedResource()
// is returning true for me at this point,
However the following code gave the error:
try FileManager.default.createDirectory(atPath: iCloudUrl, withIntermediateDirectories: true, attributes: nil)
"You can’t save the file “xyz” because the volume is read only."
This actually works :
try FileManager.default.createDirectory(at: iCloudUrl, withIntermediateDirectories: true, attributes: nil)
Which makes sense because the URL probably is carrying around it’s security access, but this little oversight stumped me for half a day…
For my swiftUI users: It's quite easy.
struct HomeView: View {
#State private var showActionSheet = false
var body: some View {
Button("Press") {
showActionSheet = true
}
.fileImporter(isPresented: $showActionSheet, allowedContentTypes: [.data]) { (res) in
print("!!!\(res)")
}
}
}
I use
try FileManager.default.copyItem(at: url, to: destinationUrl)
instead of moveItem. Otherwise, the files are removed from iCloud Drive, which is not what I want.