问题
I followed the Swift project UsingFiles github and its video to write files in my SwiftUI project. The project UsingFiles can write files to Files APP and then the writing files can be seen in the Files APP. But I followed the code as following, the files cannot be seen in Files APP.
let file = "\(UUID().uuidString).txt"
let contents = "Some text..."
let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = dir.appendingPathComponent(file)
do {
try contents.write(to: fileURL, atomically: false, encoding: .utf8)
}
catch {
print("Error: \(error)")
}
The UsingFiles writing files is file:///Users/fmac/Library/Developer/CoreSimulator/Devices/11111111-881E-488A-9571-E61B83EB6062/data/Containers/Data/Application/11111111-AF89-4B15-B3B5-E13A63A19F8D/Documents/E018F056-83EA-4D70-87C4-16F755AA404A.txt.
My writing files is file:///Users/fmac/Library/Developer/CoreSimulator/Devices/11111111-881E-488A-9571-E61B83EB6062/data/Containers/Data/Application/11111111-B191-4ACD-98B1-004E619C2EC7/Documents/C9E0F52E-040F-4647-94A3-88E0DA171AB5.txt
I can find the writing files of UsingFiles in the directory UsingFiles as following:
But I cannot find the writing file in Files APP in my SwiftUI project. Is there something wrong of the code in SwiftUI? Why I cannot find the writing file in Files APP?
回答1:
As I have already posted in comments you can NOT programmatically save a file out of your APP Bundle. You can use a UIDocumentInteractionController and ask the user to choose the location where the file is supposed to be written.
So if you are working with SwiftUI this gets a bit more complicated than the regular Storyboard approach as you can see in this post because you need to implement UIViewControllerRepresentable for UIDocumentInteractionController:
struct DocumentInteractionController: UIViewControllerRepresentable {
fileprivate var isExportingDocument: Binding<Bool>
fileprivate let viewController = UIViewController()
fileprivate let documentInteractionController: UIDocumentInteractionController
init(_ isExportingDocument: Binding<Bool>, url: URL) {
self.isExportingDocument = isExportingDocument
documentInteractionController = .init(url: url)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<DocumentInteractionController>) -> UIViewController { viewController }
func updateUIViewController(_ controller: UIViewController, context: UIViewControllerRepresentableContext<DocumentInteractionController>) {
if isExportingDocument.wrappedValue && documentInteractionController.delegate == nil {
documentInteractionController.uti = documentInteractionController.url?.typeIdentifier ?? "public.data, public.content"
documentInteractionController.name = documentInteractionController.url?.localizedName
documentInteractionController.presentOptionsMenu(from: controller.view.frame, in: controller.view, animated: true)
documentInteractionController.delegate = context.coordinator
documentInteractionController.presentPreview(animated: true)
}
}
func makeCoordinator() -> Coordintor { .init(self) }
}
And its Coordinator:
class Coordintor: NSObject, UIDocumentInteractionControllerDelegate {
let documentInteractionController: DocumentInteractionController
init(_ controller: DocumentInteractionController) {
documentInteractionController = controller
}
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController { documentInteractionController.viewController }
func documentInteractionControllerDidDismissOptionsMenu(_ controller: UIDocumentInteractionController) {
controller.delegate = nil
documentInteractionController.isExportingDocument.wrappedValue = false
}
}
Now you can create your DocumentInteraction View and its previews:
struct DocumentInteraction: View {
@State private var isExportingDocument = false
var body: some View {
VStack {
Button("Export Document") { self.isExportingDocument = true }
.background(DocumentInteractionController($isExportingDocument,
url: Bundle.main.url(forResource: "sample", withExtension: "pdf")!))
}
}
}
struct DocumentInteraction_Previews: PreviewProvider {
static var previews: some View { DocumentInteraction() }
}
You will need those helpers as well:
extension URL {
var typeIdentifier: String? { (try? resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier }
var localizedName: String? { (try? resourceValues(forKeys: [.localizedNameKey]))?.localizedName }
}
Sample project
回答2:
I used UIActivityViewController to save a file on my phone. It's simple and works.
import SwiftUI
struct ContentView: View {
var body: some View {
Button(action: wirtieFile) {
Image(systemName: "square.and.arrow.up")
}
}
func wirtieFile() -> Void{
let file = "test.txt"
let dir = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(file)
let contents = "test..."
do {
try contents.write(to: dir!, atomically: true, encoding: .utf8)
} catch {
print(error.localizedDescription)
}
var filesToShare = [Any]()
filesToShare.append(dir!)
let av = UIActivityViewController(activityItems: filesToShare, applicationActivities: nil)
UIApplication.shared.windows.first?.rootViewController?.present(av, animated: true, completion: nil)
}
}
来源:https://stackoverflow.com/questions/62325524/how-can-i-write-a-file-in-a-folder-located-at-apples-files-app-in-swiftui