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

Cen*_*Guy 5 mpmusicplayercontroller ios swift

我真的很想找出解决办法,并且在互联网上看了都没找到答案。如您所知,Spotify和Apple Music本身的音乐应用程序使用户即使在收听歌曲时也可以重新排列上一个队列。我还无法弄清楚该怎么做。我希望能够完全重新排列队列,包括在上一个队列中添加,删除和移动歌曲。我尝试了各种方法,例如

musicPlayer.setQueue([queue])
Run Code Online (Sandbox Code Playgroud)

但这需要我调用musicPlayer.prepareToPlay()后记以更新队列,该队列将结束当前歌曲并启动新队列。

我也尝试过使用

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]")
    }
})
Run Code Online (Sandbox Code Playgroud)

但您可能从以下问题中知道: MPMusicPlayerControllerMutableQueue插入Apple Music歌曲不起作用

插入项目后插入功能似乎不起作用(我也尝试将项目设置为nil,这有时会删除当前项目并将队列设置为空)。我还知道musicPlayer.prepend([queue])哪个队列将在当前播放项目之后添加新队列,但是我还必须从内存中删除前一个队列,因此上一个队列最终不会超过300首歌曲。我也尝试过prepend在队列事务中使用该函数,但有时歌曲会在中间停止,而音乐播放器会将设置nowPlayingItem为nil。我真的希望有人知道这个问题的答案,因为我已经有4天以上的时间了,而我似乎找不到100%可能有效的解决方案。

gom*_*lon 4

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

根据您的要求,您可能还有另一种选择,尽管需要做出一些妥协。该AVFoundation框架提供了 AVPlayerAVQueuePlayer,可以更轻松地管理队列并提供更高级的播放选项。但是,您只能播放下载的、无 DRM 的内容(即无法播放 Apple Music 中的歌曲)。

设置你的播放器:

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())
Run Code Online (Sandbox Code Playgroud)

在队列中插入新项目:

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)
Run Code Online (Sandbox Code Playgroud)

在我的音乐播放器应用程序中,我保留了一个Array媒体,以便非常简单地重新排序、插入和删除媒体,并保留一个索引来跟踪当前播放的曲目。然后,我一次将媒体传递给AVQueuePlayer一两个媒体,这样我就不必弄乱用于插入/删除媒体的 API。