これはなに
CarPlay対応アプリを開発する際の手順や、「できること/できないこと」をなんとなく理解するために、 とりあえず動くCarPlay対応のAudioアプリを作ってみたときの雑なメモです。
開発環境
- Xcode 10.1
- Swift 4.2
注意事項
実機(車載ナビ)でテストする場合は、下記URLからアップルへ連絡が必要になります。
https://developer.apple.com//contact/carplay/
1ヶ月ほど待つと、アップルから CarPlay Audio App Programming Guide がメールで送られてきます。このタイミングでデベロッパーアカウントにCarPlay entitlementがアサインされ、CarPlay対応アプリを実機で動かすことが許可されます。
なお、Simulatorでのテストだけであれば上記の連絡なしでもできるようです。
勘違いしていたこと
- CarPlay対応アプリは Watch App 等のようにターゲットを分けて作るわけではなかった
- AppDelegate を拡張して CarPlayでも動くようにするイメージ
- なので CarPlay 専用のアプリストアも存在しない
開発手順
1. Include the CarPlay audio app entitlement
Entitlements.plist
に com.apple.developer.playable-content
を追加します。
これを追加するだけでCarPlayのホーム画面に自分のアプリが表示されるようになります。
2. Show an app icon on the CarPlay home screen
CarPlay用のアプリアイコンをAssetsにセットします。
3. Extend AppDelegate
AppDelegate を拡張し、CarPlayに表示するビューコントローラをセットします。
@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? var carWindow: UIWindow? func updateCarWindow() { guard let screen = UIScreen.screens.first(where: {$0.traitCollection.userInterfaceIdiom == .carPlay}) else { self.carWindow = nil return } // CarPlay is connected let carWindow = UIWindow(frame: screen.bounds) carWindow.screen = screen carWindow.makeKeyAndVisible() carWindow.rootViewController = CarViewController() self.carWindow = carWindow } func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. updateCarWindow() } 〜
CarPlay用の UIWindow
を別途用意し、その rootViewController
にビューコントローラをセットするイメージですね。
4. Present a hierarchical list to navigate and select audio content
曲リストを作るために MPPlayableContentDataSource
と MPPlayableContentDelegate
プロトコルを実装します。名前からわかるように前者はリストに表示するデータをセットし、後者は曲が選択された際のアクションを定義します。
class CarViewController: UIViewController, MPPlayableContentDataSource, MPPlayableContentDelegate { func numberOfChildItems(at indexPath: IndexPath) -> Int { return 3 } func contentItem(at indexPath: IndexPath) -> MPContentItem? { let item = MPContentItem.init(identifier: UUID.init().uuidString) item.title = "hoge rock" item.subtitle = "huga" item.isContainer = false item.isPlayable = true item.artwork = MPMediaItemArtwork(image: UIImage(named: "koogawa")!) return item } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. MPPlayableContentManager.shared().dataSource = self MPPlayableContentManager.shared().delegate = self } func playableContentManager(_ contentManager: MPPlayableContentManager, initiatePlaybackOfContentItemAt indexPath: IndexPath, completionHandler: @escaping (Error?) -> Void) { // 曲が選択された! completionHandler(nil) }
今回は固定データを表示するだけですが、実際には動的にコンテンツを取得し、曲が選択された際にはネットワーク上の曲をストリーミング再生する、などの実装が必要になります。
実行方法
ここでいったんアプリを実行してみます。
iOS Simulatorのメニューから Hardware > External Displays > CarPlay でCarPlay用のSimulatorが起動します。
曲リストが表示されましたね!
がっつり実装したい場合は
今回、自分が実装したのはここまでですが、完全なオーディオアプリを開発する場合は次の実装も必要になります。
- 再生中の曲情報を表示する Now Playing screen に情報を提供する
- リモコンによるイベント(再生・停止・次の曲など)ハンドリング
詳細はアップルから送られてくるCarPlay Audio App Programming Guideを参照してください。
また、偶然GITHUB上で見つけた下記リポジトリも大変参考になりました。