Я разрабатываю приложение IOS для IPAD на максимально возможном родном языке Swift (с использованием Xcode 11.4.1, Swift 5, таргетинг на IOS 13.X). Я не знаю Cocoa или Objective- C, и у меня нет предыдущего опыта IOS. Я исхожу из C / C ++ и Android / Java фона. Тем не менее, мне очень нравится Swift и то, насколько быстро он позволяет мне заниматься разработкой. Вещи, которые я ожидал быть трудными, оказались легкими, но одна вещь, которая мне кажется, что это должно быть легко, - это стена, которую я не могу преодолеть. Короче говоря, я пытаюсь разрешить своим пользователям использовать средство выбора файлов для выбора документа со своего iPad, который мое приложение затем загрузит на сервер веб-сайта.
Мой пример использования - это частный веб-сайт. платформа для совместной работы - пользователи пишут документы на своих ноутбуках, обычно с помощью Word, а затем загружают эти документы на веб-сервер, используя типичный сценарий HTTP POST. Раньше моя платформа была только для Интернета; Теперь я пытаюсь написать приложение IOS, чтобы обеспечить более естественный опыт для пользователей IPad.
Я представляю себе эту работу так: пользователи будут писать документы, используя (например) Microsoft Word на iPad, а затем из моего приложения Swift IOS пользователь загрузит свои документы Word на сервер.
Моя проблема связана с правами доступа. Я использую следующий код для средства выбора документов:
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:
.sheet(isPresented: $showFilePicker, onDismiss: {self.showFilePicker = false}) {
DocPicker(callback: self.readyFile(_:), onDismiss: { self.showFilePicker = false })
И, когда выполняется обратный вызов, Я действительно получаю обратно URL-адрес, который, кажется, после длинного компонента пути, подобного UUID, указывает на выбранный файл ... или, по крайней мере, последний компонент URL-адреса совпадает с именем выбранного мной файла.
файл: ///private/var/mobile/Containers/Data/Application/4B63589A-7037-4105-99F1-427444B27F40/tmp/org.me.myapp-Inbox/Document.docx
Итак - мое приложение запускается, я выбираю функцию загрузки, открывается сборщик. Я перехожу в каталог документов Microsoft Word, нахожу сохраненный файл и выбираю его. Все хорошо.
Однако, когда я перехожу к функции загрузки, я обнаруживаю ошибку. Я создаю сообщение multipart / form-data, используя методы, которые, кажется, используют все, но когда я пытаюсь ввести фактические данные для файла сюда:
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 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 «Нет такого файла или каталога»}}
Я читал комментарии к нескольким другим вопросам - которые были неуместны, но все равно привлекли мое внимание - к которым можно получить доступ файл в этом случае необходимо «скопировать в песочницу приложения». Когда средство выбора запускается и пользователь выбирает файл, я отмечаю это в отладочных данных:
Не удалось связать эскизы для выбранного файла URL: /// private / var / mobile / Containers / Data / Application / 83576950-92C8-442 C -83B5-8320C037112F / Documents / Document.docx с файлом копии папки «Входящие»: /// 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 "Generation not found" UserInfo = {NSDescription = Генерация не найдена}}}
В нем говорится о "файле копии папки" Входящие ", и это тот URL-адрес" копии ", который средство выбора отправляет мне обратно, но сам файл, похоже, не существует .
Теперь я должен отметить, что я уже реализовал функцию «Загрузить изображение», аналогичную моей функции «Загрузить файл», за исключением того, что функция «Загрузить изображение» использует ImagePicker. В этом случае я получаю изображение обратно из средства выбора, я могу получить доступ к изображению, и оно отлично загружается, без проблем. Проблема находится где-то в коде, который я опубликовал выше ... или в моем понимании, который вполне может быть ограничен.
На этой странице на веб-сайте Apple говорится о том, чтобы попросить пользователя выберите каталог, но их фрагмент кода, похоже, не работает, когда я пытаюсь вставить его (похоже, повторяющаяся тема для меня), поэтому я не могу продолжить с ним.
Вопрос о переполнении стека 47902995 использует другой подход, говорит о ключах безопасности, но, похоже, полагается на Какао, а этот вопрос имеет фрагмент кода, но я не вижу, как его ie в мой существующий сборщик.
Сводка:
В Android (извините), я могу дать своему приложению «разрешение», которое позволяет ему просматривать все ( open) файлы на внутренней памяти устройства. Я понимаю, что IOS работает по-другому, но я не понимаю как это другое. Я недостаточно (пока) знаю о Xcode / IOS / Swift / SwiftUI, чтобы понимать все нюансы, и до сих пор работаю довольно слепо.
Итак, мой вопрос вкратце: может кто-нибудь, пожалуйста, скажите мне, как изменить мой код, чтобы пользователь мог открыть документ, созданный Microsoft-Office в локальном хранилище устройства, и прочитать его, чтобы затем он мог быть загружен моим приложением без нарушения каких-либо правил и ошибок?
TIA