When I try to play video on my Apple Vision Pro simulator using a custom view with an AVPlayerLayer (as seen in my below VideoPlayerView), nothing displays but a black screen while the audio for the video i'm trying to play plays in the background. I've tried everything I can think of to resolve this issue, but to no avail.
import SwiftUI
import AVFoundation
import AVKit
struct VideoPlayerView: UIViewRepresentable {
var player: AVPlayer
func makeUIView(context: Context) -> UIView {
let view = UIView(frame: .zero)
let playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = .resizeAspect
view.layer.addSublayer(playerLayer)
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
if let layer = uiView.layer.sublayers?.first as? AVPlayerLayer {
layer.frame = uiView.bounds
}
}
}
I have noticed however that if i use the default VideoPlayer (as demonstrated below), and not my custom VideoPlayerView, the video displays just fine, but any modifiers I use on that VideoPlayer (like the ones in my above custom struct), cause the video to display black while the audio plays in the background.
import SwiftUI
import AVKit
struct MyView: View {
var player: AVPlayer
var body: some View {
ZStack {
VideoPlayer(player: player)
Does anyone know a solution to this problem to make it so that video is able to display properly and not just appear as a black screen with audio playing in the background?
SOLVED:
It took me literal months to figure this out but alas, there is actually a solution to this problem. If you ever use an AVPlayer in a visionOS app and find that your video is displaying as a black screen whilst the audio plays in the background, use some variant of this implementation below.
The solution: create a custom view for your AVPlayer as is done below
import SwiftUI
import AVKit
// Define a UIView subclass to host the AVPlayerLayer
class PlayerView: UIView {
private var playerLayer = AVPlayerLayer()
// Initialize with an AVPlayer
init(player: AVPlayer) {
super.init(frame: .zero)
playerLayer.player = player
playerLayer.videoGravity = .resizeAspect // Adjust as needed
layer.addSublayer(playerLayer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
playerLayer.frame = bounds
}
}
// UIViewRepresentable wrapper for the PlayerView
struct VideoPlayerView: UIViewRepresentable {
var player: AVPlayer
func makeUIView(context: Context) -> PlayerView {
return PlayerView(player: player)
}
func updateUIView(_ uiView: PlayerView, context: Context) {
// No need to update anything for now; the PlayerView handles resizing
}
}
Then use this custom view in your program wherever needed like this:
struct ContentView: View {
var player: AVPlayer
var body: some View {
VideoPlayerView(player: player)
}
}