I've been running into an issue using .fileImporter
in SwiftUI already for a year. On iPhone simulator, Mac Catalyst and real iPad it works as expected, but when it comes to the test on a real iPhone, the picker just won't let you select files. It's not the permission issue, the sheet won't close at all and the callback isn't called. At the same time, if you use UIKits DocumentPickerViewController
, everything starts working as expected, on Mac Catalyst/Simulator/iPad as well as on a real iPhone.
Steps to reproduce:
- Create a new Xcode project using SwiftUI.
- Paste following code:
import SwiftUI
struct ContentView: View {
@State var sShowing = false
@State var uShowing = false
@State var showAlert = false
@State var alertText = ""
var body: some View {
VStack {
VStack {
Button("Test SWIFTUI") {
sShowing = true
}
}
.fileImporter(isPresented: $sShowing, allowedContentTypes: [.item]) {result in
alertText = String(describing: result)
showAlert = true
}
VStack {
Button("Test UIKIT") {
uShowing = true
}
}
.sheet(isPresented: $uShowing) {
DocumentPicker(contentTypes: [.item]) {url in
alertText = String(describing: url)
showAlert = true
}
}
.padding(.top, 50)
}
.padding()
.alert(isPresented: $showAlert) {
Alert(title: Text("Result"), message: Text(alertText))
}
}
}
DocumentPicker.swift:
import SwiftUI
import UniformTypeIdentifiers
struct DocumentPicker: UIViewControllerRepresentable {
let contentTypes: [UTType]
let onPicked: (URL) -> Void
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: contentTypes, asCopy: true)
documentPicker.delegate = context.coordinator
documentPicker.modalPresentationStyle = .formSheet
return documentPicker
}
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {}
class Coordinator: NSObject, UIDocumentPickerDelegate {
var parent: DocumentPicker
init(_ parent: DocumentPicker) {
self.parent = parent
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
print("Success!", urls)
guard let url = urls.first else { return }
parent.onPicked(url)
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
print("Picker was cancelled")
}
}
}
- Run the project on Mac Catalyst to confirm it working.
- Try it out on a real iPhone.
For some reason, I can't attach a video, so I can only show a screenshot