WWDC Quick Look 💓 By SwiftGGTeam
Deliver a great playback experience on tvOS

Deliver a great playback experience on tvOS

Watch original video

Highlight

Apple redesigned the AVPlayerViewController standard playback interface in tvOS 15. Developers can integrate titles, playback controls, content tags, and contextual operations into the system player, reducing the maintenance cost of custom playback UI.

Core Content

The most difficult part of building a tvOS media app is often not playing the video itself.

The user holds the remote control and wants to open subtitles, switch audio tracks, bookmark the current program, skip the title, and view chapters. In the past, if you only used the basic player, these entries would be scattered in the custom menu. You also have to deal with remote control gestures, focus movement, picture-in-picture, Siri commands, and future system behavior.

This type of custom player can easily compete with the system playback interface. It was clearly recommended in the speech not to add additional gestures to the player, as it would interfere with the standard playback UI and may fail in the future.

Apple redesigned the standard playback interface in tvOS 15.AVPlayerViewControllerContinued responsibility for playback, jump, scan, drag, Siri commands, interstitials, and remote control support. Developers add their own information and operations to it.

The new entrances are concentrated in four places.

Title ViewDisplays the title and subtitle of the current content.Transport Bar ControlsPlace operations such as collections and settings above the progress bar.Content TabsDisplay information, chapters and recommended content in the playback interface.Contextual ActionsDisplay actions such as “Skip the beginning” or “Look back” during a specific period of time.

The user does not have to leave the player. Developers don’t have to re-implement a player shell.

To use these new interfaces, apps must link to the tvOS 15 SDK. Older apps will continue to get tvOS 14’s default playback interface, which is the boundary Apple uses to maintain compatibility.

Detailed Content

Title View: Let the player know what is currently playing

03:08

Title View is located above the transport bar (playback control bar). it starts from the currentAVPlayerItemThe metadata reads the title and subtitle.

The speech mentioned two fields:commonIdentifierTitleandiTunesMetadataTrackSubtitle. If the media file does not have embedded metadata, or you need to supplement the information, you can setAVPlayerItem.externalMetadata

import AVFoundation
import AVKit

func configureTitleView(
    playerItem: AVPlayerItem,
    playerViewController: AVPlayerViewController,
    title: String,
    subtitle: String
) {
    let titleItem = AVMutableMetadataItem()
    titleItem.identifier = .commonIdentifierTitle
    titleItem.value = title as NSString

    let subtitleItem = AVMutableMetadataItem()
    subtitleItem.identifier = .iTunesMetadataTrackSubtitle
    subtitleItem.value = subtitle as NSString

    playerItem.externalMetadata = [titleItem, subtitleItem]
    playerViewController.transportBarIncludesTitleView = true
}

Key points:

  • import AVFoundationintroduceAVPlayerItemand metadata types. -import AVKitintroduceAVPlayerViewController
  • configureTitleViewReceives the current play item and player controller. -AVMutableMetadataItem()Create writable metadata items. -titleItem.identifier = .commonIdentifierTitleCorresponds to the title field used for the Title View in the lecture. -titleItem.value = title as NSStringWrite title text. -subtitleItem.identifier = .iTunesMetadataTrackSubtitleCorresponds to the subtitle field in the speech. -subtitleItem.value = subtitle as NSStringWrite subtitle text. -playerItem.externalMetadataComplete media information with external metadata. -transportBarIncludesTitleView = trueKeep Title View displayed; if you don’t want to display it, you can set it tofalse

Transport Bar Controls: Put common operations into the system playback control bar

04:01

Transport Bar Controls are a set of controls above the progress bar. The system will provide standard controls such as subtitles, audio language, and picture-in-picture.

Apply your own operations viaAVPlayerViewController.transportBarCustomMenuItemsAdd to. it supportsUIActionandUIMenu. The speech also stated thatAVPlayerViewControllerdisplayedUIMenuSupports one level of nesting and can be useddisplayInlineoptions.

import AVKit
import UIKit

func configureTransportBarControls(playerViewController: AVPlayerViewController) {
    let favoriteAction = UIAction(
        title: "Favorites",
        image: UIImage(systemName: "heart")
    ) { _ in
        // Add to favorites
    }

    let normalSpeedAction = UIAction(title: "Normal", state: .on) { _ in }
    let fastSpeedAction = UIAction(title: "Fast") { _ in }

    let speedMenu = UIMenu(
        title: "Speed",
        options: [.displayInline, .singleSelection],
        children: [normalSpeedAction, fastSpeedAction]
    )

    let settingsMenu = UIMenu(
        image: UIImage(systemName: "gearshape"),
        children: [speedMenu]
    )

    playerViewController.transportBarCustomMenuItems = [
        favoriteAction,
        settingsMenu
    ]
}

