How to Write a File to a Folder Located At Apple'S Files App in Swift

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

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

How to write a file to a folder located at Apple's Files App in Swift

You can use UIDocumentInteractionController and let the user select where he wants to save your file when you share your url. The user just needs to select save to files and choose which directory to save the file you are exporting.

You can use UIDocumentInteractionController to share any file type located inside your App bundle, at your Documents directory or another folder accessible from your App.

class ViewController: UIViewController {
let documentInteractionController = UIDocumentInteractionController()
func share(url: URL) {
documentInteractionController.url = url
documentInteractionController.uti = url.typeIdentifier ?? "public.data, public.content"
documentInteractionController.name = url.localizedName ?? url.lastPathComponent
documentInteractionController.presentOptionsMenu(from: view.frame, in: view, animated: true)
}
@IBAction func shareAction(_ sender: UIButton) {
guard let url = URL(string: "https://www.ibm.com/support/knowledgecenter/SVU13_7.2.1/com.ibm.ismsaas.doc/reference/AssetsImportCompleteSample.csv?view=kc") else { return }
URLSession.shared.dataTask(with: url) { data, response, error in
guard let data = data, error == nil else { return }
let tmpURL = FileManager.default.temporaryDirectory
.appendingPathComponent(response?.suggestedFilename ?? "fileName.csv")
do {
try data.write(to: tmpURL)
DispatchQueue.main.async {
self.share(url: tmpURL)
}
} catch {
print(error)
}

}.resume()
}
}


extension URL {
var typeIdentifier: String? {
return (try? resourceValues(forKeys: [.typeIdentifierKey]))?.typeIdentifier
}
var localizedName: String? {
return (try? resourceValues(forKeys: [.localizedNameKey]))?.localizedName
}
}

edit/update:

If you would like to expose the files located on your App Bundle's document directory you can check this post How can I display my App documents in the Files app for iPhone

How can I display my App documents in the Files app for iPhone

If you would like to expose your App document files inside Apple's Files App you need to include the "Supports Document Browser" key in your info plist file and set it to YES:

Sample Image

How to save document to Files App in swift

If you have access to your PDFdata then you could present the user with a UIActivityViewController where they can then save it to Files, or share it with any of the other available options:

let activityViewController = UIActivityViewController(activityItems: ["Name To Present to User", pdfData], applicationActivities: nil)
present(activityViewController, animated: true, completion: nil)

Sample Image

How to write files in an iOS app to make them visible to afc protocol?

It seems that what I am trying to find is the Documents directory in my iOS app's sandbox directory (from documentation).
The directory can be made visible in afc protocol by following this answer,
and this answer gives a good example of writing to a file in that directory.

Share Specific directory in app's Documents with Files app

Before using file system of iOS, Please check the usage of different directories of the iOS file system.

You can refer this link: https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/FileSystemOverview/FileSystemOverview.html

As per above link, apple has clearly mentioned that:

For Documents Directory : It clearly says that this directory should only contain files that you may wish to expose to the user.

Sample Image

If you want something that should not be exposed to User, then dont use Documents directory, instead use Library directory for this.

For Library directory: Use the Library subdirectories for any files you don’t want exposed to the user. Your app should not use these directories for user data files.

Sample Image

Here, see the following screenshot from above link, which says about which directory to use when?

Sample Image

In short, keep your root directories content in Document directory and move all other directory with their content to Library directory OR Library/Application Support Directory. So, your intended purpose will get fulfilled.

Create a folder inside documents folder in iOS apps

I do that the following way:

NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents folder
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:@"/MyFolder"];

if (![[NSFileManager defaultManager] fileExistsAtPath:dataPath])
[[NSFileManager defaultManager] createDirectoryAtPath:dataPath withIntermediateDirectories:NO attributes:nil error:&error]; //Create folder


Related Topics



Leave a reply



Submit