CPNowPlayingTemplate.shared() - Now having errors?

So I am using the sample code that was provided by Apple in 2020, however it seems that the code is no longer correct.

As I am getting the following error:

Cannot call value of non-function type 'CPNowPlayingTemplate'
Remove '()'


However when I do remove it the app fires up fine, minus the now playing information.

I am wondering what do I need to do to get the now playing information which my iOS app does display, to send over to the CarPlay screen.

I was told - "All you need is this template and then apple does everything in the background."

Clearly that's wrong, because Apple would never make something be so easy.

So I know I am going to have to add buttons, album art extra extra. But I don't know how to go about this, as I normally use SwiftUI.

Code Block import Foundationimport CarPlayclass CarPlaySceneDelegate: UIResponder, CPTemplateApplicationSceneDelegate {      func templateApplicationScene(_ templateApplicationScene: CPTemplateApplicationScene,                                  didConnect interfaceController: CPInterfaceController) {        if #available(iOS 14.0, *) {        let nowPlayingTemplate = CPNowPlayingTemplate.shared         let rateButton = CPNowPlayingPlaybackRateButton() {_ in            // Change the playback rate!                    }                nowPlayingTemplate.updateNowPlayingButtons([rateButton])      } else {          // Fallback on earlier versions      }        }}

Side note: the sooner Apple allows SwiftUI to take over this the better.

So key questions:

  1. How to print song information on this screen

  2. How to add pause and play button.

I have included my MediaPlayer.swift file so you can see I use  MPNowPlayingInfoCenter


import SwiftUI

//import Foundation

import AVFoundation

import MediaPlayer

import AVKit



struct NowPlayingData: Codable , Identifiable  {

  var id,artist,song,cover:String



  private enum CodingKeys : String, CodingKey {

    case id = "_id", artist , song , cover

  }

}



class MusicPlayer {

static let shared = MusicPlayer()

static var mediatype = ""

static var artist = ""

static var song = ""

static var cover = ""

static var uuid = UIDevice.current.identifierForVendor?.uuidString





var player: AVPlayer?

let playerViewController = AVPlayerViewController()



    

    

    

    func gettype(completion: @escaping (String) -> Void){

          

            completion(MusicPlayer.mediatype)

       

      }

      

      func getPodCastPlayerNP(completion: @escaping (NowPlayingData) -> ()) {

       // Timer.scheduledTimer(withTimeInterval: 15, repeats: true) { (timer) in

          let songdata = "{\"_id\": \"1\",\"song\": \"\(MusicPlayer.song)\",\"artist\": \"\(MusicPlayer.artist)\", \"cover\": \"\(MusicPlayer.cover)\"}"

          let data: Foundation.Data = songdata.data(using: .utf8)!

          

          let podcast = try! JSONDecoder().decode(NowPlayingData.self, from: data)

                

                         //print(data!)

                        // let episode = podcast.programs

                        DispatchQueue.main.async{

                            // The array is stored under programs now

                          //print(podcast)

                          completion(podcast)

                        }

         // }

      }



    func startBackgroundMusic(url: String, type:String) {

     

        MusicPlayer.mediatype = String(type)

        

        //let urlString = "http://stream.radiomedia.com.au:8003/stream"

        let urlString = url+"?uuid="+MusicPlayer.uuid!

        print(urlString)

        guard let url = URL.init(string: urlString) else { return }



        let playerItem = AVPlayerItem.init(url: url)

        player = AVPlayer.init(playerItem: playerItem)

        

      

        do {



            try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.duckOthers, .defaultToSpeaker, .mixWithOthers, .allowAirPlay])

            print("Playback OK")

           // let defaults = UserDefaults.standard

           // defaults.set("1", forKey: defaultsKeys.musicplayer_connected)

            try AVAudioSession.sharedInstance().setActive(true)

            print("Session is Active")

        } catch {

           // let defaults = UserDefaults.standard

          //  defaults.set("0", forKey: defaultsKeys.musicplayer_connected)

            print(error)

        }



         #if targetEnvironment(simulator)



        self.playerViewController.player = player

        self.playerViewController.player?.play()

        print("SIMULATOR")



         #else



        self.setupRemoteTransportControls()

        player?.play()



        #endif

        



    }

    

    

    func startBackgroundMusicTwo() {



        

        let urlString = "http://stream.radiomedia.com.au:8003/stream"

        //let urlString = url

        guard let url = URL.init(string: urlString) else { return }



        let playerItem = AVPlayerItem.init(url: url)

        player = AVPlayer.init(playerItem: playerItem)

        

      

        do {



            try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default, options: [.duckOthers, .defaultToSpeaker, .mixWithOthers, .allowAirPlay])

            print("Playback OK")

           // let defaults = UserDefaults.standard

           // defaults.set("1", forKey: defaultsKeys.musicplayer_connected)

            try AVAudioSession.sharedInstance().setActive(true)

            print("Session is Active")

        } catch {

           // let defaults = UserDefaults.standard

          //  defaults.set("0", forKey: defaultsKeys.musicplayer_connected)

            print(error)

        }



         #if targetEnvironment(simulator)



        self.playerViewController.player = player

        self.playerViewController.player?.play()

        print("SIMULATOR")



         #else



        self.setupRemoteTransportControls()

        player?.play()



        #endif



    }









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 == 0.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

    }



   // self.nowplaying(artist: "Anna", song: "test")





}



