问题
This code results in silence:
let query = MPMediaQuery.songs()
let result = query.items
guard let items = result, items.count > 0 else {return}
let song = items[0]
let player = MPMusicPlayerController.applicationQueuePlayer
let coll = MPMediaItemCollection(items: [song])
let q = MPMusicPlayerMediaItemQueueDescriptor(itemCollection: coll)
player.setQueue(with: q)
player.play()
I've stepped through the code, and we reach player.play()
. I have an MPMediaItem and I've correctly formed an MPMediaItemCollection from that, and an MPMusicPlayerMediaItemQueueDescriptor from that. So why isn't my player playing?
回答1:
You've found a bug. It appears that the initializer MPMusicPlayerMediaItemQueueDescriptor(itemCollection:)
is completely broken: it results in an unusable queue descriptor.
The workaround, where possible, is to use the other initializer instead, namely MPMusicPlayerMediaItemQueueDescriptor(query:)
.
For example, in this case, you could write (picking up in the last four lines of the original code):
let coll = MPMediaItemCollection(items: [song])
let predicate = MPMediaPropertyPredicate(
value: song.persistentID,
forProperty: MPMediaItemPropertyPersistentID)
let query = MPMediaQuery(filterPredicates: [predicate])
let q = MPMusicPlayerMediaItemQueueDescriptor(query: query)
player.setQueue(with: q)
player.play()
Unfortunately, there are many circumstances where you can't form a single query that gets the MPMediaItemCollection you really wanted.
In this particular example you could work around that, too, by setting the player's queue directly with an MPMediaItemCollection instead of a MPMusicPlayerMediaItemQueueDescriptor made from an MPMediaItemCollection.
But alas, there are some commands (such as append(_:)
) that require an MPMusicPlayerMediaItemQueueDescriptor, and for things like that, this entire API is basically hosed. It has been hosed since iOS 10.1 and it remains hosed in iOS 11.1.
回答2:
"It has been hosed since iOS 10.1 and it remains hosed in iOS 11.1." Seconded.
I have been in the midst of a protracted fight just trying to a) get MPMusicPlayerController to simply work (finally managed that) and b) get it to play a song from an offset (still have not). And this is in an app that prior to iOS 10 worked 100% as expected.
Right now, this is code that works for me (at least with regard to getting a song to play):
let currentPlayer = MPMusicPlayerController.applicationQueuePlayer()
currentPlayer.repeatMode = .none
self.currentCollection = MPMediaItemCollection(items: [mediaItem])
currentPlayer.beginGeneratingPlaybackNotifications()
let query = MPMediaQuery.songs()
let pred = MPMediaPropertyPredicate(value: mediaItem.persistentID, forProperty: MPMediaItemPropertyPersistentID)
query.addFilterPredicate(pred)
let desc = MPMusicPlayerMediaItemQueueDescriptor(query: query)
currentPlayer.setQueueWith(desc)
currentPlayer.prepareToPlay(completionHandler: {[unowned self] (error) in
MPMusicPlayerController.applicationQueuePlayer().play()
})
It is a bit convoluted in that I had to use what I would consider the most complicated means based on available APIs. But several other methods cause the completion block to either never get called or get a completely unhelpful error. Right now I have 5 bugs reported to Apple with regard to MPMusicPlayerController so I am not exactly a happy developer at the moment. I will be opening one more related to this code as setStartTime & setEndTime does not appear to work any better than currentPlaybackTime for starting play at a specified offset.
This code does dependably play synced and downloaded Apple Music items though.
来源:https://stackoverflow.com/questions/46836728/cant-set-mpmusicplayercontroller-queue-with-mpmusicplayermediaitemqueuedescript