使用VideoPlayer包播放视频:https://github.com/wxxsw/VideoPlayer
提供一些可供测试的视频链接,不保证稳定可用哦:
https://vfx.mtime.cn/Video/2019/06/15/mp4/190615103827358781.mp4
https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4
https://vfx.mtime.cn/Video/2019/06/29/mp4/190629004821240734.mp4
https://vfx.mtime.cn/Video/2019/06/27/mp4/190627231412433967.mp4
https://vfx.mtime.cn/Video/2019/06/25/mp4/190625091024931282.mp4
https://vfx.mtime.cn/Video/2019/06/16/mp4/190616155507259516.mp4
https://vfx.mtime.cn/Video/2019/06/05/mp4/190605101703931259.mp4
安装VideoPlayer
使用spm安装包,直接在xcode项目的依赖包右键,添加包:
在右上角输入包地址:添加到项目中即可
使用VideoPlayer
在项目中导入:
import VideoPlayer
如果提示没有这个包:No such module 'VideoPlayer'
需要在项目的通用设置里面添加这个包到项目中:
选中 VideoPlayer 点击 add:
播放在线视频代码
直接使用在线视频url即可播放
@State private var play: Bool = true
var body: some View {
VideoPlayer(url: URL(string: "你的视频URL链接")!, play: $play)
}
实现的效果:
播放本地视频
把视频添加到项目中,点击File > Add Files to 项目 > 选中要添加的视频,就可以了
然后在项目代码中添加视频:
// 本地文件
let localMp4Url = Bundle.main.url(forResource: "localMp4", withExtension: "mp4")
@State private var play: Bool = true
var body: some View {
VideoPlayer(url: localMp4Url!, play: $play)
}
实现的效果:
视频控制
在视频上显示播放控制按钮等配置,可以通过给播放器绑定变量来实现控制
//
// ContentView.swift
// swiftPro
//
// Created by song on 2024/5/21.
//
import Alamofire
import AVKit
import GIFImage
import Kingfisher
import SwiftUI
import VideoPlayer
private var videoURLs: [URL] = [
URL(string: "https://vfx.mtime.cn/Video/2019/06/29/mp4/190629004821240734.mp4")!,
URL(string: "https://vfx.mtime.cn/Video/2019/06/27/mp4/190627231412433967.mp4")!,
URL(string: "https://vfx.mtime.cn/Video/2019/06/25/mp4/190625091024931282.mp4")!,
URL(string: "https://vfx.mtime.cn/Video/2019/06/16/mp4/190616155507259516.mp4")!,
URL(string: "https://vfx.mtime.cn/Video/2019/06/15/mp4/190615103827358781.mp4")!,
URL(string: "https://vfx.mtime.cn/Video/2019/06/05/mp4/190605101703931259.mp4")!,
]
struct ContentView: View {
// 本地文件
let localMp4Url = Bundle.main.url(forResource: "localMp4", withExtension: "mp4")
// 远程视频
let remoteUrl = URL(string: "https://vfx.mtime.cn/Video/2019/06/15/mp4/190615103827358781.mp4")
// 获取当前播放时间
func getTimeString() -> String {
let m = Int(time.seconds / 60)
let s = Int(time.seconds.truncatingRemainder(dividingBy: 60))
return String(format: "%d:%02d", arguments: [m, s])
}
// 获取视频所有的时间
func getTotalDurationString() -> String {
let m = Int(totalDuration / 60)
let s = Int(totalDuration.truncatingRemainder(dividingBy: 60))
return String(format: "%d:%02d", arguments: [m, s])
}
// 视频列表索引
@State var index = 0
// 播放状态
@State private var play: Bool = true
// 视频播放时间
@State private var time: CMTime = .zero
// 是否自动播放
@State private var autoReplay: Bool = true
// 是否开启声音(mute:沉默的,无声的)
@State private var mute: Bool = false
// 视频播放状态文字提示
@State private var stateText: String = ""
// 总共持续时间
@State private var totalDuration: Double = 0
// 播放速度
@State private var speedRate: Float = 1.2
// 使用状态来跟踪播放状态
@State private var isPlaying = false
var body: some View {
VStack(content: {
// 视频播放控制是通过绑定变量来实现的
VideoPlayer(url: videoURLs[index % videoURLs.count], play: $play, time: $time)
.autoReplay(autoReplay)
.mute(mute)
.speedRate(speedRate)
.onBufferChanged { progress in print("onBufferChanged \(progress)") }
.onPlayToEndTime { print("onPlayToEndTime") }
.onReplay { print("onReplay") }
.onStateChanged { state in
switch state {
case .loading:
self.stateText = "Loading..."
case .playing(let totalDuration):
self.stateText = "Playing!"
self.totalDuration = totalDuration
case .paused(let playProgress, let bufferProgress):
self.stateText = "Paused: play \(Int(playProgress * 100))% buffer \(Int(bufferProgress * 100))%"
case .error(let error):
self.stateText = "Error: \(error)"
}
}
.aspectRatio(1.78, contentMode: .fit)
.cornerRadius(16)
.shadow(color: Color.black.opacity(0.7), radius: 6, x: 0, y: 2)
.padding()
// 视频状态
Text(stateText)
.padding()
// 视频控制:暂停/声音控制/自动重播/后退前进5秒/下一个视频
HStack {
Button(self.play ? "Pause" : "Play") {
self.play.toggle()
}
Divider().frame(height: 20)
Button(self.mute ? "Sound Off" : "Sound On") {
self.mute.toggle()
}
Divider().frame(height: 20)
Button(self.autoReplay ? "Auto Replay On" : "Auto Replay Off") {
self.autoReplay.toggle()
}
}
HStack {
Button("Backward 5s") {
self.time = CMTimeMakeWithSeconds(max(0, self.time.seconds - 5), preferredTimescale: self.time.timescale)
}
Divider().frame(height: 20)
Text("\(getTimeString()) / \(getTotalDurationString())")
Divider().frame(height: 20)
Button("Forward 5s") {
self.time = CMTimeMakeWithSeconds(min(self.totalDuration, self.time.seconds + 5), preferredTimescale: self.time.timescale)
}
}
Button("Next Video") { self.index += 1 }
})
}
}
#Preview {
ContentView()
}
播放效果:
使用AVPlayer
导入AVPlayer:
import AVKit
import VideoPlayer
创建一个player:
注意视频链接协议要为https的,http的视频链接需要单独设置
// 使用状态来跟踪播放状态
@State private var isPlaying = false
// AVPlayer 实例
private let player = AVPlayer(url: URL(string: "https://vfx.mtime.cn/Video/2019/06/15/mp4/190615103827358781.mp4")!)
// 在ui层放入播放器
var body: some View {
VStack {
// 视频播放器控件
VideoPlayer(player: player)
.ignoresSafeArea()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.onAppear {
player.play()
}
}
}
加载本地视频资源:
需要将本地视频资源加载到项目中,然后通过Bundle引入
// 加载本地资源
let player = AVPlayer(url: Bundle.main.url(forResource: "localMp4", withExtension: "mp4")!)
var body: some View {
VideoPlayer(player: player)
.ignoresSafeArea()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.onAppear {
player.play()
}
}
显示效果:
播放也没有问题,视频控制也没有问题,很不错了
ipad的效果:果然是看剧神器,视觉效果还是不错的
可以添加自定义控制:
struct VideoPlayerView: View {
// 使用状态来跟踪播放状态
@State private var isPlaying = false
// AVPlayer 实例
private let player = AVPlayer(url: URL(string: "https://vfx.mtime.cn/Video/2019/06/15/mp4/190615103827358781.mp4")!)
var body: some View {
VStack {
// 视频播放器控件
AVPlayerViewController()
.embed(player: player)
// 添加自定义控制
Button(action: togglePlay) {
Text(isPlaying ? "暂停" : "播放")
}
}
}
// 切换播放状态的方法
func togglePlay() {
isPlaying ? player.pause() : player.play()
isPlaying.toggle()
}
}
extension AVPlayerViewController {
func embed(player: AVPlayer) -> some View {
return VideoPlayer(player: player)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
.onAppear {
player.play()
}
.onDisappear {
player.pause()
}
}
}
效果: