title: SwiftUI - Use File Picker to Open a file belonging to another IOS Application, then access that file directly
body: <p>I'm developing an IOS app for the IPAD in as much native Swift as possible, (using Xcode 11.4.1, Swift 5, targeting IOS 13.X).  I do not know Cocoa or Objective-C, and I don't have prior IOS experience.  I'm coming from a C/C++ and an Android/Java background.   That said, I'm having a lot of fun with Swift, and how quickly it lets me do development.  Things which I expected to be hard have turned out to be easy, but one thing that seems to me like it should be easy has thrown up a wall I can't get over.  In brief, I am trying to allow my users to use a File Picker to choose a document from their iPad, which my app will then upload to a website server.</p>
  
  <p>My use case here is a web-based private collaboration platform - users write documents on their laptops, generally with Word, and then upload those documents to the web server, using a typical HTTP POST scenario.  In the past my platform has been web-only; now, I'm trying to write an IOS app to provide a more native experience for IPad users.</p>
  
  <p>The way I envision this working is: Users will write documents, using (for example) Microsoft Word on the iPad, and then, from within my Swift IOS app, the user will upload their Word document(s) to the server.</p>
  
  <p>My problem appears to be access permissions.  I use the following code for the Document Picker:</p>
  
  <pre><code>import SwiftUI
  import MobileCoreServices
  
  struct DocPicker: UIViewControllerRepresentable {
  
      var callback: (URL) -&gt; ()
      private let onDismiss: () -&gt; Void
  
      init(callback: @escaping (URL) -&gt; (), onDismiss: @escaping () -&gt; Void) {
          self.callback = callback
          self.onDismiss = onDismiss
      }
  
      func makeCoordinator() -&gt; Coordinator { Coordinator(self) }
  
      func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: UIViewControllerRepresentableContext&lt;DocPicker&gt;) {
      }
  
      func makeUIViewController(context: Context) -&gt; 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()
          }
      }
  }
  </code></pre>
  
  <p>I call my Document Picker using this code fragment hung off of a VStack:</p>
  
  <pre><code>.sheet(isPresented: $showFilePicker, onDismiss: {self.showFilePicker = false}) {
              DocPicker(callback: self.readyFile(_:), onDismiss: { self.showFilePicker = false })
  </code></pre>
  
  <p>And, when the callback runs, I do in fact get a URL back which seems, after a long UUID-like path component, to point to the selected file.... or at least the last component of the URL matches the name of the file I picked.</p>
  
  <blockquote>
    <p>file:///private/var/mobile/Containers/Data/Application/4B63589A-7037-4105-99F1-427444B27F40/tmp/org.me.myapp-Inbox/Document.docx</p>
  </blockquote>
  
  <p>So - my app runs, I choose the upload function, the picker opens.  I navigate into the Microsoft Word Documents directory, I find the file I saved, I select it.  All good.</p>
  
  <p>However, when I get to my upload function, I encounter an error.  I build the multipart/form-data post using methods that everyone seems to use, but when I try to bring in the actual data for the file here:</p>
  
  <pre><code>do {
              data1 = try NSData.init(contentsOf: URL.init(fileURLWithPath: fileURL, isDirectory: true)) as Data
          }
          catch { print("Error \(error)") }
  </code></pre>
  
  <p>I get a "File not found" error in Xcode's debugging window:</p>
  
  <blockquote>
    <p>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 "The file “Document.docx” couldn’t be opened because there is no such file." 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 "No such file or directory"}}</p>
  </blockquote>
  
  <p>I've read comments in a few other questions - which were off-point, but caught my attention anyway - that to access a file in this case one must "copy it to the application Sandbox."  When the picker executes and the user chooses a file, I note this in the debug output:</p>
  
  <blockquote>
    <p>Failed to associate thumbnails for picked URL file:///private/var/mobile/Containers/Data/Application/83576950-92C8-442C-83B5-8320C037112F/Documents/Document.docx with the Inbox copy 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 "Generation not found" UserInfo={NSDescription=Generation not found}}}</p>
  </blockquote>
  
  <p>It talks about an "Inbox copy file", and it is that "copy" URL that the picker sends back to me - but the file itself seems not to exist.</p>
  
  <p>Now, I should note that I've already implemented an "Upload Image" function similar to my "Upload File" function, except the Upload Image function uses an ImagePicker.  In that case, I get the Image back from the picker, I can access the Image, and it uploads perfectly, no problem.  The problem is somewhere in the code I've posted above... or in my understanding, which may well be limited.</p>
  
  <p><a href="https://developer.apple.com/documentation/uikit/view_controllers/providing_access_to_directories" rel="nofollow noreferrer">This page on the Apple website</a> talks about asking a user to select a directory, but their code fragment doesn't seem to work when I try to paste it in (a recurring theme for me, it seems) so I can't get any farther with it.</p>
  
  <p><a href="https://stackoverflow.com/questions/47902995/read-and-write-permission-for-user-selected-folder-in-mac-os-app">Stack Overflow question 47902995</a> takes a different approach, talks about security keys but seems to rely on Cocoa, and <a href="https://stackoverflow.com/questions/35861576/reusing-security-scoped-bookmark/35863729">this question</a> has a code fragment but I don't see how to tie it in to my existing picker.</p>
  
  <p><strong>Summary:</strong></p>
  
  <p>In Android (sorry), I can give my app a "permission" that lets it view all the (open) files on the device's internal storage.  I get that IOS works differently, but I do not get <em>how</em> it is different.  I don't know enough (yet) about Xcode/IOS/Swift/SwiftUI to understand all the nuances, and have been working rather blindly so far.</p>
  
  <p>So my question in a nutshell is:  Can someone please tell me how to modify my code so that a user can open a Microsoft-Office-created document on local device storage, and read it, so that it can then be uploaded by my app, without violating any rules or throwing any errors?</p>
  
  <p>TIA</p>