Post

Replies

Boosts

Views

Activity

Cannot modify files outside my iOS app's sandbox. Permissions issue.
I'm developing an iOS app (latest Swift, iOS, Xcode versions atm of writing) which needs to rename audio files (and later modify its metadata) located anywhere (local storage, external storage, cloud, etc). I'm bringing my own question in StackOverflow but I'd like to know better from the source so I came here. The trouble comes when testing on a physical device while trying to rename a file in some folder On My iPhone, the app does as intended when testing on the Simulator. On my physical iPhone I get an error logged saying that I don't have the permissions to do that. “filename.mp3” couldn’t be moved because you don’t have permission to access “randomFolder". I did my googling and asked GPTs about it, learned about FileCoordinator, UIDocumentPickerViewController⁠, startAccessingSecurityScopedResource. I also saw a couple of videos that I cannot reference in this forum. Some code I have in place: This is the document picker which I then call from a .sheet on another View. struct DocumentPicker: UIViewControllerRepresentable { @Binding var newName: String @EnvironmentObject private var bookmarkController: BookmarkController func makeUIViewController(context: Context) -> UIDocumentPickerViewController { let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: supportedTypes) documentPicker.delegate = context.coordinator return documentPicker } func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) { print("updateUIViewController documentPicker") } func makeCoordinator() -> Coordinator { Coordinator(self, newName) } class Coordinator: NSObject, UIDocumentPickerDelegate { var parent: DocumentPicker var newName: String init(_ parent: DocumentPicker, _ newName: String = "") { self.parent = parent self.newName = newName } func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { // save bookmark print("documentPicker \(urls[0])") parent.bookmarkController.addBookmark(for: urls[0]) // Rename the file var error: NSError? NSFileCoordinator().coordinate(readingItemAt: urls[0], options: [], error: &error) { coordinatedURL in do { // let data = try Data(contentsOf: newURL) print("urls[0]: \(urls[0])") print("coordinatedURL: \(coordinatedURL)") print("renamedURL: \(newName)") try renameFile(at: coordinatedURL, to: newName) } catch { print("Error: \(error.localizedDescription)") } } } } } Renaming function: /// Rename selected file from browser func renameFile(at fileURL: URL, to newName: String) throws { let fileExtension = fileURL.pathExtension let directory = fileURL.deletingLastPathComponent() // Create a new URL with the updated name and the original extension let renamedURL = directory.appendingPathComponent(newName).appendingPathExtension(fileExtension) try FileManager.default.moveItem(at: fileURL, to: renamedURL) } I have a BookmarkController in place so that my URLs are bookmarked for later use. Here it is: import SwiftUI import MobileCoreServices class BookmarkController: ObservableObject { @Published var urls: [URL] = [] init() { loadAllBookmarks() } func addBookmark(for url: URL) { print("adding bookmark for \(url)") do { guard url.startAccessingSecurityScopedResource() else { print("Failed to obtain access to the security-scoped resource.") return } defer { url.stopAccessingSecurityScopedResource() } let bookmarkData = try url.bookmarkData(options: .minimalBookmark, includingResourceValuesForKeys: nil) let uuid = UUID().uuidString try bookmarkData.write(to: getAppSandboxDir().appendingPathComponent(uuid)) urls.append(url) } catch { print("Error Adding Bookmark: \(error.localizedDescription)") } } func loadAllBookmarks() { // Get all the bookmark files let files = try? FileManager.default.contentsOfDirectory(at: getAppSandboxDir(), includingPropertiesForKeys: nil) // Map over the bookmark files self.urls = files?.compactMap { file in do { let bookmarkData = try Data(contentsOf: file) var isStale = false // Get the URL from each bookmark let url = try URL(resolvingBookmarkData: bookmarkData, bookmarkDataIsStale: &isStale) guard !isStale else { // Handle stale bookmarks return nil } print("loaded bookmark: \(url)") // Return URL return url } catch { print("Error Loading Bookmark: \(error.localizedDescription)") return nil } } ?? [] } private func getAppSandboxDir() -> URL { // TODO ver 0 index FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] } } When running on my device, I see url.startAccessingSecurityScopedResource throwing: Failed to obtain access to the security-scoped resource. I have also tried getting access to the parent directory like this: let parentURL = url.deletingLastPathComponent() and then using parentURL instead, but it also fails. Something I noticed is that my app is not shown in the Settings -> Privacy & Security -> Files and Folders list. My app didn't trigger any dialog to be added here given user consent. Fiddling with entitlements in Info.plist and Capabilities did not help either, but I'm not so sure about which ones should I add. So: Could it be that the problem I'm seeing about permissions and my app not appearing at the Files and Folders privacy settings on my iPhone are because my app is signed with a developer account which is not in the apple developer program? this is my last thought since I'm not understanding what else should I try. Any pointers and help will be much appreciated. Thanks!
3
0
900
Jan ’24