In SwiftUI I implemented AVPlayerLooper.
When the URL changes that is passed to the view, it should "recreate" the player aka loading the new url
The looping works but it doesn't update the video on URL change. Apparently the UIView url set {} gets called with the correct newValue but for some reason it does not have any effect on the video. Is SwiftUI caching the player or something?
import SwiftUI
import AVKit
import AVFoundation
struct PlayerView: UIViewRepresentable {
var url: URL
private let player: LoopingPlayerUIView
init(url: URL) {
self.url = url
self.player = LoopingPlayerUIView(frame: .zero)
}
func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PlayerView>) {
self.player.url = url
}
func makeUIView(context: Context) -> UIView {
return player
}
}
class LoopingPlayerUIView: UIView {
private var playerLayer = AVPlayerLayer()
private var playerLooper: AVPlayerLooper?
private var player: AVQueuePlayer = AVQueuePlayer()
var url: URL {
set {
self.playerLayer.removeFromSuperlayer()
self.playerLayer = AVPlayerLayer()
let asset = AVAsset(url: newValue)
let item = AVPlayerItem(asset: asset)
// Setup the player
self.player = AVQueuePlayer()
self.playerLayer.player = self.player
playerLayer.videoGravity = .resizeAspectFill
layer.addSublayer(self.playerLayer)
// layer.addSublayer(playerLayer)
// Create a new player looper with the queue player and template item
self.playerLooper = AVPlayerLooper(player: player, templateItem: item)
// Start the movie
player.play()
}
get {
fatalError()
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(frame: CGRect) {
super.init(frame: frame)
}
override func layoutSubviews() {
super.layoutSubviews()
playerLayer.frame = bounds
}
}