iOS 14 brought AVKit
to the world of SwiftUI
with the introduction of VideoPlayer
view. VideoPlayer
displays content of an AVPlayer
instance. View
is defined inside AVKit
framework and lets us play videos natively in SwiftUI
without the need of porting functionality over from UIKit
.
VideoPlayer
takes player as an initialization parameter, which is an instance of AVPlayer.
Let’s start with an example. We will begin with the import of AVKit framework.
import AVKit
Videos can be played from bundle or from a url. We will start by playing video from bundle.
We can download sample videos from pexels.com
https://www.pexels.com/videos/
Import video and make sure that we have copy item if needed, create folder reference and add to targets checked.
Ideally, you would want to import videos in a folder, maybe create a Resources folder.
Now, all we gotta do is create VideoPlayer
and AVPlayer
instance to play this video.
import AVKitstruct DevTechieVideoPlayerExample: View {
var body: some View {
VStack {
Text("DevTechie")
.font(.title3)
VideoPlayer(player: AVPlayer(url: Bundle.main.url(forResource: "sample", withExtension: "mp4")!))
}
}
}
Note: VideoPlayer view comes with bunch of controls out of the box.
Since AVPlayer
takes URL
as the parameter, we can easily replace the video link from local to remote location and stream the video via remote url. All we need to do, is provide a url to the video.
We will use another video from Pexels by copying its url:
https://www.pexels.com/video/10167684/download/
Our code will look like this:
import AVKitstruct DevTechieVideoPlayerExample: View {
var body: some View {
VStack {
Text("DevTechie")
.font(.title3)
VideoPlayer(player: AVPlayer(url: URL(string: "https://www.pexels.com/video/10167684/download/")!))
}
}
}
VideoPlayer
has another overload which provides a ViewBuilder
closure to display content as overlay.
Let’s add overlay to our example.
struct DevTechieVideoPlayerExample: View {
var body: some View {
VideoPlayer(player: AVPlayer(url: Bundle.main.url(forResource: "sample", withExtension: "mp4")!)) {
VStack {
Text("Visit DevTechie.com to learn iOS Development")
.font(.largeTitle)
.frame(maxWidth: .infinity)
.background(.thinMaterial)
Spacer()
}
}
.ignoresSafeArea()
}
}
At this point, we have to tap on play button when view is loaded but what if we want to auto play the video as soon as view is loaded and video is ready to be played. We can do all that with a simple modification.
We just gotta take out AVPlayer
instance into a property and use the instance to call predefined functions to play the video.
let player = AVPlayer(url: URL(string: "https://www.pexels.com/video/10167684/download/")!)
We will call player.play()
inside onAppear
struct DevTechieVideoPlayerExample: View {
let player = AVPlayer(url: URL(string: "https://www.pexels.com/video/10167684/download/")!)
var body: some View {
VStack {
Text("DevTechie")
.font(.title3)
VideoPlayer(player: player)
}
.onAppear {
player.play()
}
}
}
Playing video is great but what if we want to be notified when our video ends. We can do that by observing AVPlayer’s
notification. Anytime current video ends, AVPlayer
posts a notification
in NotificationCenter
and we can observe that to act upon it. We can either replay the video or start playing another video.
Let’s update our code to replay the video when it ends.
We will start by creating a publisher
to observe AVPlayerItemDidPlayToEndTime
notification.
let videoEnded = NotificationCenter.default.publisher(for: NSNotification.Name.AVPlayerItemDidPlayToEndTime)
We will use onReceive
observer to receive the notification
to reset player’s seek
time to zero and play
the video again.
struct DevTechieVideoPlayerExample: View {
let player = AVPlayer(url: URL(string: "https://www.pexels.com/video/8759455/download/")!)
let videoEnded = NotificationCenter.default.publisher(for: NSNotification.Name.AVPlayerItemDidPlayToEndTime)
var body: some View {
VStack {
Text("DevTechie")
.font(.title3)
VideoPlayer(player: player)
}
.onAppear {
player.play()
}
.onReceive(videoEnded) { _ in
player.seek(to: .zero)
player.play()
}
}
}