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!