1

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: enter image description here

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?

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
Muz
  • 699
  • 1
  • 11
  • 25
  • What do you mean by “ I cannot find the writing file in Files APP”? Your file is showing inside onMyPhone location – Leo Dabus Jun 11 '20 at 13:39
  • @Leo, I mean the file is not in onMyPhone. I cannot find the file on my phone. – Muz Jun 11 '20 at 13:51
  • You have posted a screenshot of your file. It is inside your documents directory. – Leo Dabus Jun 11 '20 at 14:00
  • The UsingFile can export file to documents directory. But I cannot export file to document directory in my APP by the code I pasted. – Muz Jun 11 '20 at 14:05
  • 1
    Your file it is not inside Files app. It is already inside your Documents. You have to learn how to browse/list your files – Leo Dabus Jun 11 '20 at 14:14
  • @Leo Thanks. I understand your meaning. I will search it. – Muz Jun 11 '20 at 14:16
  • @Leo The same as you say that the file has been written in the Documents and I can read it by `try String(contentsOf: fileURL)`. Could you tell me how to show them in Files APP? Why the UsingFiles can show them in Files APP? – Muz Jun 11 '20 at 15:10
  • Creating your own file browser it is not a trivial task. If you want the same look/options of the Files App you can use UIDocumentBrowserViewController. https://developer.apple.com/documentation/uikit/uidocumentbrowserviewcontroller and https://developer.apple.com/documentation/uikit/view_controllers/adding_a_document_browser_to_your_app – Leo Dabus Jun 11 '20 at 15:14
  • Thanks. But I want to write the txt file out of my APP's sandbox and share it to other people or send the written file by email. So the written file should be shown in Files--On My Phone. Then how to write the file to Files APP directly like the project UsingFiles? – Muz Jun 11 '20 at 15:24
  • 2
    There is no way to programmatically save a file out of your APP Bundle. You need to ask the user to choose the location https://stackoverflow.com/questions/46456481/how-to-write-a-file-to-a-folder-located-at-apples-files-app-in-swift/46457518#46457518 – Leo Dabus Jun 11 '20 at 15:31

3 Answers3

4

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)
    }
}
Muz
  • 699
  • 1
  • 11
  • 25
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

Leo Dabus
  • 229,809
  • 59
  • 489
  • 571
0

Try add “Application supports iTunes file sharing” and “Supports opening documents in place” to “info.plist”. And change them value to true.

  • You should add some code to your solution in order to help OP – Mattia Righetti Feb 18 '23 at 01:11
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Feb 18 '23 at 01:12