Key points:

  • import AVKitsupplyAVPlayerViewController
  • import UIKitsupplyUIActionUIMenuandUIImage
  • favoriteActionCreate a favorite operation corresponding to the Favorites example in the lecture. -UIImage(systemName: "heart")Add a system icon to the collection operation.
  • The comment position in the handler executes the business logic of “add to favorites”. -normalSpeedActionandfastSpeedActionIs a menu item. -state: .onMark the currently selected menu item. -speedMenuCreate a Speed ​​menu that corresponds to the Speed ​​submenu in the lecture. -.displayInlineMake submenus appear inline. -.singleSelectionIndicates that only one operation in the same group can be selected. -settingsMenuUse the gear icon to host submenus. -transportBarCustomMenuItemsLeave the custom operations to the system playback interface for display.

05:19

Content Tabs allow the playback interface to carry supplementary information. When the media has metadata,AVPlayerViewControllerThe Info tab is displayed.AVPlayerItemsupplynavigationMarkerGroups, the system displays the Chapters label.

Applications can be passedcustomInfoViewControllersAdd more tags. tvOS 15 replaces the old one with this new propertycustomInfoViewController, because the new interface supports multiple view controllers.

import AVKit
import UIKit

func configureContentTabs(
    playerViewController: AVPlayerViewController,
    customViewController: UIViewController
) {
    customViewController.preferredContentSize = CGSize(width: 0, height: 140)
    customViewController.title = "Recommended"

    playerViewController.customInfoViewControllers = [customViewController]
}

Key points:

  • configureContentTabsReceives player controller and custom content controller. -preferredContentSizeSpecifies the desired height of the content label. -width: 0It means that the focus here is to set the height, and the width is handled by the system layout. -height: 140Corresponds to the height of the example in the lecture snippet. -title = "Recommended"Set the tab title, which will be used to display the tab name. -customInfoViewControllersAdd an array of custom content tags.
  • When multiple labels exist at the same time, the system will calculate the overall height based on the tallest content label.

07:08

If you want to display a group of related videos in Content Tabs, you can use the new content configuration provided by TVUIKit (tvOS UI tool framework).

TVMediaItemContentConfiguration.wideCell()For use with 16:9 media cards. It can set pictures, titles, subtitles, badges and playback progress.

import TVUIKit
import UIKit

func configureMediaCell(cell: UICollectionViewCell) {
    var contentConfiguration = TVMediaItemContentConfiguration.wideCell()
    contentConfiguration.image = UIImage(imageLiteralResourceName: "tanu")
    contentConfiguration.text = "Title"
    contentConfiguration.secondaryText = "Secondary text"
    contentConfiguration.badgeText = "NEW"
    contentConfiguration.badgeProperties.backgroundColor = .systemRed
    contentConfiguration.playbackProgress = 0.75

    cell.contentConfiguration = contentConfiguration
}

Key points:

  • import TVUIKitIntroducing content configuration types for tvOS. -import UIKitintroduceUICollectionViewCellandUIImage
  • configureMediaCellConfigure a collection view cell. -TVMediaItemContentConfiguration.wideCell()Create a 16:9 media card configuration. -imageSet card picture. -textSet the main title. -secondaryTextSet subtitle. -badgeText = "NEW"Display badge text for the card. -badgeProperties.backgroundColor = .systemRedSet the badge background color. -playbackProgress = 0.75Showing 75% viewing progress. -cell.contentConfigurationApply the configuration to the cell.

TVMonogramContentConfiguration: Display characters in the playback interface

07:36

If the content tag shows a person or role, speech is recommended to useTVMonogramContentConfiguration

It is suitable for displaying actor, guest, speaker or character information in an area relevant to the current media.

import TVUIKit
import UIKit

func configureMonogramCell(cell: UICollectionViewCell) {
    var contentConfiguration = TVMonogramContentConfiguration.cell()
    contentConfiguration.image = UIImage(imageLiteralResourceName: "jad")
    contentConfiguration.text = "Jad"

    cell.contentConfiguration = contentConfiguration
}

Key points:

  • TVMonogramContentConfiguration.cell()Create a cell configuration with character avatar style. -imageSet the character picture. -textSet the character name. -cell.contentConfigurationLet the collection view cell use this system style.
  • Both this configuration and the media card configuration serve the list content in Content Tabs.

