@ WWDC 19
import AVKit
// ์ค์ ๋ก๋ url ์์ฑ ํ ๋ฃ์ด์ค์ผ ํจ ๊ตฌ๋ผ์์ด ์์ ์จ ํฅ
// 1) Create an AVPlayer
let player = AVPlayer(url: "https://my.example.video.m3u8")
// 2) Create an AVPlayerViewController
let playerViewController = AVPlayerViewController()
playerViewController.player = player
// 3) Show it
present(playerViewController, animated: true)
- Extends
AVPlayerViewControllerDelegate
- Notifies delegate when beginning or ending full screen presentation
@available(iOS 12.0, *)
func playerViewController(_ playerViewController: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator)
func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator)
// Implementing AVPlayerViewControllerDelegate's full screen callbacks
func playerViewController(_ playerViewController: AVPlayerViewController, willBeginFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animate(alongsideTransition: { (context) in
// Add coordinated animations
}) { (context) in
if context.isCancelled {
// Still embedded inline
} else {
// Presented full screen
// Take strong reference to playerViewController if needed
}
}
}
- Keep embeded player view controller alive when full screen (ํ์คํฌ๋ฆฐ์ผ๋ก ๋์ ๋๋ฐ ์๋ ํ๋ ์ด์ด๊ฐ ์ฌ๋ผ์ง๋ฉด ์ ๋๊ฒ ์ง?!)
- Deallocating will stop full screen playback
- Okay to be offscreen or removed from superview / parent
- Use delegate to restore playerViewController or retarget animation
func playerViewController(_ playerViewController: AVPlayerViewController, willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
// If scrolled away, update playerViewController's layout here
}
- Track full screen presentation state with
AVPlayerViewControllerDelegate
- Do not rely on
viewWillAppear(_:)
and friends
- Do not rely on
- Works for both embedded and full screen presentations
- Keep embedded player view controller alive when full screen
- Can retarget dismissal animation when embedding inline
- Exact same API as on iOS
- Picture-in-picture support
- Including AVPictureInPictureController (also for AppKit)
- And AVPlayerView, for AppKit-based apps
- Touch Bar, keyboard, and Now Playing support
- Audio and Airplay routing
- Available in macOS 10.15
: ์ ๊ธ ํ๋ฉด์ ํ์๋๋ ํ๋ ์ด์ด ์์ง? ๊ทธ๋ฐ ๋ฐ์ ์ ๋ณด๋ฅผ ์ ๋ณด์ฌ์ฃผ๋ ค๋ฉด ๋ฉํ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํด์ผ ๋ผ.
- Supplement missing metadata
- Title, artwork, and more
- Same API as tvOS
@available(iOS 12.0, *)
extension AVPlayerItem {
open var externalMetadata: [AVMetadataItem]
}
- Interactive dismissals
- Landscape support for portrait-only apps
- Keyboard and Touch Bar support
- Now playing management
- Automatic video zoom
- Set
showsPlaybackControls
tofalse
- Present modally
- Add controls to
contentOverlayView
- For the best user experience, you should:
- Override UIViewController methods for status bar, home indicator
- Pass unhandled touches through your view
- Let AVKit handle double-tap for video zoom
- Full screen callbacks
- AVPlayerViewController in iPad apps for the Mac
- Plus picture-in-picture support for AppKit-based apps
- External metadata
- Improved support for custom controls
-
Covers
UIWindowScene
coordinate -
Use cases:
- Splash screen
- Full screen playback
-
Underneath your UI
-
No interaction playback controls
-
No need to hide status bar or home indicator
-
Possibly looping
-
Video should always fill screen
-
For video with alpha, custom background color
-
Audio is secondary
-
Add as child:
parent.addChild(playerViewController) parent.view.addSubview(playerViewController.view) // Or other UIView insertion API playerViewController.didMove(toParent: parent)
-
Remove from parent:
playerViewController.willMove(toParent: nil) playerViewController.view.removeFromSuperview() playerViewController.removeFromParent()
-
Disable playback controls:
playerViewController.showsPlaybackControls = false
-
Make video fill entire screen:
playerViewController.videoGravity = .resizeAspectFill
-
Set background color (if needed):
playerViewController.view.backgroundColor = .clear // Or any other UIColor
-
Disable
AVPlayer.allowsExternalPlayback
-
Configure
AVAudioSession
for secondary media playback- Use
.ambient
category
- Use
-
Observe
AVAudioSession.silenceSecondaryAudioHintNotification
- Honor
AVAudioSession.secondaryAudioShouldBeSilenceHint
- Honor
- Present modally
- Use the default
modalPresentationStyle
<- iOS 13์์ default๊ฐ automatic์ด๋๊น ๊ฑ default ์ฐ๋! - Do not set
AVPlayerViewController.videoGravity
- Use
AVPlayerViewControllerDelegate
to track full screen presentation state- Do not rely on
viewWillAppear(_:)
and friends
- Do not rely on
- Set up
AVPlayerItem
before buffering- Set
AVPlayer.rate
for setting item
- Set
- Observe
AVPlayer.status
andAVPlayerItem.status
- Don't begin playback until status is
.readyToPlay
- Check
error
property when staus is.failed
- Rebuild AVFoundation object if
.mediaServicesWereReset
- Rebuild AVFoundation object if
- Don't begin playback until status is
- Enable
AVPlayer.usesExternalPlaybackWhileExternalScreenIsActive
- Configure
AVAudioSession
for.playback
-
Be prepared to begin and end full screen playback
- Track state using
AVPlayerViewControllerDelegate
- Keep strong reference to embedded
AVPlayerViewController
when full screen - Retarget dismissal animations when ending full screen presentation
- Track state using
-
Leave
modalPresentationStyle
as.fullScreen
-
Can style embedded content without impacting full screen:
videoGravity
view.layer.cornerRadius
,cornerCurve
, andmaskedCorners
view.backgroundColor
-
For automatically entering and exiting full screen:
entersFullScreenWhenPlaybackBegins
exitsFullScreenWhenPlaybackEnds
-
Adopt UIViewController containment API
-
Add as child:
parent.addChild(playerViewController) containerView.addSubview(playerViewController.view) // Don't put views on top playerViewController.didMove(toParent: parent)
-
Remove from parent:
playerViewController.willMove(toParent: nil) playerViewController.view.removeFromSuperview() playerViewController.removeFromParent()
-
Use
.contentOverlayView
<- ์ฝ๊ฐ ๋ด๊ฐ ์ฐพ๋ ๋๋์ฐ, ์ข ๋ ๊ณต๋ถํด ๋ณด์.- Okay to use before setting player or player item
-
Observe
.isReadyForDisplay
- Returns
true
when first frame is ready
let token = pvc.observe(\.isReadyForDisplay, options: [.initial]) { [weak self] in if observed.isReadyForDisplay { // Hide any poster frame or placeholder } }
- Returns
-
Configure AVAudioSession for
.playback
-
Add background audio mode entitlement in Xcode
-
Don't pause playback when entering background
- Picture-in-picture may be starting!
-
If you must pause, wait until in background
- Only if picture-in-picture hasn't started
- Pre-iOS 13:
UIApplicationStateBackground
- iOS 13 and later:
UISceneActivationStateBackground
-
Track state using
AVPlayerViewControllerDelegate
-
Application can stop picture-in-picture
- Toggle
AVPlayerViewController.allowsPictureInPicturePlayback
- Toggle
-
Be prepared for dismissal when starting
- AVKit prevents deallocation while active
-
Always restore user interface when requested by user
// Restoring from picture-in-picture using AVPlayerViewControllerDelegate func playerViewController(_ playerViewController: AVPlayerViewController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) { presentingViewController.present(playerViewController, animated: true) { // Must invoke completionHandler completionHandler(true) } }
tvOS ๋ด์ฉ์ ์ ๋ฆฌ๋ ๋ฑํ ์ ๋ฆฌํ์ง ์๊ฒ ๋ค!