Experimenting with MusicKit for Swift - Permission

The second part of the series is on permission and user content. You authorize permission to a third-party app to use your Apple Music library with your consent. You should also have control over which app can access that data.

Apple Music Usage

For building Musadora, I explicitly need permission to access the user’s music library and listening history to create an experience around it. While writing this, I’m relishing sad songs from Replay 2015. Oh boy, my music taste has certainly matured over the years. I still want to sob over similar songs, so I turned on the autoplaying option on Apple Music.

My Replay 2015 playlist on Apple Music

I desire to build a decent recommendation system, and access to listening history is therefore essential.

To get informed consent from the user, I added the NSAppleMusicUsageDescription key to the Info.plist. The value is the message that tells the user why the app requests access to the user’s media library.

For Musadora, the value is -

Musadora uses Music access to play music and create a pleasant experience.

Requesting Authorization

Earlier, we used a type method called requestAuthorization(_:) of SKCloudServieController to ask the user for permission to play Apple Music tracks or add tracks to the music library.

class func requestAuthorization(_ completionHandler: @escaping (SKCloudServiceAuthorizationStatus) -> Void)

And based on the authorization status from the completion handler, we updated the flow accordingly.

SKCloudServiceController.requestAuthorization { [weak self] status in
    switch status {
        case .authorized:
            self?.isAuthorizedForMusicKit = true
        case .restricted:
            self?.musicKitError = .restricted
        case .notDetermined:
            self?.musicKitError = .notDetermined
        case .denied:
            self?.musicKitError = .denied
        @unknown default:
            self?.musicKitError = .notDetermined
    }
}

If you use this method in Xcode 13 now, you’ll get a warning - Consider using asynchronous alternative function.

So, let’s do that instead! We use the MusicAuthorization structure in MusicKit. To request the user to authorize access to Apple Music and provide the app with consent, we use the request asynchronous method -

class LoginManager: LoginManagerProtocol, ObservableObject {
    @Published var isAuthorizedForMusicKit = false
    @Published var musicKitError: MusicKitError?

    func requestMusicAuthorization() async {
        let status = await MusicAuthorization.request()

        switch status {
            case .authorized:
                isAuthorizedForMusicKit = true
            case .restricted:
                musicKitError = .restricted
            case .notDetermined:
                musicKitError = .notDetermined
            case .denied:
                musicKitError = .denied
            @unknown default:
                musicKitError = .notDetermined
        }
    }
}

We get the following prompt on running the above code while trying to request access to Apple Music. The value from the property list key is shown as the message in the action view.

Prompt to access Apple Music in Musadora

Conclusion

Completion handlers weren’t the most elegant code to write, in my opinion, and I’ve been enjoying the asynchronous syntax for a while.

With the initial setup of authentication and authorization done, we can finally move to use the latest APIs offered by MusicKit for Swift!