11.2 C
New York
Sunday, April 6, 2025

swift – Learn how to learn/write to a folder from the iOS Recordsdata app accross app restarts


I am growing a SwiftUI app that has to sync information to a folder in Dropbox, Google Drive or any file supplier that exists on the iOS Recordsdata app. I can’t use the Dropbox or Google Drive APIs as a result of I need to supply the app without spending a dime, and people APIs grow to be very costly when you begin getting customers.

From my analysis I perceive that I ought to current a UIDocumentPickerViewController to the person, to let him choose the folder the place to sync the information to, and that controller ought to return the URL to the folder chosen. Then I can use that URL to jot down to the folder, and I can persist the URL to reuse it everytime I would like to jot down to the folder.

I’ve created a demo app that works nice on the simulator, however not on an actual gadget as a result of the URL stops working when the person closes the app (which doesn’t occur on the simulator).

My questions are:

  • Can I persist the URL in a method that continues to be legitimate after the app restarts?
  • Is there a greater strategy to learn/write to a folder within the Recordsdata app?

I do know this may be performed as another apps, like Kepassium, do the identical. I even discovered their supply code in GitHub, however it’s applied with storyboards, which I have no idea, and I have not managed to determine how they do it, regardless of having devoted a number of hours to review the code.

Under is the supply for the demo app:

struct ContentView: View {
    
    enum Constants : String {
        case folderURLKey = "folderURL"
    }
    
    
    @State non-public var isShowingDocumentPicker = false
    @State non-public var selectedFolderURL: URL?
    @State non-public var fileList: [String] = []

    var physique: some View {
        VStack {
            Button("Choose Dropbox folder") {
                isShowingDocumentPicker = true
            }
            .padding(.backside, 20)

            if let folderURL = selectedFolderURL {
                Textual content("Chosen folder:")
                Textual content(folderURL.path)
                    .foregroundColor(.blue)
                    .padding(.backside, 20)
                
                Button("Create random file") {
                    createRandomFile()
                }
                ForEach(self.fileList, id: .self) { fileName in
                    Textual content(fileName).font(.caption2)
                }
            }
        }
        .buttonStyle(.bordered)
        .sheet(isPresented: $isShowingDocumentPicker) {
            FolderPickerView { folderURL in
                selectedFolderURL = folderURL
                if let url = folderURL {
                    let urlData = strive! url.bookmarkData()
                    UserDefaults.normal.setValue(urlData, forKey: Constants.folderURLKey.rawValue)
                }
            }
        }
        .onAppear() {
            let urlData = UserDefaults.normal.information(forKey: Constants.folderURLKey.rawValue)
            if let urlData = urlData {
                var isStale: Bool = false
                let folderURL = strive! URL(resolvingBookmarkData: urlData, bookmarkDataIsStale: &isStale)
                self.selectedFolderURL = folderURL
                
                self.fileList = self.listFiles(folderURL: self.selectedFolderURL!)
            }
            
        }
    }
    
    func listFiles(folderURL: URL) -> [String] {
        var record: [String] = []
        do {
            if folderURL.startAccessingSecurityScopedResource() {
                let contents = strive FileManager.default.contentsOfDirectory(at: folderURL, includingPropertiesForKeys: nil)
                for fileURL in contents {
                    record.append(fileURL.lastPathComponent)
                }
                folderURL.stopAccessingSecurityScopedResource()
            }
            else {
                print("Name to startAccessingSecurityScopedResource failed!!!!!")
            }
        }
        catch {
            print("ERROR: (error)")
        }
        return record
    }
    
    func createRandomFile() {
        if selectedFolderURL!.startAccessingSecurityScopedResource() {
            FileManager.default.createFile(atPath: selectedFolderURL!.appendingPathComponent("random_file_(UUID().uuidString).txt").path, contents: Information("Hey, world!".utf8))
            selectedFolderURL!.stopAccessingSecurityScopedResource()
            self.fileList = self.listFiles(folderURL: self.selectedFolderURL!)
        }
        else {
            print("Name to startAccessingSecurityScopedResource failed!!!!!")
        }
    }
    
}

struct FolderPickerView: UIViewControllerRepresentable {
    var onFolderSelected: (URL?) -> Void

    func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
        let picker = UIDocumentPickerViewController(forOpeningContentTypes: [.folder])
        picker.delegate = context.coordinator
        picker.allowsMultipleSelection = false // Solo una carpeta
        return picker
    }

    func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {}

    func makeCoordinator() -> Coordinator {
        Coordinator(onFolderSelected: onFolderSelected)
    }

    class Coordinator: NSObject, UIDocumentPickerDelegate {
        var onFolderSelected: (URL?) -> Void

        init(onFolderSelected: @escaping (URL?) -> Void) {
            self.onFolderSelected = onFolderSelected
        }

        func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
            onFolderSelected(urls.first)
        }

        func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
            onFolderSelected(nil)
        }
    }
}

Any assistance is appreciated!

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles