iosswiftavfoundationavaudiosessionmpremotecommandcenter

MPRemoteCommandCenter - Remote controls on lock screen does not show up


I've implemented two functions in View controller (setupRemoteTransportControls() and setupNowPlaying()) and added one function to AppDelegate, but I'm still unable to see background audio controls of my app on the lock screen and also audio interruption function isn't working. This is the live stream from url, as you can spot on in the code. In the general settings I have added background playing: enter image description here

What I would like to do is to print on the Remote Command Center artist, title and albumArt labes and UIImage (labels an UIImage are taken from my station API) , but i was stuck just displaying the command center. Here is my code:

import UIKit
import AVKit
import MediaPlayer
class ViewController: UIViewController, AVAudioPlayerDelegate {

@IBAction func buttonPressed(_ sender: UIButton){
              if isPlaying {
                   player.pause()
                   sender.setImage(playImage, for: .normal)
              } else {
                   let url = "https://myradio.com/radio.mp3"
                   do {
                        try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.mixWithOthers, .allowAirPlay])
                        try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: [])
                        print("Playback OK")
                        try AVAudioSession.sharedInstance().setActive(true)
                        print("Session is Active")
                   } catch {
                        print(error)
                   }
                   
                   player = AVPlayer(url: URL(string: url)!)
                   player.volume = 1.0
                   player.rate = 1.0
                   player.play()
                sender.setImage(pauseImage, for: .normal)
              }
              
              isPlaying.toggle()
         }


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        overrideUserInterfaceStyle = .light
        setupRemoteTransportControls()
        requestNowPlaying()
        setupNowPlaying()
    }

// Here is the API data downloading part, so i skipped it 


    //Command Center audio controls
    
    func setupRemoteTransportControls() {
        // Get the shared MPRemoteCommandCenter
        let commandCenter = MPRemoteCommandCenter.shared()
        // Add handler for Play Command
        commandCenter.playCommand.addTarget { [unowned self] event in
            if self.player.rate == 1.0 {
                self.player.play()
                return .success
            }
            return .commandFailed
        }

        // Add handler for Pause Command
        commandCenter.pauseCommand.addTarget { [unowned self] event in
            if self.player.rate == 1.0 {
                self.player.pause()
                return .success
            }
            return .commandFailed
        }
    }

    func setupNowPlaying() {
        // Define Now Playing Info
        var nowPlayingInfo = [String : Any]()
        nowPlayingInfo[MPMediaItemPropertyTitle] = "Test"

        if let image = UIImage(named: "Default_albumart") {
            nowPlayingInfo[MPMediaItemPropertyArtwork] = MPMediaItemArtwork(boundsSize: image.size) { size in
                return image
            }
        }
        nowPlayingInfo[MPNowPlayingInfoPropertyIsLiveStream] = true
        

        // Set the metadata
        MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
    }


    func updateNowPlaying(isPause: Bool) {
        // Define Now Playing Info
        let nowPlayingInfo = MPNowPlayingInfoCenter.default().nowPlayingInfo!

        //nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = player.currentTime
        //nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = isPause ? 0 : 1

        // Set the metadata
        MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
    }
    

    
    
//audio interruption
    @objc func handleInterruption(notification: Notification) {
        guard let userInfo = notification.userInfo,
                let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
                let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
                    return
            }

            // Switch over the interruption type.
            switch type {

            case .began:
                print("Interruption began")
                

            case .ended:
               // An interruption ended. Resume playback, if appropriate.

                guard let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt else { return }
                let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
                if options.contains(.shouldResume) {
                    player.play()
                } else {
                    // An interruption ended. Don't resume playback.
                }

            default: ()
            }
        }
    
            
    
}

Here's what I've added in My AppDelegate.swift:

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        application.beginReceivingRemoteControlEvents()
     //    Override point for customization after application launch.
       return true
    }

Solution

  • Remove .mixWithOthers from your category options. I think the reasoning is that only the primary iOS audio app can control the remote screen. .mixWithOthers is for secondary audio apps.