How to access files in iCloud Drive from within my iOS app?

后端 未结 5 525
[愿得一人]
[愿得一人] 2020-12-03 02:06

Is there a way to choose file from iCloud Drive similar way to UIImagePickerController()?

5条回答
  •  执笔经年
    2020-12-03 02:38

    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)
            }
        }
    
    }
    

提交回复
热议问题