Field Notes

MusicKit on macOS

This week I’ve been looking at adding Apple Music integration into Portal. MusicKit is pretty awesome but whilst it’s available on macOS for exploring the library content the music playback APIs are not (not yet at least crosses fingers).

After some investigations I found that there exists a MusicKit JS it’s currently listed as in beta but seems quite complete on the playback side. So the plan was hatched, could we lean on the JS API for music playback when running on Mac.

The process looks something like this:

  1. call MusicAuthorization.request() from Swift to request access.
  2. call DefaultMusicTokenProvider().developerToken() from Swift to get an API token
  3. call DefaultMusicTokenProvider().userToken(for: developerToken, options: [.ignoreCache]) from Swift to get an API token as the signed in user, relying on their Mac for auth.
  4. create a WKWebView(frame: CGRect.zero) to act as a headless browser.
  5. Inject a page into the webview that loads musickit.js and the above tokens.
  6. Configure the player in JS land, avoiding calling music.authorize() as the docs suggest and instead using the injected credentials. Something like the below.
document.addEventListener('musickitloaded', function() {
  MusicKit.configure({
    developerToken,
    app: {
      name: 'Portal',
      build: '1.0'
    }
  });

  let music = MusicKit.getInstance();
  music.musicUserToken = userToken;
  window.music = music
});

With this all in place we can now control playback from the Swift side via, e.g. webView.evaluateJavaScript("window.music.pause()")

So far this has actually worked a lot better than I was expecting and might actually be workable as a solution until such time as Apple ship MPMusicPlayerController support on macOS.