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()
I can’t help you with the third-party tooling side of this. My advice is that you set up a small Xcode test project to exercise the APIs in question. If you get stuck with that, I’d be happy to help. Once you get that working, you can translate that knowledge to your third-party environment. And if you have problems with that, you can seek help via its support channel.
However, I can tell you that this is wrong:
I do have these entries in my Entitlements.plist … com.apple.developer.music-kit
MusicKit is one of the most commonly hallucinating entitlements. Indeed, I listed it, with a slightly different spelling, in Determining if an entitlement is real.
Oh, and if you were using a modern version of Xcode, it would’ve told you about this, which is another good reason to prototype this stuff in Xcode.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"