AVPlayer & SwiftUI
Update: Check out part 5 for SwiftUI’s own VideoPlayer view in iOS 14!
This article was written against Xcode 11 beta 3
Note: video playback on the simulator seems to not show the video, just play the audio, so use a real device if necessary!
SwiftUI is brand new in iOS 13 and with the betas now available iOS developers have been diving into it to see what all the fuss is about. But you knew that already, right? You’re already up to speed on SwiftUI and you’re just here to hear about how AVPlayer can be used with it?
If not, a great place to start is Paul Hudson’s brilliant SwiftUI by Example over at hackingwithswift.com. It’s a great starter guide to help you get to grips with SwiftUI and how different it is to UIKit.
What do we need to know first?
Ok so we’re all up to speed now. I’m assuming you’re familiar with how to use AVPlayer in UIKit, if not then you can maybe bumble along with this article or maybe go and find a guide to explain how it all works.
The next guide of note is Apple’s own Creating and Combining Views SwiftUI tutorial. It’s a tutorial covering the basics of SwiftUI, though I skipped through most of it (having used Paul’s guide previously) so can’t comment on much of it! The bit I was after was Section 5: Use UIKit and SwiftUI Views Together.
As you can tell from the title of that section, there are some things that aren’t (yet?) available directly in SwiftUI. Sure you can create Buttons and Stacks and Text views, but MKMapView is their example of something that needs to still be accessed through UIKit. AVPlayerLayer is our example and we can’t really display a video without it. You may like to read through Apple’s tutorial later on, but for now you can follow on below and I’ll explain what needs to be done.
Let’s do some code!
Start off with a new project in Xcode 11, making sure you tick the ‘Use SwiftUI’ checkbox.
Firstly we need a struct that implements UIViewRepresentable, this is our interface from SwiftUI into UIKit:
struct PlayerView: UIViewRepresentable { func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<PlayerView>) {
} func makeUIView(context: Context) -> UIView {
return PlayerUIView(frame: .zero)
}}
The UIViewRepresentable protocol has two functions we need to implement, the most important being makeUIView(context:). This is where we create a UIKit view and it then gets wrapped up into something SwiftUI can use.
The exact purpose of the updateUIView(uiView: context:) function is a bit more of a mystery to me at the moment. Apple’s tutorials seem to use it as an initial setup for the UIView but it gets called when rotating from portrait to landscape so the things they suggest using it for don’t seem appropriate.
This struct can be used like any other SwiftUI View so if you wildly throw the above code into you ContentView.swift (or, maybe, a different file..?) you’ll be able to update your ContentView’s body to this:
var body: some View {
PlayerView()
}
Now you’ll probably have noticed that the PlayerView struct’s makeUIView(context:) function returns a PlayerUIView class, which is a custom class that I’ve yet to mention, so here it is:
class PlayerUIView: UIView { private let playerLayer = AVPlayerLayer() override init(frame: CGRect) {
super.init(frame: frame)
let url = URL(string: “https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8")!
let player = AVPlayer(url: url)
player.play()
playerLayer.player = player
layer.addSublayer(playerLayer)
} required init?(coder: NSCoder) {
fatalError(“init(coder:) has not been implemented”)
} override func layoutSubviews() {
super.layoutSubviews() playerLayer.frame = bounds
}}
This should look familiar to you, simply a UIView with an AVPlayerLayer added to it that fills its bounds as it changes size.
You can throw that into your ContentView.swift (or, gosh, maybe a different file..?) and (so long as you remember to import AVFoundation) you should be ready to go!
I’m certainly no expert at SwiftUI, having only used it for a few hours at this point, and this may not be the perfect way to do this, but it works and hopefully will help out someone who needs to do the same!
If you enjoyed this article you may be interested in the next one:
AVPlayer & SwiftUI Part 2: Player Controls