使用MPNowPlayingInfoCenter处理CarPlay中的播放事件 [英] Handling playback events in CarPlay with MPNowPlayingInfoCenter

查看:262
本文介绍了使用MPNowPlayingInfoCenter处理CarPlay中的播放事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试构建具有CarPlay集成的示例音频应用程序.该应用程序是一个测试项目-没有API,没有流媒体,没有复杂的UI.只是歌曲标题的简短列表,它具有选择并播放歌曲的功能.我的目标是在正在播放"屏幕上按下播放"按钮并处理文件时处理回调.

I am trying to build a sample audio app with CarPlay integration. The app is a test project - no API, no streaming, no complicated UI. Just a short list of song titles with the functionality to select one and play it. My goal is to handle the callback when the play button is pressed on the Now Playing screen and play a file.

我在设置MPPlayableContentManager,MPPlayableContentDataSource和MPPlayableContentDelegate时没有任何问题.我的内容是从JSON文件解析的,并且可以正确显示在模拟器的屏幕上.

I don't have any problems setting up the MPPlayableContentManager, MPPlayableContentDataSource and MPPlayableContentDelegate. My content is parsed from a JSON file and it shows up correctly on the simulator's screen.

// 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)
  }
}

此代码提供以下图形输出:

This code gives the following graphic output:

CarPlay模拟器

两个选项卡包含两个播放列表.每个播放列表都有许多歌曲.

The two tabs contain the two playlists. Each playlist has a number of songs.

当我轻按一首歌曲时,该应用程序将变为正在播放"应用程序,但前提是在用户与该行进行交互时,我已经开始和结束接收远程控制事件.

When I tap on a song the app becomes the Now Playing app but only if I have both began and ended receiving remote control events at the time of the user's interaction with the row.

当检测到对表行的单击时,将调用 initiatePlaybackOfContentItemAt 方法.

The initiatePlaybackOfContentItemAt method is called when a click on the table row is detected.

// 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方法放置在其他任何地方,则该应用都会退出以响应行触摸,并且不会进入正在播放"屏幕.

This is the only code that works for me if I want the app to transition to the Now Playing screen. If I place any of the UIApplication methods anywhere else the app quits responding to row touches and doesn't enter the Now Playing screen.

但是,我正在猜测是因为我正在调用 endReceivingRemoteControlEvents(),所以无法获取不同事件的回调.设置了正在播放的信息,我可以在用户界面中看到播放按钮,但是当我按下该按钮时,回调将不会执行.

However, I'm guessing because I'm invoking the endReceivingRemoteControlEvents(), I can't get the callback for the different events. The now playing info is set, I can see the play button in the UI but, when I press it, the callback doesn't execute.

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
    }
....
}

正在播放屏幕

我做错了什么?

这与我在模拟器上进行测试有关吗?这可以在真实设备上工作吗?

Could this have something to do with the fact that I'm testing on a simulator? Will this work on a real device?

如果任何人都可以阐明如何正确设置CarPlay集成以进入正在播放"屏幕并响应事件,请分享.我在查找任何可用的代码示例或示例时遇到很多麻烦.

If anyone can shed some light on how to correctly setup the CarPlay integration to enter the Now Playing screen and respond to events, please, share. I'm having a lot of trouble finding any usable code samples or examples.

我知道我可以,但我尚未申请CarPlay授权,因为该项目仅用于研究目的,我非常怀疑我会获得批准.

I know I can but I haven't applied for a CarPlay entitlement because this project is for research purposes only and I highly doubt I'll get approved.

推荐答案

只有在快速暂停后调用beginReceivingRemoteControlEvents方法,我才能修复" playCommandstopCommand来接收回调.秒):

I was able to "fix" the playCommand and stopCommand to receive callbacks only if call the beginReceivingRemoteControlEvents method after a quick pause (like a second):

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假定用户必须点击播放"按钮,然后才应该开始播放(通过处理远程命令回调) .否则,您将被重定向到具有活动音频的正在播放"屏幕,并且无法使按钮带有停止"图标.

one more thing, when a user is navigated to the "Now Playing" screen, the iOS assumes that the user has to hit the "Play" button and only then you should start a playback (by handling the remote command callback). Otherwise, you will be redirected to the "Now Playing" screen with active audio and without any ability to make the button with the "Stop" icon.

更新

虽然以上逻辑适用于Simulator,但我已经在真正的CarPlay设备上进行了测试,但这不是必需的.您开始播放并调用完成处理程序. iOS会自动处理所有其余操作,包括过渡到正在播放"屏幕.

While the logic above works for Simulator, I've tested on a real CarPlay device and it's not required. You start the playback and call the completion handler. All the rest is handled automatically by iOS including the transition to the "Now Playing" screen.

这篇关于使用MPNowPlayingInfoCenter处理CarPlay中的播放事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