Search code examples
iosswiftswiftuivideo

SwiftUI Error when playing video when view appears


I have a basic video player that presents videos from a url. When the view appears I call player.play() and in doing so I think it causes the error below. I think I have to wait until the video is fully fetched from the url to try and play it. How can I achieve this?

Main thread blocked by synchronous property query on not-yet-loaded property (PreferredTransform) for HTTP(S) asset. This could have been a problem if this asset were being read from a slow network.

import SwiftUI
import AVKit

struct MainVideoPlayer: View {
   let url: URL
   @State var player = AVPlayer(url: URL(string: "https://www.google.com")!)
   
   var body: some View {
       ZStack {
           VideoPlayer(player: $player)
       }
        .onAppear {
           player = AVPlayer(url: url)
           self.player.play()
        }
   }
}

struct VideoPlayer : UIViewControllerRepresentable {
   @Binding var player : AVPlayer
   
   func makeUIViewController(context: UIViewControllerRepresentableContext<VideoPlayer>) -> AVPlayerViewController {

       let controller = AVPlayerViewController()
       controller.player = player
       controller.showsPlaybackControls = false
       controller.videoGravity = .resizeAspectFill
       return controller
   }
   
   func updateUIViewController(_ uiViewController: AVPlayerViewController, context: UIViewControllerRepresentableContext<VideoPlayer>) { }
}

Solution

  • You could try a different (more modern) approach, using Apple VideoPlayer, such as in this example code:

    Works well for me in my tests. On MacOS 14.3, using Xcode 15, tested on real ios 17 devices (and Previews), macCatalyst and MacOS.

    import Foundation
    import SwiftUI
    import AVKit
     
     
    struct ContentView: View {
        var body: some View {
            MainVideoPlayer(url: URL(string: "https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4")!)
        }
    }
    
    struct MainVideoPlayer: View {
        let url: URL
        @State var player = AVPlayer()
        
        var body: some View {
            VideoPlayer(player: player)
                .frame(height: 300)
                .onDisappear {
                    player.pause()
                }
                .onAppear {
                    player = AVPlayer(url: url)
                    player.play()
                }
        }
    }
    

    See also: VideoPlayer