WWDC Quick Look 💓 By SwiftGGTeam
Explore media metadata publishing and playback interactions

Explore media metadata publishing and playback interactions

Watch original video

Highlight

iOS 16 willMPNowPlayingSessionExtended from tvOS to iPhone and iPad, with the automatic metadata publishing function, developers can make the application’s playback information correctly displayed on the control center, lock screen, Apple Watch and HomePod with just a few lines of code.

Core Content

Now Playing everywhere

When users adjust the volume in the Control Center, they will see the cover and title of the currently playing content. Quickly pause or AirPlay to other devices while locked. There’s also the Now Playing App on Apple Watch, and there’s even an Apple TV remote built-in.

These interfaces all rely on the application to publish metadata correctly. If the metadata is missing or not updated in time, the user experience will be broken - the cover will not be displayed, the progress bar will be inaccurate, and the remote control will not respond.

MPNowPlayingSession unifies multiple platforms

(02:18)

MPNowPlayingSessionPreviously exclusive on tvOS, iOS 16 is officially available. It represents an independent playback session, and an application can have multiple sessions - such as one for the main player and one for picture-in-picture.

The system determines whether an application is eligible to become a Now Playing application based on two conditions:

  1. Register at least one remote command handler 2.AVAudioSessionConfigure as non-mixing category

Automatic release reduces maintenance burden

(07:16)

iOS 16 adds automatic metadata publishing. After opening,MPNowPlayingSessionAutomatically observe player status and update fields such as duration, elapsed play time, and play status in real time. Developers only need to set the title and cover and leave the rest to the system.

Detailed Content

Create a playback session

(04:34)

Single player scenario:

self.session = MPNowPlayingSession(players: [player])

Picture-in-picture scene, two independent sessions:

self.session = MPNowPlayingSession(players: [player])
self.pipSession = MPNowPlayingSession(players: [pipPlayer])

Multiple perspectives and same content scenarios, multiple players in one session:

self.session = MPNowPlayingSession(players: [topLeft, topRight, bottomLeft, bottomRight])

Key points:

  • the sameMPNowPlayingSessionMultiple players within should belong to the same content
  • Multi-session scenarios require manual promotion of active sessions

Switch active session

(04:58)

To switch active sessions when picture-in-picture content is full screen:

self.pipSession.becomeActiveIfPossible { becameActive in
    // After success, pipSession data is populated on the Lock Screen and in Control Center
    // Remote control commands are also routed to pipSession
}

Key points:

  • becomeActiveIfPossibleIt is asynchronous, and the success is confirmed through callback.
  • The system may refuse to switch (if another app is playing)

Respond to remote commands

(05:32)

Play and pause:

self.session = MPNowPlayingSession(players: [player])

self.session.remoteCommandCenter.playCommand.addTarget { event in
    player.play()
    return .success
}

self.session.remoteCommandCenter.pauseCommand.addTarget { event in
    player.pause()
    return .success
}

Fast forward command:

self.session.remoteCommandCenter.skipForwardCommand.preferredIntervals = [15.0]
self.session.remoteCommandCenter.skipForwardCommand.addTarget { event in
    let skipCommand = event as! MPSkipIntervalCommandEvent
    let newTime = CMTimeAdd(
        player.currentTime(),
        CMTimeMakeWithSeconds(skipCommand.interval, preferredTimescale: 1)
    )
    player.seek(to: newTime)
    return .success
}

// Disable fast-forwarding during ads
self.session.remoteCommandCenter.skipForwardCommand.isEnabled = false

Key points:

  • eachMPNowPlayingSessionhave ownMPRemoteCommandCenterExample
  • Register handlers for all applicable commands, unsupported commands can be disabled -preferredIntervalsDefine the number of seconds to fast forward/rewind -MPSkipIntervalCommandEvent.intervalGet the specific skip duration requested by the user
  • Jump commands should be disabled in scenarios such as live streaming

Automatically publish metadata

(07:48)

Set title and cover, and turn on automatic publishing:

let artwork = MPMediaItemArtwork(image: image)
let title = "Magnificent"

playerItem.nowPlayingInfo = [
    MPMediaItemPropertyTitle: title,
    MPMediaItemPropertyArtwork: artwork
]

self.session = MPNowPlayingSession(players: [player])
self.session.automaticallyPublishNowPlayingInfo = true

Key points:

  • nowPlayingInfoThe dictionary is set inAVPlayerItemsuperior -MPMediaItemPropertyTitleSet title -MPMediaItemPropertyArtworkSet the cover, the type isMPMediaItemArtwork
  • automaticallyPublishNowPlayingInfo = trueTurn on automatic publishing
  • The system automatically observes the player and updates the duration, elapsed play time, and play status

