Native file import and export functionality has been added to SwiftUI 2.0. It should be noted that the behavior of file export in different directories will vary, and the handling of permissions will also differ on different platforms.
Update
Currently, SwiftUI has made significant changes to the usage of file import and export.
fileImporter, fileExporter, and fileMover now correspond to import, export, and move operations, respectively.
An example is as follows:
.fileImporter(isPresented: showImport, allowedContentTypes: [.zip], onCompletion: {
result in
switch result{
case .success(let url):
print(store.dataHandler.importData(url))
case .failure(let error):
print(error)
}
showImport.wrappedValue = false
})
The system will automatically pop up a sheet. Currently, the fileImporter has a bug: if the sheet is canceled using a gesture, it will be difficult to bring it up again. It can only be canceled using the “cancel” function.
In fact, I prefer the previous usage, but the old usage has now been deprecated.
Original Article
importFiles
@Environment(\.importFiles) var importFile
importFile.callAsFunction(singleOfType: [.plainText]){ result in}
exportFiles
@Environment(\.exportFiles) var exportFile
try! exportFile.callAsFunction(FileWrapper(url: URL(fileURLWithPath:filePath), options: .immediate), contentType: .plainText){result in}
Sample Code
import SwiftUI
struct ExportImportTest: View {
@Environment(\.importFiles) var importFile
@Environment(\.exportFiles) var exportFile
@State var text:String = ""
var body: some View {
List{
Button("Generate File"){
let filePath = NSTemporaryDirectory() + "test.txt"
let outputText = "Hello World!"
do {
try outputText.write(toFile: filePath, atomically: true, encoding: .utf8)
print("Test file has been generated")
}
catch let error {
print(error)
}
}
Button("Import File importFiles"){
importFile.callAsFunction(singleOfType: [.plainText]){ result in
switch result{
case .success(let url):
print(url)
do {
//iOS sandbox mechanism requires us to request temporary access to the url
_ = url.startAccessingSecurityScopedResource()
let fileData = try Data(contentsOf: url)
if let text = String(data:fileData,encoding: .utf8) {
self.text = text
print(text)
}
url.stopAccessingSecurityScopedResource()
}
catch let error {
print(error)
}
case .failure(let error):
print(error)
case .none:
break
}
}
}
Button("Export File exportFiles"){
//exportFile.callAsFunction(moving: URL, completion: ) will move the file, and the source file will be deleted
//If there is an error with the move (e.g. source file not found), the program will crash
//When exporting a file from the temporary directory, whether using "move" or not, the source file will be deleted
//Personally, I prefer the callAsFunction method of FileWrapper
let filePath = NSTemporaryDirectory() + "test.txt"
do {
try exportFile.callAsFunction(FileWrapper(url: URL(fileURLWithPath:filePath), options: .immediate), contentType: .plainText){result in
switch result{
case .success(let url):
print("File exported successfully: \(url)")
case .failure(let error):
print(error)
case .none:
break
}
}
}
catch let error {
print(error)
}
}
Text("Imported File Content: \(text)")
}
}
}
For macOS, the App Sandbox - User Selected File setting in the project configuration needs to be set to read and write.
Regret
There is no native activityViewController provided.