App access to another app folder

I am working on a personal use app, to transcribe audio files. I have over 1000 Voice Memos of ideas for a dog training app and book, recorded while... walking dogs, of course. I seem to not have the built in transcription option, either because Sonoma doesn't support it or my region doesn't, but I have learned a lot of Swift building an app that works great fort files in a folder in Documents. I have also found the path to to all the Voice Memo recordings. But when I try to read the contents of the folder to build the queue for transcription I get The file “Recordings” couldn’t be opened because you don’t have permission to view it. I expected this to be locked down, and some searching brought me to this and I have added Access User Selected Files (Read Only) = YES to the entitlements file, but I am not seeing where in the TARGETS editor I would assign com.apple.security.files.user-selected.read-only. If I add it as a key under info I don't get a popup to select, either in Xcode or when running the app. If I try to add that key to the entitlements file it doesn't allow for selection either. I am sure I am just missing something in the documentation, likely as a result of being an Xcode & Swift noob. So, if I CAN do this and I am just missing something, can someone point the way? And if a folder inside another app is just verboten, manually copying those files to a documents folder for processing won't be the end of the world.

Answered by DTS Engineer in 813217022

Ah, OK. That’s definitely a MAC restriction. Consider:

% ls -lh ~/Library/Group\ Containers/group.com.apple.VoiceMemos.shared
total 0
ls: /Users/quinn/Library/Group Containers/group.com.apple.VoiceMemos.shared: Operation not permitted

Voice memos are highly sensitive and thus MAC blocks access to the Voice Memos container [1]. One way around this is to present an open panel (NSOpenPanel in AppKit, fileImporter(…) in SwiftUI). The panel runs in in an separate OS process, and thus is allowed to navigate to this location (as is the Finder, btw). And if the user chooses a file from that location, the system extends your process’s privileges to allow you to read the file. For example, with this code:

@IBAction
private func testAction(_ sender: Any) {
    print("AppDelegate.testAction(_:)")
    let panel = NSOpenPanel()
    panel.beginSheetModal(for: self.window) { response in
        guard response == .OK else { return }
        let url = panel.url!
        do {
            print("will read, path: \(url.path)")
            let data = try Data(contentsOf: url)
            print("did read, count: \(data.count)")
        } catch {
            print("did not read, error: \(error)")
        }
    }
}

I was able to read a voice memo:

will read, path: /Users/quinn/Library/Group Containers/group.com.apple.VoiceMemos.shared/Recordings/20210106 161835-ECF11557.m4a
did read, count: 25164

This even works if the app is sandboxed, although with two tweaks:

  • It needs the com.apple.security.files.user-selected.read-only entitlement.

  • Sandboxed apps must start and stop access to the URL, for example:

let didStart = url.startAccessingSecurityScopedResource()
defer { if didStart { url.stopAccessingSecurityScopedResource() } }
let data = try Data(contentsOf: url)

ps It’s better if you reply as a reply; see Quinn’s Top Ten DevForums Tips for this and other tips.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Even if it didn’t, you’d run into app group container protection. See On File System Permissions for more on that.

I suspect that this directory is protected by MAC. This is something I talk about in detail in On File System Permissions.

What is the exact path you’re trying to access?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Ah, OK. That’s definitely a MAC restriction. Consider:

% ls -lh ~/Library/Group\ Containers/group.com.apple.VoiceMemos.shared
total 0
ls: /Users/quinn/Library/Group Containers/group.com.apple.VoiceMemos.shared: Operation not permitted

Voice memos are highly sensitive and thus MAC blocks access to the Voice Memos container [1]. One way around this is to present an open panel (NSOpenPanel in AppKit, fileImporter(…) in SwiftUI). The panel runs in in an separate OS process, and thus is allowed to navigate to this location (as is the Finder, btw). And if the user chooses a file from that location, the system extends your process’s privileges to allow you to read the file. For example, with this code:

@IBAction
private func testAction(_ sender: Any) {
    print("AppDelegate.testAction(_:)")
    let panel = NSOpenPanel()
    panel.beginSheetModal(for: self.window) { response in
        guard response == .OK else { return }
        let url = panel.url!
        do {
            print("will read, path: \(url.path)")
            let data = try Data(contentsOf: url)
            print("did read, count: \(data.count)")
        } catch {
            print("did not read, error: \(error)")
        }
    }
}

I was able to read a voice memo:

will read, path: /Users/quinn/Library/Group Containers/group.com.apple.VoiceMemos.shared/Recordings/20210106 161835-ECF11557.m4a
did read, count: 25164

This even works if the app is sandboxed, although with two tweaks:

  • It needs the com.apple.security.files.user-selected.read-only entitlement.

  • Sandboxed apps must start and stop access to the URL, for example:

let didStart = url.startAccessingSecurityScopedResource()
defer { if didStart { url.stopAccessingSecurityScopedResource() } }
let data = try Data(contentsOf: url)

ps It’s better if you reply as a reply; see Quinn’s Top Ten DevForums Tips for this and other tips.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Even if it didn’t, you’d run into app group container protection. See On File System Permissions for more on that.

App access to another app folder
 
 
Q