Handling inline ads:

let preroll = MPAdTimeRange(
    timeRange: CMTimeRange(
        start: CMTime.zero,
        duration: CMTimeMakeWithSeconds(30, preferredTimescale: 1)
    )
)

playerItem.nowPlayingInfo = [
    MPMediaItemPropertyTitle: title,
    MPMediaItemPropertyArtwork: artwork,
    MPNowPlayingInfoPropertyAdTimeRanges: [preroll]
]

self.session = MPNowPlayingSession(players: [player])
self.session.automaticallyPublishNowPlayingInfo = true

Key points:

  • MPAdTimeRangeMark advertising time slots -MPNowPlayingInfoPropertyAdTimeRangesPass in advertising array
  • Automatic press conferences automatically deduct advertising time and calculate the net playback time

AVKit metadata settings

(11:02)

When using AVKit on tvOS, passexternalMetadataset up:

let path = Bundle.main.path(forResource: "poster", ofType: "jpg")!
let posterData = FileManager.default.contents(atPath: path)!

let artwork = AVMutableMetadataItem()
artwork.identifier = .commonIdentifierArtwork
artwork.value = posterData as NSData
artwork.dataType = kCMMetadataBaseDataType_JPEG as String
artwork.extendedLanguageTag = "und"

let title = AVMutableMetadataItem()
title.identifier = .commonIdentifierTitle
title.value = "Magnificent" as NSString
title.extendedLanguageTag = "und"

playerItem.externalMetadata = [artwork, title]

Key points:

  • AVMutableMetadataItemUsed to build metadata items -identifierSpecify the metadata type,.commonIdentifierArtworkIndicates cover -valueIt is the actual data, used for the coverNSData, for titleNSString
  • dataTypeIndicate the image format,kCMMetadataBaseDataType_JPEGor_PNG
  • extendedLanguageTaguse"und"(undefined) Ensures all locales are visible
  • AVKit automatically handles remote command and metadata publishing

Manually publish metadata

(12:59)

Not usedMPNowPlayingSessionFallback when:

let artwork = MPMediaItemArtwork(image: image)

let nowPlayingInfo: [String: Any] = [
    MPMediaItemPropertyTitle: title,
    MPMediaItemPropertyArtwork: artwork,
    MPMediaItemPropertyPlaybackDuration: playerItem.duration,
    MPNowPlayingInfoPropertyElapsedPlaybackTime: player.currentTime().seconds,
    MPNowPlayingInfoPropertyPlaybackRate: player.rate
]

MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo

Update elapsed time and playback rate:

var nowPlayingInfo = MPNowPlayingInfoCenter.default().nowPlayingInfo
nowPlayingInfo?[MPNowPlayingInfoPropertyElapsedPlaybackTime] = player.currentTime().seconds
nowPlayingInfo?[MPNowPlayingInfoPropertyPlaybackRate] = player.rate
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo

Key points:

  • Manual publishing requires maintaining all fields by yourself
  • Update metadata when playing/pausing, jumping, switching content
  • There is no need to update the played time periodically, the system will automatically calculate it based on the last update and playback rate
  • useMPNowPlayingInfoCenter.default()shared instance of

Core Takeaways

  • What: Adds full lock screen control support to the podcast app

  • Why it’s worth doing: Users often listen to podcasts while driving or exercising, and lock screen and headphone control are the main modes of interaction.

  • How to get started: CreateMPNowPlayingSession, register play/pause/skipForward/skipBackward command, setnowPlayingInfoContains title, cover, and chapter information

  • What to do: Build a multi-room audio control application

  • Why it’s worth it: Users can control playback on iPhone via HomePod, and metadata publishing makes this cross-device control work seamlessly

  • How to start: Make sureAVAudioSessionTo configure the non-mixing class, register the remote command handler, useMPNowPlayingSessionManage playback status

  • What to do: Develop a video application that supports picture-in-picture

  • Why it’s worth it: Multi-session management allows Now Playing information to always be correct when users switch between picture-in-picture and full screen

  • How to start: Create for main player and picture-in-pictureMPNowPlayingSession, called when switchingbecomeActiveIfPossible

  • What to do: Create a live streaming app

  • WHY IT’S WORTH IT: Live streaming scenarios require disabling certain commands (like fast forward) while keeping other controls available

  • How to start: After registering the command, set it dynamically according to the live broadcast statusisEnabled, disable skip functionality during commercials

Comments

GitHub Issues · utterances