首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SwiftUI -使用文件选择器打开属于另一个IOS应用程序的文件,然后直接访问该文件

SwiftUI -使用文件选择器打开属于另一个IOS应用程序的文件,然后直接访问该文件
EN

Stack Overflow用户
提问于 2020-05-06 06:19:56
回答 2查看 8.2K关注 0票数 2

我正在为IPAD开发一个IOS应用程序,尽可能多地使用原生Swift (使用Xcode 11.4.1,Swift 5,针对IOS 13.X)。我不知道可可或目标C,我没有以前的IOS经验。我来自C/C++和Android/Java背景。这就是说,我和Swift玩得很开心,而且它让我有多快就能做好开发。我认为困难的事情原来是容易的,但在我看来应该很容易的一件事是,竖起了一堵我无法克服的墙。简单地说,我试图允许我的用户使用文件选择器从他们的iPad中选择一个文档,然后我的应用程序将其上传到网站服务器。

我这里的用例是一个基于web的私有协作平台--用户通常用Word在笔记本上编写文档,然后使用典型的HTTP场景将这些文档上传到web服务器。在过去,我的平台只限于网络;现在,我正在尝试编写一个IOS应用程序,为IPad用户提供更多的本地体验。

我设想的工作方式是:用户将在iPad上使用(例如) Microsoft编写文档,然后,在我的Swift应用程序中,用户将他们的Word文档上传到服务器。

我的问题似乎是访问权限。我对文档选择器使用了以下代码:

代码语言:javascript
复制
import SwiftUI
import MobileCoreServices

struct DocPicker: UIViewControllerRepresentable {

    var callback: (URL) -> ()
    private let onDismiss: () -> Void

    init(callback: @escaping (URL) -> (), onDismiss: @escaping () -> Void) {
        self.callback = callback
        self.onDismiss = onDismiss
    }

    func makeCoordinator() -> Coordinator { Coordinator(self) }

    func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: UIViewControllerRepresentableContext<DocPicker>) {
    }

    func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
        let controller = UIDocumentPickerViewController(documentTypes: [kUTTypeItem as String], in: UIDocumentPickerMode.import)
        controller.allowsMultipleSelection = false
        controller.delegate = context.coordinator
        return controller
    }

    class Coordinator: NSObject, UIDocumentPickerDelegate {
        var parent: DocPicker
        init(_ pickerController: DocPicker) {
            self.parent = pickerController
        }
        func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
            parent.callback(urls[0])
            parent.onDismiss()
        }
        func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
            parent.onDismiss()
        }
    }
}

我使用挂在VStack上的这个代码片段调用我的文档选择器:

