Hi,
I'm developing a Tauri V2 app on MacOS, and am wanting to implement playback controls. It seems that Apple locks down playback, requiring a signed application.
My app also has capabilities to "get currently playing track", and I confirmed this works; Apple produces a popup triggered by my await MusicAuthorization.request() call. It returns nil, of course, because I can't get anything to play via the ApplicationMusicPlayer; only through the system's Apple Music app. I understand SystemMusicPlayer is not available on MacOS, which is fine.
I'm just a little confused as it seems pretty standard to need to test playback controls quickly without having to codesign and do some provisionprofile embedding acrobatics each time Rust re-compiles target/debug. This slows down development a lot.
I do have these entries in my Entitlements.plist:
<key>com.apple.security.personal-information.media-library</key>
<true/>
<key>com.apple.developer.music-kit</key>
<true/>
<key>com.apple.security.app-sandbox</key>
<true/>
In my tauri.conf.json, I have: "macOS": { "entitlements": "./Entitlements.plist", "signingIdentity": "Apple Development: <name> (<id>)" }
My application works like this: I have a temporary button click to fire off a tauri<string>invoke() command which goes to a #tauri::command, which bridges to Swift code. Again, I validated that my less-permissive "get currently playing track" works; i.e., does not get permission denied.
exact error message:
[swift] playMedia error: .permissionDenied
(^specifically, ".permissionDenied")
My code to trigger playback of a specific media item:
Task {
print("[swift] entered sema Task")
let status: MusicAuthorization.Status = await MusicAuthorization.request()
print("auth status: \(status)")
guard status == .authorized else { sema.signal(); return }
print("passed the status guard.")
do {
var request = MusicCatalogResourceRequest<Song>(matching: \.id, equalTo: MusicItemID(rawValue: songId))
request.limit = 1
let response = try await request.response()
guard let song = response.items.first else { sema.signal(); return }
let player = ApplicationMusicPlayer.shared
player.queue = [song]
try await player.play()
success = true
} catch {
print("[swift] playMedia error: \(error)")
}
sema.signal()