🙄
[Swift] iOSのVideoPlayerで保存した動画を自動再生せず読み込む
概要
iOSアプリでiPhone内の動画を再生したい。
WKWebView
に読み込ませると、画面表示時に自動再生してしまう…。
WKWebViewConfiguration
のmediaTypesRequiringUserActionForPlayback
を設定してみたけど効かない…。
自前で作るにもAVPlayer
は実装コスト高そう…。
そんなときはAVPlayerViewController
やVideoPlayer
を利用できます。
サンプルコード
1. UIKit で AVPlayerViewController を使う場合
VideoPreviewViewController.swift
import AVKit
import UIKit
class VideoPreviewViewController: UIViewController {
let url: URL
init(url: URL) {
self.url = url
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
let playerViewController = AVPlayerViewController()
let playerItem = AVPlayerItem(url: url)
let player = AVPlayer(playerItem: playerItem)
playerViewController.player = player
playerViewController.showsPlaybackControls = true
self.addChild(playerViewController)
self.view.addSubview(playerViewController.view)
playerViewController.view.translatesAutoresizingMaskIntoConstraints = false
playerViewController.view.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
playerViewController.view.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
playerViewController.view.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
playerViewController.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
}
}
2. SwiftUI で VideoPlayer を使う場合
VideoPreviewView.swift
import AVKit
import SwiftUI
struct VideoPreviewView: View {
private let endPublisher = NotificationCenter.default.publisher(for: NSNotification.Name.AVPlayerItemDidPlayToEndTime)
@State private var isPlaying = false
var url: URL
var body: some View {
VStack {
let player = AVPlayer(url: url)
VideoPlayer(player: player)
.onReceive(endPublisher) { _ in
player.seek(to: CMTimeMakeWithSeconds(0, preferredTimescale: Int32(NSEC_PER_SEC)), toleranceBefore: CMTime.zero, toleranceAfter: CMTime.zero) // player.seek(to: .zero) でもよい
isPlaying = false
}
Button {
if isPlaying {
player.pause()
} else {
player.play()
}
isPlaying.toggle()
} label: {
Image(systemName: isPlaying ? "stop" : "play")
.padding()
}
}
}
}
3. SwiftUI の VideoPlayer を UIKit から使う場合
MyViewController.swift
let videoVC = UIHostingController(rootView: VideoPreviewView(url: url))
self.addChild(videoVC)
self.view.addSubview(videoVC.view)
videoVC.view.translatesAutoresizingMaskIntoConstraints = false
videoVC.view.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true
videoVC.view.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true
videoVC.view.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
videoVC.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
4. UIKit の AVPlayerViewController を SwiftUI から使う場合(URLの外部注入を含む)
UIKitVideoPreviewView.swift
struct UIKitVideoPreviewView: UIViewControllerRepresentable {
@EnvironmentObject private var environment :VideoPlayerEnvironment
typealias UIViewControllerType = VideoPreviewViewController
func makeUIViewController(context: Context) -> VideoPreviewViewController {
return VideoPreviewViewController(url: environment.url)
}
func updateUIViewController(_ uiViewController: VideoPreviewViewController, context: Context) {
// Updates the state of the specified view controller with new information from SwiftUI.
}
}
ContentView.swift
struct ContentView: View {
@EnvironmentObject private var environment :VideoPlayerEnvironment
@State private var isUIKitPresented = false
var body: some View {
VStack {
Button("UIKit") {
isUIKitPresented.toggle()
}
.sheet(isPresented: $isUIKitPresented) {
UIKitVideoPreviewView()
}
}
.padding()
}
}
VideoPlayerEnvironment.swift
class VideoPlayerEnvironment: ObservableObject {
var url = URL(fileURLWithPath: "/Your/Path/To/Video.mp4")
}
VideoPlayerSampleApp.swift
@main
struct VideoPlayerSampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(VideoPlayerEnvironment())
}
}
}
実行結果
UIKit版(4.のやり方で表示)
SwiftUI版
全画面化する左上のボタンはUIKit版だけ出てますね。
VideoPlayer側にも何かオプションが生えているかもしれませんが未調査です。
参考:https://developer.apple.com/documentation/avkit/videoplayer
Discussion