iosxcodeswiftuiswiftui-fileimporter

SwiftUI .fileImporter Not Working Due to Permissions


In an iOS app, I am trying to load a .csv file from the user iCloud Drive. It works as expected in the simulator but does not work on a device. I have seen a couple of SO articles with similar questions but no solution that works for me.

This Apple documentation seems to indicate that I am coding the process correctly: https://developer.apple.com/documentation/swiftui/view/fileimporter(ispresented:allowedcontenttypes:allowsmultipleselection:oncompletion:)

I thought perhaps an Info.plist item was required, but I could not find any keys that seem to fix this.

The result is the same whether I include the url.startAccessingSecurityScopedResource() line or not.

The console says: Failed to import CSV: The file “EightItems.csv” couldn’t be opened because you don’t have permission to view it.

The dataStore item below is just to control a progress view: @Published var isImporting: Bool = false And the code is: @State private var isDocumentPickerPresented = false

//import from csv file
if dataStore.isImporting {
    ProgressView("Importing data...")
} else {
    Button("Import CSV") {
        isDocumentPickerPresented = true
    }
    .fileImporter(
        isPresented: $isDocumentPickerPresented,
        allowedContentTypes: [.commaSeparatedText],
        allowsMultipleSelection: false
    ) { result in
        switch result {
        case .success(let urls):
            if let url = urls.first {
                let gotAccess = url.startAccessingSecurityScopedResource()
                if !gotAccess { return }
                dataStore.importCSV(from: url, context: context)
                url.stopAccessingSecurityScopedResource()
            }
        case .failure(let error):
            print("Failed to pick file: \(error.localizedDescription)")
        }
    }
    .buttonStyle(.borderedProminent)
}//if else

screenshot if file finder

Any guidance would be appreciated. Xcode 15.4, iOS 17.5


Solution

  • For others - it seems that you need to add the

    .startAccessingSecurityScopedResource()
    

    to BOTH the above code and in the enclosed dataStore.importCSV() function. And then, only issue the stop at the end of that function. Don't know the reasoning, but that works for me.