swiftUI使用VideoPlayer和AVPlayer播放视频

使用VideoPlayer包播放视频:github.com/wxxsw/Video...

提供一些可供测试的视频链接,不保证稳定可用哦:

Swift 复制代码
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

在项目中导入:

arduino 复制代码
import VideoPlayer

如果提示没有这个包:No such module 'VideoPlayer'

需要在项目的通用设置里面添加这个包到项目中:

选中 VideoPlayer 点击 add:

播放在线视频代码

直接使用在线视频url即可播放

Swift 复制代码
    @State private var play: Bool = true

    var body: some View {
        VideoPlayer(url: URL(string: "你的视频URL链接")!, play: $play)
    }

实现的效果:

播放本地视频

把视频添加到项目中,点击File > Add Files to 项目 > 选中要添加的视频,就可以了

然后在项目代码中添加视频:

Swift 复制代码
// 本地文件
let localMp4Url = Bundle.main.url(forResource: "localMp4", withExtension: "mp4")


@State private var play: Bool = true


var body: some View {
    VideoPlayer(url: localMp4Url!, play: $play)
}

实现的效果:

视频控制

在视频上显示播放控制按钮等配置,可以通过给播放器绑定变量来实现控制

Swift 复制代码
//
//  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:

Swift 复制代码
import AVKit
import VideoPlayer

创建一个player:

注意视频链接协议要为https的,http的视频链接需要单独设置

Swift 复制代码
    // 使用状态来跟踪播放状态
    @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引入

Swift 复制代码
    // 加载本地资源
    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的效果:果然是看剧神器,视觉效果还是不错的

可以添加自定义控制:

Swift 复制代码
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()
            }
    }
}

效果:

相关推荐
etsuyou几秒前
Koa学习
服务器·前端·学习
Easonmax16 分钟前
【CSS3】css开篇基础(1)
前端·css
大鱼前端34 分钟前
未来前端发展方向:深度探索与技术前瞻
前端
昨天;明天。今天。40 分钟前
案例-博客页面简单实现
前端·javascript·css
天上掉下来个程小白41 分钟前
请求响应-08.响应-案例
java·服务器·前端·springboot
周太密1 小时前
使用 Vue 3 和 Element Plus 构建动态酒店日历组件
前端
时清云2 小时前
【算法】合并两个有序链表
前端·算法·面试
小爱丨同学2 小时前
宏队列和微队列
前端·javascript
持久的棒棒君2 小时前
ElementUI 2.x 输入框回车后在调用接口进行远程搜索功能
前端·javascript·elementui
2401_857297912 小时前
秋招内推2025-招联金融
java·前端·算法·金融·求职招聘