iosswiftswiftuiavkit

Impossible to play video in background with swiftui


I am starting on SwiftUI dev and I tried to create a Signin screen with a video playing in background. The Sign-in screen works fine but now it's time to make it nice.

I found on Internet this class below to play the video but I cannot make it build


import SwiftUI
import AVKit


struct VideoPlayerView: UIViewRepresentable {
    func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<VideoPlayerView>) {
    }
    
    func makeUIView(context: Context) -> UIView {
        return PlayerUIView(frame: .zero)
    }
}

class PlayerUIView: UIView {
    @State var urlLink = Bundle.main.path(forResource: "splash", ofType: "mp4")!
    private let playerLayer = AVPlayerLayer()
    
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
       // guard let filePath = Bundle.main.path(forResource: "splash", ofType: "mp4") else { return }
        
        let player = AVPlayer(url: urlLink)
        //player.actionAtItemEnd = .none
        player.play()
        
        playerLayer.player = player
        playerLayer.videoGravity = .resizeAspectFill
        
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(playerItemDidReachEnd(notification:)),
                                               name: .AVPlayerItemDidPlayToEndTime,
                                               object: player.currentItem)

        layer.addSublayer(playerLayer)
    }
    
    @objc func playerItemDidReachEnd(notification: Notification) {
        if let playerItem = notification.object as? AVPlayerItem {
            playerItem.seek(to: .zero, completionHandler: nil)
        }
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        playerLayer.frame = bounds
    }
}


struct VideoPlayerView_Previews: PreviewProvider {
    static var previews: some View {
        VideoPlayerView()
    }
}

The issue is on let player = AVPlayer(url: urlLink) where it complains that he cannot convert a string to URL.

I drag'n'drop my mp4 video into the assets' folder.

Any idea? I do not look to build a real player just having a video looping in background of my signin screen

Thanks


Solution

  • yes you have to use a different API for that. The current API you are using is only returning the string which is the path to your file. It's not a URL, And for that, you have to replace your code with the below line.

    //Your code 
    `Bundle.main.path(forResource: "splash", ofType: "mp4")!`
    //with 
    ` URL(fileURLWithPath: Bundle.main.path(forResource: "", ofType: "")))
    

    This will give you a URL for your file and you can load it on your AVPlayerLayer.

    Now this is the whole solution you were trying to do.

    import SwiftUI
    import AVKit
    
    struct VideoPlayerView: UIViewControllerRepresentable {
        let videoURL: URL
    
        func makeUIViewController(context: Context) -> AVPlayerViewController {
            let player = AVPlayer(url: videoURL)
            player.isMuted = true
            player.play()
            
            let playerViewController = AVPlayerViewController()
            playerViewController.player = player
            
            NotificationCenter.default.addObserver(
                forName: .AVPlayerItemDidPlayToEndTime,
                object: player.currentItem,
                queue: nil
            ) { _ in
                player.seek(to: .zero)
                player.play()
            }
            
            return playerViewController
        }
        
        func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) {
        }
    }
    
    struct ContentView: View {
        var body: some View {
            ZStack {
                VideoPlayerView(videoURL: URL(fileURLWithPath: Bundle.main.path(forResource: "Video", ofType: "mp4")!))
                    .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
                
                VStack {
                    Text("Some UI elements")
                        .foregroundColor(.white)
                        .background(Color.black)
                        .font(.title)
                                
                }
                .padding()
            }
        }
    }
    

    Attaching working video. enter image description here