使用VideoPlayer包播放视频:https://github.com/wxxsw/VideoPlayer
提供一些可供测试的视频链接,不保证稳定可用哦:
https://vfx.mtime.cn/Video/2019/06/15/mp4/190615103827358781.mp4https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4https://vfx.mtime.cn/Video/2019/06/29/mp4/190629004821240734.mp4https://vfx.mtime.cn/Video/2019/06/27/mp4/190627231412433967.mp4https://vfx.mtime.cn/Video/2019/06/25/mp4/190625091024931282.mp4https://vfx.mtime.cn/Video/2019/06/16/mp4/190616155507259516.mp4https://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 = truevar 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 = truevar 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 VideoPlayerprivate 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 = falsevar 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 inswitch state {case .loading:self.stateText = "Loading..."case .playing(let totalDuration):self.stateText = "Playing!"self.totalDuration = totalDurationcase .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()}}
}
效果: