How to display album artwork of streamed Apple Mus

2019-03-16 14:49发布

问题:

In my music player using the new Apple Music API(released May 12, 2016) in iOS 9 (swift, although I'm currently getting familiar with Objective-C as well), I can display information from a streamed song, but not the artwork. I am using MediaPlayer, UIKit, and StoreKit frameworks. I have been successful requesting authorization to AddToCloudMusicLibrary and MusicCatalogPlayback. I have success displaying Apple Music artwork from songs that I downloaded from the Apple Music app, as well as artwork from my personal song collection. I have seen other people with issues on this, with no luck...

Just going to try asking one more time, for the people, before I resort to displaying a default image(which is necessary anyway for error-handling), or pull from an alternate service. Any help would be great! Not really an error in my code so I won't show it, unless requested to help solve this problem.

My first attempt at posting code...Here is what I have in a swift file called Authorization. Do I need to reference this code anywhere or should it be in the AppDelegate file instead? This is the only part of my project I am not 100% sure of.

import StoreKit
import MediaPlayer
import UIKit

class AppleMusicPlayer: NSObject {

    let applePlayer = MPMusicPlayerController.systemMusicPlayer()

    func playID(productID: String) {
        SKCloudServiceController.requestAuthorization { status in
            let controller = SKCloudServiceController()
            controller.requestCapabilitiesWithCompletionHandler { capabilities, error in
                if capabilities != SKCloudServiceCapability.None {
                    MPMediaLibrary.defaultMediaLibrary().addItemWithProductID(productID) { entities, error in
                        self.appPlayer.setQueueWithStoreIDs([productID])
                        self.appPlayer.shuffleMode = .Songs
                        self.appPlayer.play()
                    }
                }
            }
        }
    }
}

回答1:

This is a bug in the current API for Apple Music. As you mentioned, songs that are not in the user's library but are instead streamed from AM will not return album artwork.

You should file a feature enhancement at bugreport.apple.com (you can also dupe mine from 6 months ago 25413082 ).

In the meantime your best bet would be to use the iTunes api to retrieve the album artwork, unfortunately this doesn't return the correct results 100% of the time...



回答2:

Inside the MediaItem class there is a property called MPMediaItemPropertyArtwork. You will be able to retrieve the artwork for the album in the following way:

MPMediaItemArtwork *artwork = [mediaItem valueForProperty:MPMediaItemPropertyArtwork];
UIImage *albumImage = [itemArtwork imageWithSize:cgSizeYouWant];


回答3:

I struggled with this for quite some time. If this ever was an actual bug I'm not sure about however you can't set a UIImageView to the nowPlayingItem like the way you might expect. You must pull the image from the Apple Music service api. See Documentation here. Also have a look at the sample project here that Apple provides for a full understanding. Also here is a full sample of how I overcame this issue.

func updateUserInterface() {
    if musicPlayerManager.musicPlayerController.playbackState == .playing { //Check if anything is playing
        if let currentItem = musicPlayerManager.musicPlayerController.nowPlayingItem {
            songAlbumLabel.text = currentItem.albumTitle
            songTitleLabel.text = currentItem.title
            songArtistNameLabel.text = currentItem.artist
            let albumTitle = currentItem.albumTitle  //Changes here!
            let artist = currentItem.artist  //Changes here!
            if let artwork = musicPlayerManager.musicPlayerController.nowPlayingItem?.artwork, let image = artwork.image(at: artworkImageView.frame.size) { // Check for local image
                print("using local image")
                artworkImageView.image = image 
        } else { 
            guard let developerToken = appleMusicManager.fetchDeveloperToken() else {print("oops");return}
            let searchTypes = "songs"
            var searchURLComponents = URLComponents()
            searchURLComponents.scheme = "https"
            searchURLComponents.host = "api.music.apple.com"
            searchURLComponents.path = "/v1/catalog/"
            searchURLComponents.path += "\(authorizationManager.cloudServiceStoreFrontCountryCode)"
            searchURLComponents.path += "/search"
            let expectedArtist = artist?.replacingOccurrences(of: " ", with: "+")  //Changes here!
            let artistExpected = expectedArtist?.replacingOccurrences(of: "&", with: "")  //Changes here!
            let expectingArtist = artistExpected?.replacingOccurrences(of: "++", with: "+")  //Changes here!
            let expectedAlbum = albumTitle?.replacingOccurrences(of: " ", with: "+")  //Changes here!
            searchURLComponents.queryItems = [
                    URLQueryItem(name: "term", value: (expectingArtist! + "-" + expectedAlbum!)),
                    URLQueryItem(name: "types", value: searchTypes)
                ]  //Changes here!
            var request = URLRequest(url: searchURLComponents.url!)
            request.httpMethod = "GET"
            request.addValue("Bearer \(developerToken)", forHTTPHeaderField: "Authorization")
            let dataTask = URLSession.shared.dataTask(with: request) {
                (data, response, error) in
                print(response!)
                if let searchData = data {
                    guard let results = try? self.appleMusicManager.processMediaItemSections(searchData) else { return}
                    self.mediaItem = results
                    let album = self.mediaItem[0][0]
                    let albumArtworkURL = album.artwork.imageUrl(self.artworkImageView.frame.size)
                    if let image = self.imageManager.cachedImage(url: albumArtworkURL) {
                        print("using cached image")
                        self.artworkImageView.image = image
                    }
                    else {
                        self.imageManager.fetchImage(url: albumArtworkURL) {(image) in
                            print("fetching image")
                            self.artworkImageView.image = image
                        }
                    }
                }
            }
            dataTask.resume()
        }
    } else { // Need to set it to some kind of default values
        artworkImageView.image = nil
        songArtistNameLabel.text = " "
        songTitleLabel.text = " "
        songAlbumLabel.text = " "
        }
    }
}


回答4:

The best method I found was to use the get song from catalog Apple Music API request, documented here.

You just need to pass in the song identifier (the one which is used for playback) and the storefront identifier which is being used to play the song. This sould always yield an accurate result, compared to the anwer which uses a search request which might fail.