此代码导致沉默:
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()
我已完成代码,我们到达player.play()
。我有一个MPMediaItem,我正确地从那里形成了一个MPMediaItemCollection,以及一个来自的MPMusicPlayerMediaItemQueueDescriptor 。那我的玩家为什么不玩呢?
答案 0 :(得分:1)
快捷键5
我来晚了一点,但这就是我想出的。 (我正在整理歌曲以使用描述符进行播放)。
确保在主线程上使用Music Player运行所有内容。如果没有,您将遇到奇怪的错误。
通过persistentId获取歌曲:
/// Retrieves a song in the MPMediaItem format using the persistentId passed.
/// - Parameter persistentID: (UInt64) The songs persistentId.
/// - Returns: (MPMediaItem?) Nil if not found other wise the MPMediaItem (song).
private static func getSong(forId persistentID: UInt64) -> MPMediaItem? {
let query = MPMediaQuery.songs()
let predicate = MPMediaPropertyPredicate(value: persistentID, forProperty: MPMediaItemPropertyPersistentID)
query.addFilterPredicate(predicate)
return query.items?.first
}
通过persistentId播放歌曲:
private var startTime: Double = 0
private var endTime: Double = 0
/// Plays the song with the identifier.
/// - Note: Trims song to start and end time.
/// - Parameter persistentId: (UInt64) The song persistent identifier.
private func play(forId persistentId: UInt64) {
DispatchQueue.main.async {
if let song = Self.getSong(forId: persistentId) {
let identifier = MPMediaItemPropertyPersistentID
let predicate = MPMediaPropertyPredicate(value: persistentId, forProperty: identifier)
let query = MPMediaQuery(filterPredicates: [predicate])
let descriptor = MPMusicPlayerMediaItemQueueDescriptor(query: query)
descriptor.setStartTime(self.startTime, for: song)
descriptor.setEndTime(self.endTime, for: song)
self.musicPlayer.setQueue(with: descriptor)
self.musicPlayer.prepareToPlay()
self.musicPlayer.repeatMode = .none
self.musicPlayer.play()
}
}
}
我还发现初始化音乐控制器的方式很重要:
private lazy var musicPlayer: MPMusicPlayerController = { MPMusicPlayerController.applicationQueuePlayer }()
请注意:某些代码不是拖放式的。您需要定义诸如开始和结束时间变量之类的东西。
答案 1 :(得分:0)
你发现了一个错误。初始化程序MPMusicPlayerMediaItemQueueDescriptor(itemCollection:)
似乎完全被破坏:它导致一个不可用的队列描述符。
在可能的情况下,解决方法是使用其他初始值设定项,即MPMusicPlayerMediaItemQueueDescriptor(query:)
。
例如,在这种情况下,您可以编写(拾取原始代码的最后四行):
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()
不幸的是,在许多情况下,您无法形成一个获得您真正想要的MPMediaItemCollection的查询。
在这个特定的例子中,你也可以通过直接用MPMediaItemCollection设置玩家的队列而不是MPMediaItemCollection制作的MPMusicPlayerMediaItemQueueDescriptor来解决这个问题。
但是,有一些命令(例如append(_:)
)需要一个MPMusicPlayerMediaItemQueueDescriptor,对于这样的事情,整个API基本上都是软管。它已经从iOS 10.1开始流行,并且仍然在iOS 11.1中使用。
答案 2 :(得分:0)
"它已经从iOS 10.1开始流行,并且仍然在iOS 11.1中使用。" 借调。
我一直在进行一场旷日持久的斗争,只是试图a)让MPMusicPlayerController简单地工作(最后管理)和b)让它从一个偏移(仍然没有)播放一首歌。这是在iOS 10之前100%按预期工作的应用程序。
现在,这是适合我的代码(至少在播放歌曲方面):
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()
})
有点令人费解,因为我必须使用基于可用API的最复杂的方法。但是其他几种方法会导致完成块永远不会被调用或者得到完全无用的错误。现在我向Apple报告了有关MPMusicPlayerController的5个错误,所以我现在不是一个非常开心的开发人员。我将打开另一个与此代码相关的内容,如setStartTime& setEndTime似乎没有比currentPlaybackTime更好地开始在指定的偏移处播放。
此代码可靠地播放同步和下载的Apple Music项目。