实现类Twitter/X的视频自动播放功能及续播问题求助
问题分析
当前实现中,每个VideoPlayerView都持有独立的VideoPlayerViewModel实例,导致信息流和详情页的同一个视频无法共享播放进度;同时旧视图的播放器未被妥善处理,出现多播放器同时播放导致的音频重叠问题。要实现Twitter/X式的跨页面续播,核心是统一管理视频播放状态与进度,并确保同一时间仅一个播放器处于活跃状态。
解决方案
通过全局单例管理器统一存储所有视频的播放进度,同时控制当前活跃的播放器,实现跨视图的状态共享与播放同步。
修改后代码
1. 全局视频播放状态管理器
import AVKit class VideoPlaybackManager: ObservableObject { static let shared = VideoPlaybackManager() // 存储每个视频URL对应的播放进度 private var playbackProgress: [URL: Double] = [:] // 记录当前正在播放的URL,避免多视频同时播放 private var currentPlayingURL: URL? // 复用播放器实例,减少资源消耗 private var activePlayer: AVPlayer? // 获取指定视频的已保存进度 func getProgress(for url: URL) -> Double? { playbackProgress[url] } // 保存指定视频的播放进度 func saveProgress(_ progress: Double, for url: URL) { playbackProgress[url] = progress } // 获取或复用指定视频的播放器实例 func getPlayer(for url: URL) -> AVPlayer { if let existingPlayer = activePlayer, let asset = existingPlayer.currentItem?.asset as? AVURLAsset, asset.url == url { return existingPlayer } let newPlayer = AVPlayer(url: url) // 恢复已保存的进度 if let progress = getProgress(for: url) { newPlayer.seek(to: CMTime(seconds: progress, preferredTimescale: 600)) } activePlayer = newPlayer return newPlayer } // 更新当前播放的URL,自动暂停之前的视频 func updateCurrentPlayingURL(_ url: URL?) { if let previousURL = currentPlayingURL, previousURL != url { activePlayer?.pause() // 保存之前视频的进度 if let currentTime = activePlayer?.currentTime().seconds { saveProgress(currentTime, for: previousURL) } } currentPlayingURL = url } }
2. 修改ViewModel依赖全局管理器
class VideoPlayerViewModel: ObservableObject { @Published var player: AVPlayer? private let url: URL private let playbackManager = VideoPlaybackManager.shared init(url: URL) { self.url = url player = playbackManager.getPlayer(for: url) } func handleViewAppear() { playbackManager.updateCurrentPlayingURL(url) player?.play() } func handleViewDisappear() { if let currentTime = player?.currentTime().seconds { playbackManager.saveProgress(currentTime, for: url) } player?.pause() // 如果当前播放的是此视频,清空活跃标记 if playbackManager.currentPlayingURL == url { playbackManager.updateCurrentPlayingURL(nil) } } }
3. 调整VideoPlayerView逻辑
import SwiftUI import AVKit struct VideoPlayerView: View { @StateObject private var viewModel: VideoPlayerViewModel init(url: URL) { _viewModel = StateObject(wrappedValue: .init(url: url)) } var body: some View { VStack { if let player = viewModel.player { VideoPlayer(player: player) .onAppear { viewModel.handleViewAppear() } .onDisappear { viewModel.handleViewDisappear() } } } .frame(maxWidth: .infinity, maxHeight: .infinity) } }
关键说明
- 状态共享:通过
VideoPlaybackManager单例存储所有视频的播放进度,信息流和详情页的同一个视频会读取同一份进度数据,实现续播。 - 播放器复用:全局维护一个活跃播放器实例,避免重复创建AVPlayer,减少内存占用,同时彻底解决多播放器同时播放的音频重叠问题。
- 播放同步:切换视图时自动更新当前活跃的视频URL,暂停之前的播放并保存进度,确保同一时间仅一个视频处于播放状态。
注意点
- 如果需要支持多视频同时播放(非Twitter/X模式),可修改
VideoPlaybackManager的逻辑,允许存储多个活跃播放器,但仍需确保切换视图时暂停非当前视图的播放器。 - 若视频URL存在动态变化(如带签名的临时URL),需调整进度存储的键值,改用视频的唯一标识(如帖子ID)代替URL。
内容的提问来源于stack exchange,提问作者user16961399
相关产品推荐
相关产品推荐

