Аудио-приложение Carplay работало до версии iOS 12.4. Когда я создал приведенный ниже класс, я последовал ответу по этой ссылке, и он отлично работает. Ниже приведен пример кода.
Текущая игра работает на Carplay, но когда приложение открыто на приборной панели, отображается сообщение о невозможности подключения. Я использую Xcode v11.2.1 (11B500), симулятор iOS v13.2.2, iPhone 11 (v13.2.3).
Вы пытались распечатать журналы на initiatePlaybackOfContentItemAt
, но он не вызывается. Как вы думаете, что мне не хватает, чтобы она могла работать и быть совместимой с iOS 13 или более поздней версией?
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
}
}
С более чем 200 строками кода нам много для чтения. Попробуйте удалить как можно больше, чтобы получить что-то, что по-прежнему не работает. Например, быстрая выборочная проверка внизу показывает isPodcast
метод, который, вероятно, не связан с проблемой. Продолжайте удалять код до тех пор, пока не получите только наименьший объем кода, в котором все еще есть проблема, и обычно нам намного проще отлаживать. — person Don Fuentes schedule 04.12.2019
У меня другое поведение. При подключении к CarPlay событие запускается, но когда я отключаюсь, ничего не происходит, поэтому я на самом деле просто знаю, когда я подключен к CarPlay, но не когда отключаюсь. — person Don Fuentes schedule 08.06.2021
Кажется, это ошибка Xcode 11. Я пробовал бета-версию Xcode 13, но результат был тот же.
В моем случае был пустой белый экран с пустыми вкладками с синим отливом. Затем была показана ошибка: «Невозможно загрузить контент (null)» Скриншот симулятора iOS 13 </ а>.
Завершил установку симулятора iPhone 5s / iOS 12.4.1.
На стороне клиента с реальным устройством iOS 13 работала как положено.
Некоторое время назад я отправил в Apple отчет об ошибке. Apple вернулась ко мне и сказала:
Как видите, этот вопрос ранее задавался на форумах разработчиков Apple.
Симулятор CarPlay отлично работает с симуляторами Xcode 11 и iOS 12.4, но, похоже, есть проблемы с симуляторами Xcode 11 и iOS 13. Я попытался создать наше приложение на Xcode 11 и запустить его на физическом устройстве iOS 13.1 с физической мультимедийной системой CarPlay в автомобиле, и оно отлично сработало! Это только кажется проблемой симулятора CarPlay.