Avplayer AVPlayerItemDidPlayToEndTime通知未向观察者发送消息

时间:2018-08-02 07:07:17

标签: ios swift avplayer nsnotification

我正在使用AVQueuePlayer播放远程音频文件列表。我想默认实现全部重复。

我的方法是,我正在观察AVPlayerItemDidPlayToEndTime通知,并在完成播放后将playerItem添加到队列的后面。

nextAudio(notification: Notification)根本没有运行。在这种或更好的方法上需要帮助,以实现无限游戏。

func playAudio(_ items: [AVPlayerItem]) {

    let avPlayerVC = AVPlayerViewController()
    let player = AVQueuePlayer(items: items)
    player.actionAtItemEnd = .pause
    avPlayerVC.player = player

    for item in items {
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(FilesViewController.nextAudio(notification:)),
                                               name: .AVPlayerItemDidPlayToEndTime, object: item)
    }

    present(avPlayerVC, animated: true) {
        self.player.play()
    }
}

@objc func nextAudio(notification: Notification) {
    debugPrint("nextAudio was called")
    guard player != nil else { return }
    debugPrint("AVPlayerItemDidPlayToEndTime notif info  \(notification.userInfo)")
    if let currentItem = notification.userInfo!["object"] as? AVPlayerItem {
        currentItem.seek(to: kCMTimeZero)
        self.player.advanceToNextItem()
        self.player.insert(currentItem, after: nil)
    }
}

2 个答案:

答案 0 :(得分:0)

我确定您已经弄明白了,但是我遇到了自己并决定回答:

当您指定通知对象时,它似乎未交付(顺便说一句,应该是正确的方式)。可能是iOS中的错误...

您需要通过nil

NotificationCenter.default.addObserver(self, selector: #selector(videoDidPlayToEnd), name: .AVPlayerItemDidPlayToEndTime, object: nil)

然后,您应该在方法中检查通知对象的对象是您的播放器项目。文档实际上是不一致的,因为Apple声明通知的对象是AVplayer但它是AVPlayerItem

@objc
    private func videoDidPlayToEnd(_ notification: Notification) {
        guard let playerItem = notification.object as? AVPlayerItem, let urlAsset = playerItem.asset as? AVURLAsset else { return }
    gpLog("Sender urlAsset: \(urlAsset.url.absoluteString)")
        // Compare an asset URL.
    }

答案 1 :(得分:0)

感谢@Lukasz的出色回答!我在多个视频在错误的时间触发通知时遇到了问题。您的回答帮助我解决了问题。

如果有人在寻找如何与 SwiftUI 结合使用的示例,这是我的以下代码:

首先创建一个播放器:

import SwiftUI
import AVKit

struct VideoPlayer : UIViewControllerRepresentable {

func makeCoordinator() -> VideoPlayer.Coordinator {
    return VideoPlayer.Coordinator(parent1: self)
}

@Binding var didFinishVideo : Bool
@Binding var player : AVPlayer
var play: Bool
var loop: Bool
var videoName: String
var controller = AVPlayerViewController()

func makeUIViewController(context: UIViewControllerRepresentableContext<VideoPlayer>) -> AVPlayerViewController {
    controller.player = player
    controller.showsPlaybackControls = false
    controller.videoGravity = .resize
    NotificationCenter.default.addObserver(context.coordinator, selector: #selector(context.coordinator.playerDidFinishPlaying(_:)), name: .AVPlayerItemDidPlayToEndTime, object: nil)
    return controller
}

func updateUIViewController(_ uiViewController: AVPlayerViewController, context: UIViewControllerRepresentableContext<VideoPlayer>) {
    if play {
        player.play()
    }
}

class Coordinator : NSObject{
    var parent : VideoPlayer
    init(parent1 : VideoPlayer) {
        parent = parent1
    }

    @objc func playerDidFinishPlaying(_ notification: Notification) {
        guard let playerItem = notification.object as? AVPlayerItem, let urlAsset = playerItem.asset as? AVURLAsset else { return }
        print("Sender urlAsset: \(urlAsset.url.absoluteString)")

        if urlAsset.url.absoluteString.contains(parent.videoName) {
            if parent.loop {
                parent.player.seek(to: CMTime.zero)
                parent.player.play()
            } else {
                parent.didFinishVideo = true
            }
        }

    }

}
}

您可以使用它来创建多个视频,如下所示:

import SwiftUI
import AVKit

struct ExampleVideo: View {
    @Binding var didFinishVideo : Bool
    var play: Bool
    @State private var player = AVPlayer(url: URL(fileURLWithPath: Bundle.main.path(forResource: "exampleVideoFileName", ofType: "mp4")!))
    var body: some View {
        VideoPlayer(didFinishVideo: $didFinishVideo, player: $player, play: play, loop: false, videoName: "exampleVideoFileName")
    }
}

struct ExampleVideo_Previews: PreviewProvider {
    static var previews: some View {
        CeveraIntroVideo(didFinishVideo: .constant(true), play: true)
    }
}

下面是在加载某些内容后在视图中使用它的示例:

struct IntroScreens: View {

@State var loadingComplete = false
@State var didFinishVideo = false

var body: some View {
        ZStack{
            ExampleVideo(didFinishVideo: $didFinishVideo, play: loadingComplete)
                .zIndex(loadingComplete ? 3 : 0)
                .animation(Animation.easeInOut(duration: 1))
        }
    }
}