How can I write a file in a folder located at Apple's Files App in SwiftUI?

Deadly 提交于 2021-02-17 03:58:52

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!