[英]How to access files in iCloud Drive from within my iOS app?
有没有办法从 iCloud Drive 中选择文件,类似于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
.请注意,您无需设置 iCloud 授权即可使用
UIDocumentPickerViewController
。 Apple provides sample code that demonstrates how to use this controller here Apple在此处提供了演示如何使用此控制器的示例代码
The document picker calls the delegate's documentPicker:didPickDocumentAtURL: method when the user selects a destination outside your app's sandbox.
当用户选择应用程序沙箱之外的目的地时,文档选择器会调用委托的 documentPicker:didPickDocumentAtURL: 方法。 The system saves a copy of your document to the specified destination.
系统将您的文档副本保存到指定的目的地。 The document picker provides the copy's URL to indicate success;
文档选择器提供副本的 URL 以指示成功; however, your app does not have access to the file referred to by this URL.
但是,您的应用程序无权访问此 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)
}
Swift 4.X斯威夫特 4.X
You need to enable iCloud
entitlements in XCode Capabilities.您需要在 XCode 功能中启用
iCloud
权利。 Also you have to turn on iCloud
in you app bundle in developer account of Apple.此外,您必须在 Apple 的开发者帐户中的应用程序包中打开
iCloud
。 Once you do this, you are able to present document picker controller by following way:完成此操作后,您可以通过以下方式呈现文档选择器控制器:
Use UIDocumentPickerDelegate
methods使用
UIDocumentPickerDelegate
方法
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)
}
This is working fine for me.这对我来说很好用。 Hope it helps you too.
希望对你也有帮助。
Happy coding :)快乐编码:)
This changed once again in iOS 14 !!这在iOS 14 中再次改变了!!
Working example for JSON: 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 5, iOS 13斯威夫特 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. Jhonattan 和 Ashu 的答案对于核心功能来说绝对是正确的,多文档选择、错误结果和不推荐使用的文档选择器 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 .下面的代码显示了一个常见用例的现代自始至终版本:选择一个外部 iCloud 文档以导入应用程序并对其进行处理。
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请注意,您必须将应用程序的功能设置为使用 iCloud 文档,并在应用程序的 .plist 中设置一个无处不在的容器...参见示例: 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)
}
}
}
iCloudUrl.startAccessingSecurityScopedResource() // is returning true for me at this point, iCloudUrl.startAccessingSecurityScopedResource() // 此时为我返回 true,
However the following code gave the error:但是下面的代码给出了错误:
try FileManager.default.createDirectory(atPath: iCloudUrl, withIntermediateDirectories: true, attributes: nil)试试 FileManager.default.createDirectory(atPath: iCloudUrl, withIntermediateDirectories: true, attributes: nil)
"You can't save the file “xyz” because the volume is read only." “您无法保存文件“xyz”,因为该卷是只读的。”
This actually works :这实际上有效:
try FileManager.default.createDirectory(at: iCloudUrl, withIntermediateDirectories: true, attributes: nil)尝试 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…这是有道理的,因为 URL 可能带有它的安全访问权限,但是这个小小的疏忽让我难住了半天……
For my swiftUI users: It's quite easy.对于我的 swiftUI 用户:这很容易。
struct HomeView: View {
@State private var showActionSheet = false
var body: some View {
ButtonComponentView(title: "Press", handler: {
showActionSheet = true
})
.fileImporter(isPresented: $showActionSheet, allowedContentTypes: [.data]) { (res) in
print("!!!\(res)")
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.