重新排列MediaPlayer音乐队列[iOS]

重新排列MediaPlayer音乐队列[iOS],ios,swift,mpmusicplayercontroller,Ios,Swift,Mpmusicplayercontroller,我真的很难弄明白一些事情,我已经在互联网上找遍了,我找不到答案。正如你所知,Spotify和Apple music等音乐应用程序本身可以让用户在收听歌曲时重新排列上一个队列。我还不知道怎么做同样的事情。我希望能够完全重新安排队列,包括添加、删除和移动上一个队列中的歌曲。我尝试过各种方法,比如 musicPlayer.setQueue([queue]) 但这需要我调用musicPlayer.prepareToPlay()afterwords来更新队列,从而结束当前歌曲并启动新队列 我也试过使用

我真的很难弄明白一些事情,我已经在互联网上找遍了,我找不到答案。正如你所知,Spotify和Apple music等音乐应用程序本身可以让用户在收听歌曲时重新排列上一个队列。我还不知道怎么做同样的事情。我希望能够完全重新安排队列,包括添加、删除和移动上一个队列中的歌曲。我尝试过各种方法,比如

musicPlayer.setQueue([queue])
但这需要我调用
musicPlayer.prepareToPlay()
afterwords来更新队列,从而结束当前歌曲并启动新队列

我也试过使用

musicPlayer.perform(queueTransaction: { (currentQueue) in
    let oldItems = currentQueue.items

    var currentItem: MPMediaItem? = nil
    for (i, item) in oldItems.enumerated() {
        if i == musicPlayer.indexOfNowPlayingItem {
            currentItem = item
            continue
        }

        currentQueue.remove(item)
    }

    currentQueue.insert(queue, after: currentItem)
}, completionHandler: { (newQueue, error) in
    if let error = error {
        print("there was an error updating the queue", error)
        return
    }

    print("===  NEW QUEUE  ===")  //insert does not work
    for item in newQueue.items {
        print("  -", item.title ?? "[No Title]")
    }
})
但正如你从这个问题中所知道的:


队列的insert after item函数似乎不起作用(我还尝试将item设置为nil,这有时会删除当前项并将队列设置为nothing)。我还知道
musicPlayer.prepend([queue])
,它将在当前播放的项目之后添加新的队列,但我还必须从内存中删除上一个队列,这样上一个队列的长度不会超过300首歌曲。我还尝试在队列事务中使用<代码>预置< /代码>函数,但有时歌曲会在中间停止,音乐播放器会将<代码>当前播放项< /代码>设置为零。我真的希望有人知道这个问题的答案,因为我已经遇到这个问题超过4天了,我似乎找不到一个能100%工作的解决方案。

MPMusicPlayerController
(及其相关子类)使得无缝管理这样的队列非常困难。如果我没记错的话,您甚至无法将重复的
MPMediaItem
对象添加到队列中,从Control Center点击播放媒体实际上会启动音乐应用程序,而不是您自己的。本质上,你的应用程序只能充当音乐播放体验的外壳,而音乐应用程序正在完成所有繁重的工作

根据您的需求,您可能有另一种选择,尽管有一些折衷。
AVFoundation
框架提供 而且,这使得管理队列更加容易,并提供了更高级的播放选项。但是,您只能播放下载的、无DRM的内容(即苹果音乐中的歌曲将无法播放)

设置您的播放器:

let audioPlayer = AVQueuePlayer()

// Play next song in queue.
NotificationCenter.default.addObserver(self, selector: #selector(didPlayToEndTime), name: .AVPlayerItemDidPlayToEndTime, object: nil)

// Recover from failed playback.
NotificationCenter.default.addObserver(self, selector: #selector(failedToPlayToEndTime(_:)), name: .AVPlayerItemFailedToPlayToEndTime, object: nil)

// Resume music after interruptions.
NotificationCenter.default.addObserver(self, selector: #selector(handleAudioSessionInterruption(_:)), name: .AVAudioSessionInterruption, object: AVAudioSession.sharedInstance())
在队列中插入新项目:

let media = MPMediaQuery.songs()
let mediaItem: MPMediaItem = media.items.first!

// MPMediaItem objects stored in iCloud or from Apple Music
// will not have a URL, therefore, they cannot be played.
guard let assetURL: URL = mediaItem.assetURL else { return }

let playerItem = AVPlayerItem(url: assetURL)
playerItem.seek(to: kCMTimeZero)
audioPlayer.insert(playerItem, after: nil)
在我的音乐播放器应用程序中,我保留了一个
媒体阵列
,使重新排序、插入和删除媒体变得非常简单,并保留了一个索引来跟踪当前播放的曲目。然后,我将媒体一次传递到一个或两个
AVQueuePlayer
,这样我就不必在插入/删除媒体时弄乱它的API