@melaka's answer works great, even in Swift 6 / iOS 18 / 2025 (yes, rapidly moving platform). I think their answer got downvoted because the sample code is a little undercooked, so here's a more complete example.
In this example, it's loading a local resource and looping, but should work with a remote resource, remove the looper, etc.
import SwiftUI
import AVKit
struct VideoPlayer: View {
@State private var player: AVQueuePlayer?
@State private var playerLooper: AVPlayerLooper?
public var resource: String
public var ext: String
var body: some View {
VideoPlayer(player: player)
.onAppear {
DispatchQueue.global(qos: .default).async {
let asset = AVURLAsset(url: Bundle.main.url(forResource: resource, withExtension: ext)!)
let item = AVPlayerItem(asset: asset)
self.player = AVQueuePlayer(playerItem: item)
self.playerLooper = AVPlayerLooper(player: player, templateItem: item)
player.play()
}
}
}
}