Contextual Actions: Show actions only at the right time

07:52

Contextual Actions are used for immediate operations during playback. The examples given in the talk are Skip Intro and Recap.

The approach is to setAVPlayerViewController.contextualActions, providing one or moreUIAction. Applications often need to listen to the player time, display operations when the relevant fragment appears, and reset the properties to an empty array when finished.

import AVFoundation
import AVKit
import UIKit

func showSkipIntroAction(
    playerViewController: AVPlayerViewController,
    player: AVPlayer
) {
    let skipIntroAction = UIAction(title: "Skip Intro") { _ in
        let targetTime = CMTime(seconds: 90, preferredTimescale: 600)
        player.seek(to: targetTime)
    }

    playerViewController.contextualActions = [skipIntroAction]
}

func hideContextualActions(playerViewController: AVPlayerViewController) {
    playerViewController.contextualActions = []
}

Key points:

  • import AVFoundationsupplyAVPlayerandCMTime
  • showSkipIntroActionCalled when a suitable fragment appears. -UIAction(title: "Skip Intro")Create a skip intro operation, corresponding to the Skip Intro example in the lecture. -CMTime(seconds: 90, preferredTimescale: 600)Indicates the playback time to jump to. -player.seek(to:)Execute jump. -contextualActions = [skipIntroAction]Show the action in the player. -hideContextualActionsCalled when not needed. -contextualActions = []Hide current context operations.

Minimum tvOS playback practices to follow

08:48

The speech ended with three practical suggestions.

First, don’t add extra gestures to the player. It interferes with the standard playback UI and may not work in future system versions.

Second, fill in the missing metadata. Information such as titles, pictures, and descriptions can beAVPlayerItem.externalMetadatasupply. The Title View and Info tags are populated with this information.

Third, consider enabling Picture in Picture. It lets users switch between full-screen content and picture-in-picture, as well as play videos and use other content simultaneously.

import AVKit

func configurePlaybackExperience(playerViewController: AVPlayerViewController) {
    playerViewController.allowsPictureInPicturePlayback = true
    playerViewController.transportBarIncludesTitleView = true
}

Key points:

  • allowsPictureInPicturePlayback = trueAllows the player to use picture-in-picture capabilities. -transportBarIncludesTitleView = trueKeep the title area displayed.
  • These settings are based onAVPlayerViewControlleron top of the standard playback experience.
  • Gesture, focus and playback controls continue to be handled by the system interface.

Core Takeaways

1. Add the “continue watching” recommendation tag to the video app

  • What to do: Add the Recommended tag to the player to display episodes or related content that the user has not finished watching.
  • Why it’s worth it: Content Tabs allow users to browse recommended content while staying in the playback interface.
  • How ​​to get started: Create a customUIViewController,set uppreferredContentSizeandtitle, then put inAVPlayerViewController.customInfoViewControllers

2. Add chapter navigation to course videos

  • What to do: Display course chapters in the playback interface, and users can jump directly to a certain section.
  • Why it’s worth doing: Mentioned in the speechAVPlayerItem.navigationMarkerGroupsWill cause the system to display the Chapters label.
  • How ​​to start: forAVPlayerItemProvide a chapter marker group and useAVPlayerViewControllerPlay the item.

3. Add a “skip title” button to the episode

  • What to do: Show Skip Intro when the intro appears and hide after the intro ends.
  • Why it’s worth doing: Contextual Actions are specifically used for related operations during playback, and the interaction behavior is consistent with the system focus.
  • How ​​to start: Use the player’s periodic or boundary time observer to monitor the time, and set it when entering the title intervalcontextualActions, set to an empty array after leaving.

4. Add a collection entry to the playback control bar

  • What to do: When users are watching a program, they can directly add the current content to their favorites in the playback control bar.
  • Why it’s worth doing:transportBarCustomMenuItemssupportUIAction, suitable for placing lightweight operations that are strongly related to the current media.
  • How ​​to get started: CreateUIAction(title:image:handler:), add it toplayerViewController.transportBarCustomMenuItems

5. Add guest tab to character interview

  • What to do: Display the list of guests, hosts or characters in this issue in the player.
  • Why it’s worth doing:TVMonogramContentConfigurationProvides character avatar styles, suitable for placement in the collection view of Content Tabs.
  • How ​​to start: Use the collection view to host the character list and set it in the cellTVMonogramContentConfiguration.cell()

Comments

GitHub Issues · utterances