func nowplaying(with artwork: MPMediaItemArtwork, artist: String, song: String){

  



MPNowPlayingInfoCenter.default().nowPlayingInfo = [

      MPMediaItemPropertyTitle:song,

      MPMediaItemPropertyArtist:artist,

      MPMediaItemPropertyArtwork: artwork,

      MPNowPlayingInfoPropertyIsLiveStream: true

]





   // self.getArtBoard();

}





func setupNowPlayingInfo(with artwork: MPMediaItemArtwork) {

      MPNowPlayingInfoCenter.default().nowPlayingInfo = [

           MPMediaItemPropertyTitle: "Some name",

           MPMediaItemPropertyArtist: "Some name",

           MPMediaItemPropertyArtwork: artwork,

           //MPMediaItemPropertyPlaybackDuration: CMTimeGetSeconds(currentItem.duration),

           //MPNowPlayingInfoPropertyPlaybackRate: 1,

           //MPNowPlayingInfoPropertyElapsedPlaybackTime: CMTimeGetSeconds(currentItem.currentTime())

       ]

   }







func getData(from url: URL, completion: @escaping (UIImage?) -> Void) {

    URLSession.shared.dataTask(with: url, completionHandler: {(data, response, error) in

        if let data = data {

            completion(UIImage(data:data))

        }

    })

        .resume()

}



func getArtBoard(artist: String, song: String, cover: String) {

   // MusicPlayer.JN = "[{'artist': \(artist), 'song':\(song), 'cover': \(cover)}]"

    MusicPlayer.artist = artist

    MusicPlayer.song = song

    MusicPlayer.cover = cover

    

    

    guard let url = URL(string: cover) else { return }

    getData(from: url) { [weak self] image in

        guard let self = self,

            let downloadedImage = image else {

                return

        }

        let artwork = MPMediaItemArtwork.init(boundsSize: downloadedImage.size, requestHandler: { _ -> UIImage in

            return downloadedImage

        })

        self.nowplaying(with: artwork, artist: artist, song: song)

    }

}







    func stopBackgroundMusic() {

        guard let player = player else { return }

        player.pause()



}

}



CPNowPlayingTemplate is for your app's now playing UI in CarPlay. You can add and configure custom playback buttons for CarPlay, just as in your partial example.

The album, artist, artwork, and other data appearing in the now playing template comes from the data your app provides to MPNowPlayingInfoCenter. That's the same API you were probably already using to have your app's now playing data appear on the iOS lock screen and in Control Center.

CPNowPlayingTemplate.shared() - Now having errors?
 
 
Q