代码语言:javascript
复制
.sheet(isPresented: $showFilePicker, onDismiss: {self.showFilePicker = false}) {
            DocPicker(callback: self.readyFile(_:), onDismiss: { self.showFilePicker = false })

而且,当回调运行时,我实际上会得到一个URL返回,在一个类似于UUID的长路径组件之后,它似乎指向所选的文件.或者至少URL的最后一个组件与我选择的文件的名称相匹配。

file:///private/var/mobile/Containers/Data/Application/4B63589A-7037-4105-99F1-427444B27F40/tmp/org.me.myapp-Inbox/Document.docx

所以-我的应用程序运行,我选择上传功能,选择打开。我导航到Microsoft文档目录,我找到我保存的文件,我选择它。一切都很好。

然而,当我到达我的上传功能时,我会遇到一个错误。我使用每个人似乎都使用的方法构建了多部分/表单数据发布,但是当我试图在这里输入文件的实际数据时:

代码语言:javascript
复制
do {
            data1 = try NSData.init(contentsOf: URL.init(fileURLWithPath: fileURL, isDirectory: true)) as Data
        }
        catch { print("Error \(error)") }

我在Xcode的调试窗口中得到了一个“没有找到的文件”错误:

file:///private/var/mobile/Containers/Data/Application/4B63589A-7037-4105-99F1-427444B27F40/tmp/org.me.myapp-Inbox/Document.docx Error Domain=NSCocoaErrorDomain Code=260“文件”“Document.docx”无法打开,因为没有这样的文件。UserInfo={NSFilePath=/file:/private/var/mobile/Containers/Data/Application/4B63589A-7037-4105-99F1-427444B27F40/tmp/org.me.myapp-Inbox/Document.docx,NSUnderlyingError=0x283039bf0 {Error Domain=NSPOSIXErrorDomain Code=2“无此类文件或目录”}}

我在其他几个问题中读到了一些评论--这些问题都是离题的,但无论如何我都注意到了--在这种情况下,要访问一个文件,必须“将其复制到应用程序Sandbox”。当选择器执行并且用户选择一个文件时,我在调试输出中注意到这一点:

未能将选中的URL file:///private/var/mobile/Containers/Data/Application/83576950-92C8-442C-83B5-8320C037112F/Documents/Document.docx的缩略图与“收件箱复制file:///private/var/mobile/Containers/Data/Application/4B63589A-7037-4105-99F1-427444B27F40/tmp/org.me.myapp-Inbox/Document.docx: Error Domain=QLThumbnailErrorDomain Code=102 "(null)”UserInfo={NSUnderlyingError=0x2830224c0 {Error Domain=GSLibraryErrorDomain Code=3“生成未找到的”UserInfo={NSDescription=Generation not }}“}关联

它谈到了一个“收件箱副本文件”,它是选择器发送给我的“复制”URL --但是文件本身似乎不存在。

现在,我应该注意到,我已经实现了一个类似于我的“上传文件”函数的“上传图像”函数,但上传图像函数使用的是ImagePicker。在这种情况下,我从选择器获得图像,我可以访问图像,它上传完美,没有问题。问题就在我上面发布的代码里.或者以我的理解,这可能是有限的。

苹果网站上的这一页谈到了要求用户选择目录,但是当我试图粘贴目录时,他们的代码片段似乎无法工作(这似乎是一个反复出现的主题),因此我无法进一步使用它。

堆栈溢出问题47902995采取了一种不同的方法,讨论安全密钥,但似乎依赖Cocoa,这个问题有一个代码片段,但我不知道如何将它绑定到现有的选择器中。

摘要:

在Android (对不起)中,我可以给我的应用程序一个“权限”,允许它查看设备内部存储的所有(打开)文件。我知道IOS的工作方式不同,但我不知道它是如何不同的。我对Xcode/IOS/Swift/Swift/Swift‘t还不太了解,也一直在盲目地工作。

因此,简单地说,我的问题是:请有人告诉我如何修改我的代码,这样用户就可以在本地设备存储上打开Microsoft-Office创建的文档,并读取它,这样我的应用程序就可以上传它,而不会违反任何规则或抛出任何错误?

提亚

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-05-12 01:40:23

因此,只是为了存档,原来我的文档Picker代码工作正常--就像我提供的一样。

问题是我处理反应的方式。

我最初的错误代码是:

代码语言:javascript
复制
do {
    data1 = try NSData.init(
        contentsOf: URL.init(fileURLWithPath: fileURL, isDirectory: true)
    ) as Data
}
catch {
    print("Error \(error)")
}

这就是问题所在。为了从文件中获取数据流,我所需要做的就是:

代码语言:javascript
复制
do {
    data1 = try Data(contentsOf: fileURL!)
}
catch {
    print("Error \(error)")
}

就这样了!当我这样做时,我能够读取文件的内容,并通过POST正确地将它们上传到我的服务器。

感谢所有读过我的问题的人,感谢普拉福拉的回答!

票数 2
EN

Stack Overflow用户

发布于 2020-05-06 07:44:03

在iOS中,如果没有特定的应用程序许可,就不能访问App之外的任何内容。

如果您想从用户本地文件、iCloud或Google驱动器(如果用户安装了它)或任何其他基于云的存储中选择文档,则需要使用MobileCoreServices。

以下是给出如何执行的步骤的答案:

https://stackoverflow.com/a/42370660/9838937

上面的答案是WRT UIKit,而不是SwiftUI。这将为你提供UIDocumentMenuViewController。现在,您需要使用以下方法包装此控制器,以使其与SwiftUI一起工作。

https://www.hackingwithswift.com/books/ios-swiftui/wrapping-a-uiviewcontroller-in-a-swiftui-view

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61628621

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档