Async Video download (like AsyncImage) with AVPlayer?

I’m trying to fetch HLS footage from my firebase storage, and if I directly store the download URL in a variable and use that as my url for AVPlayer, the video plays smoothly. But, when I try to first fetch the url using some asncy methods, the AVPlayer receives a nil value for the url paramater:

enter image description here

This makes sense considering the videoPlayer view is rendered first before the await call to vManager.loadVideos() on the body view goes to completion.

Now, usually I never encountered such issues when loading images from the server because I always used AsyncImage and it automatically handled the image loads. However, how would I go about achieving something similar for my AVPlayer?

My State properties and objects are as follows:

struct RecentCard: View {
    @State private var player = AVPlayer()
    @State private var playToggle: Bool = true
    @State var video: VideoModel
    
    @StateObject var vManager = VideoManager()
    
    var body: some View {
        ZStack(alignment: .leading) {
            videoPlayer
            
            textOverlay
        }
        .frame(maxWidth: .infinity, maxHeight: 220, alignment: .leading)
        .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 20))
        .cornerRadius(20)
        .task {
            await vManager.loadVideos()
            video = vManager.video
        }
    }

Also, note that there’s no issues with fetching the correct URL. I’ve already verified that the URL recieved is the valid. The only issue is the AVPlayer loads before the URL is fetched. I’m also a relatively new iOS developer.

>Solution :

Load the video after the URL has been fetched successfully. Remove your code from .onAppear then add:

.onChange(of: video.videoUrlPath) { newValue in
    guard let url = newValue else {return}
    player = AVPlayer(url: url)
    player.play()
}

Or, you could put that snippet in .task.

Leave a Reply