Обработка событий воспроизведения в CarPlay с помощью MPNowPlayingInfoCenter - PullRequest
0 голосов
/ 15 октября 2018

Я пытаюсь создать пример звукового приложения с интеграцией CarPlay.Приложение представляет собой тестовый проект - без API, без потоковой передачи, без сложного пользовательского интерфейса.Просто краткий список названий песен с возможностью выбора и воспроизведения.Моя цель - обработать обратный вызов при нажатии кнопки воспроизведения на экране «Сейчас исполняется» и воспроизвести файл.

У меня нет проблем с настройкой MPPlayableContentManager, MPPlayableContentDataSource и MPPlayableContentDelegate.Мой контент анализируется из файла JSON, и он правильно отображается на экране симулятора.

// MARK: - MPPlayableContentDataSource methods
extension PlayableContentManager: MPPlayableContentDataSource {
  func numberOfChildItems(at indexPath: IndexPath) -> Int {
    if indexPath.count == 0 {
      return playlists.count
    } else if indexPath.count == 1 {
      return playlists[indexPath.first ?? 0].playlist.count
    } else if indexPath.count == 2 {
      return playlists.last?.playlist.count ?? 0
    }

    return 0
 }

  func contentItem(at indexPath: IndexPath) -> MPContentItem? {
    if indexPath.count == 1 {
      return createTabbar(item: playlists[indexPath.first ?? 
0].name.capitalized, itemType: playlists[indexPath.first ?? 0].type)
    } else if indexPath.count == 2 {
      if indexPath.first == 0 {
        return createContent(item: playlists[0].playlist[indexPath.last 
?? 0], isContainer: false, isPlayable: true)
      } else {
        return createContainerContent(item: playlists[indexPath.first 
?? 0].playlist[indexPath.last ?? 0])
      }
    }

    return createTabbar(item: "", itemType: nil)
  }
}

Этот код дает следующий графический вывод:

Симулятор CarPlay

Две вкладки содержат два списка воспроизведения.В каждом плейлисте есть несколько песен.

Когда я нажимаю на песню, приложение становится приложением «Сейчас исполняется», но только если я одновременно начал и закончил получать события дистанционного управления во время взаимодействия пользователя со строкой.

Метод initiatePlaybackOfContentItemAt вызывается при обнаружении щелчка по строке таблицы.

// MARK: - MPPlayableContentDelegate methods
extension PlayableContentManager: MPPlayableContentDelegate {
  func playableContentManager(_ contentManager: 
MPPlayableContentManager, initiatePlaybackOfContentItemAt indexPath: 
 IndexPath, completionHandler: @escaping (Error?) -> Void) {
    DispatchQueue.main.async {
      UIApplication.shared.beginReceivingRemoteControlEvents()
      self.infoCenter.nowPlayingInfo = self.setupNowPlayingInfo(for: 
indexPath)
      completionHandler(nil)
      UIApplication.shared.endReceivingRemoteControlEvents()
    }
  }
}

Это единственный код, который работает для меня, если я хочу приложениедля перехода к экрану «Сейчас исполняется».Если я размещу какой-либо из методов UIApplication где-либо еще, приложение перестанет реагировать на прикосновения строк и не откроет экран «Сейчас исполняется».

Однако, я думаю, потому что я вызываю endReceivingRemoteControlEvents () , я не могу получить обратный вызов для различных событий.Теперь информация о воспроизведении установлена, я вижу кнопку воспроизведения в пользовательском интерфейсе, но когда я нажимаю ее, обратный вызов не выполняется.

private func setupPlaybackCommands() {
    commandCenter = MPRemoteCommandCenter.shared()

    commandCenter.playCommand.addTarget { [unowned self] event in
      if self.audioPlayer.rate == 0.0 {
        self.play()
        return .success
      }
      return .commandFailed
    }
....
}

Экран воспроизведения сейчас

Что я делаю не так?

Может ли это быть как-то связано с тем, что я тестирую на симуляторе?Будет ли это работать на реальном устройстве?

Если кто-то может пролить свет на то, как правильно настроить интеграцию CarPlay, чтобы войти в экран «Сейчас исполняется» и ответить на события, поделитесь, пожалуйста.У меня много проблем с поиском любых полезных примеров кода или примеров.

Я знаю, что могу, но я не подал заявку на получение разрешения CarPlay, потому что этот проект предназначен только для исследовательских целей, и я сильно сомневаюсь, что я 'получу одобрение.

1 Ответ

0 голосов
/ 02 декабря 2018

Мне удалось «исправить» playCommand и stopCommand для получения обратных вызовов только в случае вызова метода beginReceivingRemoteControlEvents после быстрой паузы (например, секунды):

extension PlayableContentManager: MPPlayableContentDelegate {
  func playableContentManager(_ contentManager: 
MPPlayableContentManager, initiatePlaybackOfContentItemAt indexPath: 
 IndexPath, completionHandler: @escaping (Error?) -> Void) {
    DispatchQueue.main.async {
      UIApplication.shared.beginReceivingRemoteControlEvents()
      self.infoCenter.nowPlayingInfo = self.setupNowPlayingInfo(for: 
indexPath)
      completionHandler(nil)
      UIApplication.shared.endReceivingRemoteControlEvents()

      // TODO: add 1 second timeout, and call this after
      UIApplication.shared.beginReceivingRemoteControlEvents()
    }
  }
}

еще одинДело в том, что когда пользователь переходит к экрану «Сейчас играет», iOS предполагает, что пользователь должен нажать кнопку «Воспроизвести», и только после этого вы должны начать воспроизведение (обработав обратный вызов удаленной команды).В противном случае вы будете перенаправлены на экран «Сейчас исполняется» с активным звуком и без возможности создания кнопки со значком «Стоп».

ОБНОВЛЕНИЕ

Хотя приведенная выше логика работает для симулятора, я проверил на реальном устройстве CarPlay, и это не требуется.Вы запускаете воспроизведение и вызываете обработчик завершения.Все остальное обрабатывается iOS автоматически, включая переход к экрану «Сейчас играет».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...