The Carplay audio app was working until iOS v12.4. When I created the below class, I followed the answer on this link and it works perfectly fine. Below is the sample code.
The now playing is working on Carplay but when the app is open on the dashboard, it displays unable to connect. I'm using Xcode v11.2.1 (11B500), simulator iOS v13.2.2, iPhone 11 (v13.2.3).
Did try print logs on initiatePlaybackOfContentItemAt
and it's not being called. What do you think I'm missing so that it could be working and compatible with iOS 13 or a higher version?
class PlayManager: NSObject {
static let shared = PlayManager()
var currentStation: Int64 = 0
var isRadio: Bool = true
var contentList: [RadioObj] = []
let commandCenter = MPRemoteCommandCenter.shared()
var nowPlayingSongManager: MPNowPlayingInfoCenter?
var playableContentManager: MPPlayableContentManager?
override init() {
super.init()
let artist = "Play"
nowPlayingSongManager = MPNowPlayingInfoCenter.default()
nowPlayingSongManager?.nowPlayingInfo = [
MPNowPlayingInfoPropertyMediaType : "Audio",
MPMediaItemPropertyTitle : api.defaults.defaultArtist,
MPMediaItemPropertyArtist: artist
]
player.initializeMedia(song: api.defaults.defaultArtist, artist: artist, album: api.defaults.appLogo)
playableContentManager = MPPlayableContentManager.shared()
playableContentManager?.dataSource = self
playableContentManager?.delegate = self
}
func loadData(){
api.data.getRadioData(event_source: "carplay") { (done, obj) in
if done {
if obj.count > 0 {
let indeces: Int = 0
api.currentRadio = obj[indeces]
api.isRadio = true
api.isPodcast = false
}
self.contentList = obj
self.playableContentManager.reloadData()
}
}
}
}
extension PlayManager: MPPlayableContentDelegate, MPPlayableContentDataSource {
func playableContentManager(_ contentManager: MPPlayableContentManager, initiatePlaybackOfContentItemAt indexPath: IndexPath, completionHandler: @escaping (Error?) -> Void) {
print("check if its called")
let indeces: Int = indexPath[0]
let radio_name = contentList[indeces].name
let id = contentList[indeces].id
let radio_logo = contentList[indeces].logo_rounded_url
let stream_url = contentList[indeces].stream_url
let hd_stream_url = contentList[indeces].hd_stream_url
var currentIdentifier = ""
if contentManager.nowPlayingIdentifiers.count > 0 {
currentIdentifier = contentManager.nowPlayingIdentifiers[0]
}
var newIdenditier = "radio_"
if let id = id {
newIdenditier += "\(id)"
}
let radioObj = RadioObj()
radioObj.stream_url = stream_url
radioObj.hd_stream_url = hd_stream_url
radioObj.name = radio_name
radioObj.logo_url = radio_logo
api.currentRadio = contentList[indeces]
api.isRadio = true
if let id = id {
currentStation = id
}
guard let logo = radio_logo, let name = radio_name else { return }
player.initializeMedia(song: name, artist: api.defaults.defaultArtist, album: api.defaults.appLogo)
api.download(image: logo) { (image) in
player.initializeMedia(song: name, artist: api.defaults.defaultArtist, album: image)
}
if api.isPlaying && currentIdentifier != newIdenditier {
contentManager.nowPlayingIdentifiers = [newIdenditier]
DispatchQueue.main.async {
player.start()
}
}
onTapSound(contentManager: contentManager, completionHandler: completionHandler, indexPath: indexPath)
}
func onTapSound(contentManager:MPPlayableContentManager,completionHandler: @escaping (Error?) -> Void, indexPath : IndexPath){
completionHandler(nil)
}
func numberOfChildItems(at indexPath: IndexPath) -> Int {
if indexPath.count == 0 {
return contentList.count
} else if indexPath.count == 1 {
let _: Int = indexPath.first ?? 0
} else if indexPath.count == 2 {
}
return 0
}
func contentItem(at indexPath: IndexPath) -> MPContentItem? {
let indeces: Int = indexPath[0]
let _: Int = indexPath.indices.count
let radio_name = contentList[indeces].name
let id = contentList[indeces].id
let radio_logo = contentList[indeces].car_logo
if let id = id, let radio_logo = radio_logo {
let contentItem = MPContentItem(identifier: "radio_\(id)")
contentItem.title = radio_name
contentItem.isContainer = false
contentItem.isPlayable = true
contentItem.isStreamingContent = true
DispatchQueue.global().async {
if let url = URL(string:radio_logo) {
do {
let radio = try UIImage(data: Data(contentsOf: url))
if let image = radio {
let artWork = MPMediaItemArtwork(boundsSize: image.size, requestHandler: { (size) -> UIImage in
return image
})
contentItem.artwork = artWork
}
} catch{}
}
}
return contentItem
}
return MPContentItem()
}
open func setupEvents(isRadio isTrue: Bool?) -> PlayManager {
guard let isTrue = isTrue else { return self }
commandCenter.playCommand.isEnabled = isTrue
if isTrue {
commandCenter.skipForwardCommand.isEnabled = false
commandCenter.skipBackwardCommand.isEnabled = false
commandCenter.stopCommand.isEnabled = true
commandCenter.pauseCommand.isEnabled = false
if #available(iOS 10.0, *) {
nowPlayingSongManager?.nowPlayingInfo?[MPNowPlayingInfoPropertyIsLiveStream] = true
}
} else {
commandCenter.stopCommand.isEnabled = false
commandCenter.pauseCommand.isEnabled = true
}
commandCenter.stopCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
api.isPlaying = false
player.stop()
return .success
}
commandCenter.pauseCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
player.pause()
return .success
}
commandCenter.playCommand.addTarget { (event) -> MPRemoteCommandHandlerStatus in
api.isPlaying = true
if api.isRadio {
self.playableContentManager?.nowPlayingIdentifiers = ["radio_\(self.currentStation)"]
guard let logo = api.currentRadio?.logo_rounded_url, let name = api.currentRadio?.name else { return .noSuchContent }
api.download(image: logo) { (image) in
player.initializeMedia(song: name, artist: api.defaults.defaultArtist, album: image)
}
player.start()
}
if api.isPodcast {
player.resume()
}
return .success
}
return self
}
}
Seems to be an Xcode 11 bug. I've tried Xcode 13 beta, but the result was the same.
In my case, there was a blank white screen with empty tabs with a blue tint. Then the error was shown, saying "Unable to load content (null)" iOS 13 Simulator screenshot.
Ended up installing iPhone 5s/iOS 12.4.1 simulator.
On the client's side with a real device iOS 13 worked as expected.