11

I'm making an iOS app using Swift 3 in which displaying information about the currently playing item on the lock screen and control center would be nice.

Currently, I'm using the following code to attempt to insert this information into the nowPlayingInfo dictionary. I've also included reference to the VideoInfo class that is used in videoBeganPlaying(_:).

class VideoInfo {
    var channelName: String
    var title: String
}

// ...

var videoInfoNowPlaying: VideoInfo?

// ...

@objc private func videoBeganPlaying(_ notification: NSNotification?) {
    // apparently these have to be here in order for this to work... but it doesn't
    UIApplication.shared.beginReceivingRemoteControlEvents()
    self.becomeFirstResponder()
    guard let info = self.videoInfoNowPlaying else { return }
    let artwork = MPMediaItemArtwork(boundsSize: .zero, requestHandler:
        { (_) -> UIImage in #imageLiteral(resourceName: "DefaultThumbnail") }) // this is filler
    MPNowPlayingInfoCenter.default().nowPlayingInfo = [
            MPMediaItemPropertyTitle: info.title,
            MPMediaItemPropertyArtist: info.channelName,
            MPMediaItemPropertyArtwork: artwork
        ]
    print("Current title: ", MPNowPlayingInfoCenter.default().nowPlayingInfo?[MPMediaItemPropertyTitle])
}

The function is called when it should be, and the print statement executed, outputting Optional("title"). However, the control center and lockscreen do not update their information. Pause/play, and the skip forward button work, as I set them in viewDidLoad() using MPRemoteCommandCenter.

What's going wrong?

EDIT:

As matt pointed out, AVPlayerViewController makes the MPNowPlayingInfoCenter funky. This was my issue. I should have specified that this is the class I am using, not just AVPlayer.

See: https://developer.apple.com/reference/avkit/avplayerviewcontroller/1845194-updatesnowplayinginfocenter

settwi
  • 199
  • 1
  • 1
  • 11

4 Answers4

11

It does work, and you don't need all that glop about the first responder and so on, as you can readily prove to yourself by just going ahead and setting the now playing info and nothing else:

enter image description here

So why isn't it working for you? Probably because you are using some sort of player (such as AVPlayerViewController) that sets the now playing info itself in some way, and thus overrides your settings.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • You ignored the artwork thing... I didn't quite understand the code for that in the question, and I hoped to learn something from the answer :) – Motti Shneor Jul 04 '17 at 16:07
  • Hi @MottiShneor, nice to hear from you! If you're having a specific issue, could you ask it as a separate question? – matt Jul 04 '17 at 21:02
  • For me, this works only on simulator and not on an actual device. On device, some music must be played for Control Center to update :( – Pavel Alexeev Jul 11 '17 at 10:38
  • @PavelAlexeev If no music from your app plays, your app is not the remote target, so it makes sense that the remote interface wouldn't be updated by your app. If you play music from the Music app and switch to your app, it's still the Music app that's the target. – matt Jul 11 '17 at 18:09
  • @matt I'm just using an AVPlayer. But didn't work. So tried this on an empty project just using the above code. What more should I add to get it work? (Like you said to make remote target?) – Varun Jan 04 '18 at 10:35
  • 1
    So, if we use AVPlayerViewController, how do we update the title? However by default (once you enable background mode), the controls show up in the lock screen and respond to pause/play. My only issue is i am not sure how to override the default nowPlayingInfo that AVPlayerViewController sets. – cableload Feb 09 '18 at 20:52
  • The song is playing but why the button on NowPlaying is not update ? – Le Minh Jan 16 '21 at 16:28
5

If you are using AVPlayerViewController, you can specify that the AVPlayerViewController instance doesn't update the NowPlayingInfoCenter:

playerViewController.updatesNowPlayingInfoCenter = false
Thomas Verbeek
  • 2,361
  • 28
  • 30
  • 2
    Once I set this to `false`, the lock screen controls don't even show up. I present `AVPlayerViewController` programatically though, not sure if that makes any difference. – Dávid Pásztor May 30 '18 at 12:31
  • Hey @DávidPásztor did you ever figure that one out? – matt Mar 24 '19 at 17:27
  • @DávidPásztor So we think that if an AVPlayerViewController you can't bend the now playing info center to your own will at all? – matt Mar 25 '19 at 02:38
  • @matt yes, that's the conclusion I have reached – Dávid Pásztor Mar 25 '19 at 09:14
  • @matt, @DávidPásztor It seem I have managed to make it work with `AVPlayerViewController`. When you set `updatesNowPlayingInfoCenter = false` the info center doesn't appear on the simulator but seems to be working on actual devices. Have you tried it on physical devices or only simulators ? – Martin Jun 06 '19 at 16:51
4

2021 and I was still experiencing this issue when using AVPlayerViewController. I'm working on an app that plays both podcast and videos. Now playing info center works correctly with podcast but it doesn't show any info for videos being played using AVPlayerViewController even though I'm setting MPNowPlayingInfoCenter.nowPlayingInfo correctly.

Found a solution watching Now Playing and Remote Commands on tvOS even though I'm not working with tvOS.

Basically, instead of filling the info using MPNowPlayingInfoCenter I set externalMetadata on the AVPlayerItem and it works.

let playerItem = AVPlayerItem(url: data.url)
let title = AVMutableMetadataItem()
title.identifier = .commonIdentifierTitle
title.value = "Title" as NSString
title.extendedLanguageTag = "und"

let artist = AVMutableMetadataItem()
artist.identifier = .commonIdentifierArtist
artist.value = "Artist" as NSString
artist.extendedLanguageTag = "und"

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

playerItem.externalMetadata = [title, artist, artwork]

This code updates now playing info correctly.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Gustavo Conde
  • 927
  • 12
  • 20
2

This caught me out. Found a helpful post regarding this. https://nowplayingapps.com/how-to-give-more-control-to-your-users-using-mpnowplayinginfocenter/

"In order for the show the nowplayinginfo on the notification screen, you need to add this one last piece of code inside your AppDelegate’s didFinishLaunchingWithOptions function."

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
     application.beginReceivingRemoteControlEvents()
}
Adam
  • 171
  • 2
  • 7
  • I don't think it's related to MediaPlayingInfo. It's available since iOS 4 and enable receiving events in AppDelegate method : `remoteControlReceived(with:)` But since iOS 7, you can use MediaPlayer framework instead. (MPRemoteCommandCenter) – vmeyer Mar 03 '23 at 10:46