WWDC Quick Look 💓 By SwiftGGTeam
Get more mileage out of your app with CarPlay

Get more mileage out of your app with CarPlay

元の動画を見る

ハイライト

CarPlay の設計哲学は常に「運転者のためにある」ことです。CarPlay 上の App は運転中に本当に必要な機能だけを提供し、ログイン、設定、規約の読み込みは iPhone に任せます。


主要内容

CarPlay App の難しさは抑制です。車内のユーザーは運転中で、UI は少なく、タスクは短く、情報は一目で把握できる必要があります。

00:55)Apple は冒頭で明確な境界を示します。CarPlay は運転者向けに設計されています。一度きりの設定、ログイン、規約の読み込みは運転前または運転後に行い、CarPlay UI には出さないべきです。

この境界が以降のすべての設計を決めます。

01:59)iOS 16 では Fueling と Driving Task の 2 種類の CarPlay App が追加されました。前者は iOS 14 の EV Charging の考え方を給油や代替燃料のシーンへ拡張し、後者は非常に単純な運転タスクの正式な入口を提供します。

09:16)Apple は CarPlay Simulator もリリースしました。Mac 上の独立 App で、iPhone を接続するとデスクトップで実際の CarPlay 環境を再現できます。Xcode と Instruments を同時に使い、画面サイズ、外観、切断・再接続、インストルメントクラスタ表示をテストできます。

14:53)ナビゲーション App には新機能もあります。対応車両では、ライブマップやターンカードをデジタルインストルメントクラスタに表示できます。App がすでに CarPlay Dashboard をサポートしている場合、同じパターンに従い、Info.plist で scene を宣言し、対応する delegate を実装します。


詳細

CarPlay テンプレートが複雑さを制御する

02:14)CarPlay の UI はテンプレートで構成されます。App がデータを提供し、システムが車載画面に UI を描画します。

これには 3 つの直接的な利点があります。

第一に、開発者はフォントサイズや車載入力デバイスの差異を自分で処理する必要がありません。第二に、テンプレートは UI の複雑さを抑えます。第三に、同種のテンプレートは CarPlay App 間で一貫しており、運転者は操作をより速く完了できます。

この Session ではテンプレート API の公式コード断片は示されませんが、いくつかのテンプレートの使用シーンは明確に列挙されています。

// 概念例:Session で言及されたテンプレートに基づいて UI 形態を選択
let roadStatusTemplate = CPPointOfInterestTemplate(...)
let accessoryTemplate = CPInformationTemplate(...)
let quickChoiceTemplate = CPGridTemplate(...)

キーポイント:

  • CPPointOfInterestTemplate:Session では道路状況 App の例に使われ、近くの重要な地点を少数表示するのに適しています。
  • CPInformationTemplate:Session ではトレーラーコントローラーの例に使われ、アクセサリの状態と少数の操作ボタンを表示するのに適しています。
  • CPGridTemplate:Session では走行距離記録とクイックレーン料金の例に使われ、1〜2 個のクイック選択ボタンに適しています。

ここでの要点はテンプレートの制約です。App タイプごとに運転シーンに関連し適したテンプレートだけを使えます。Apple は開発者向けドキュメントに対応表を提供しています。

Fueling App は地点検索だけでなく給油プロセスを扱う

04:26)iOS 16 で Fueling App タイプが追加されました。iOS 14 の EV Charging App の考え方を拡張し、対象は従来のガソリン車や代替燃料車です。

Apple は特に注意します。多くのユーザーはすでにナビ App で地点を探して向かいます。したがって CarPlay で「ガソリンスタンドを探す」だけでは不十分です。

より適切な機能は、運転中に本当に必要な給油フローです。例えば正しいスタンド機器への接続や、給油ポンプの直接起動です。

// 概念例:Fueling App の CarPlay UI は運転中のアクションを中心に
struct FuelingAction {
    let stationName: String
    let pumpIdentifier: String
    let primaryActionTitle = "Start Pump"
}

キーポイント:

  • stationName:CarPlay UI は現在関連する地点だけを表示し、完全な地点計画は行いません。
  • pumpIdentifier:Session では App がユーザーに正しい機器への接続を支援できると明記しています。
  • primaryActionTitle:コアアクションは給油ポンプ起動など、運転中に必要なタスクであるべきです。

この例は概念モデルであり、Apple が提供する新 API ではありません。公式トランスクリプトは製品境界とシナリオのみを説明し、Fueling タイプのコード断片は提供していません。

Driving Task App は数秒で完了すべき

05:22)Driving Task は、より広範な単純な運転タスクを担う新しい CarPlay App タイプです。

Apple は 4 つの例を示します。道路状況情報、車両アクセサリ制御、走行開始・終了時のタスク、クイックレーンの人数選択です。共通点は小さく、できれば 1 画面で完了することです。

08:40)設計ルールは厳格です。単画面 App を検討し、運転中に最小限必要な機能だけを提供し、数秒で完了できるタスクだけを許可し、複雑または低頻度のユースケースは避けます。

// 概念例:Driving Task の操作集合は小さく
let mileageActions = [
    CPGridButton(titleVariants: ["Personal"], image: personalImage) { _ in
        recordPersonalMileage()
    },
    CPGridButton(titleVariants: ["Business"], image: businessImage) { _ in
        recordBusinessMileage()
    }
]

キーポイント:

  • mileageActions:Session の走行距離記録 App には個人用と業務用の 2 ボタンだけがあります。
  • CPGridButton:Session ではこの種の App が CPGridTemplate を使えると説明し、ボタン式選択は数秒で完了するタスクに適しています。
  • recordPersonalMileage() / recordBusinessMileage():例の関数はビジネスアクションを表し、Session は具体的な実装を提供していません。

この例はトランスクリプトの UI 形態を保ちますが、関数名は概念的です。公式の完全 API 例として扱わないでください。

CarPlay Simulator で実機デバッグをデスクトップへ

10:18)CarPlay Simulator は独立した Mac App です。Additional Tools for Xcode をダウンロードし、App を起動し、ケーブルで iPhone を Mac に接続すると、実車に接続したかのように CarPlay が起動します。

解決するのはテストコストです。

以前は実機 iPhone で CarPlay UI をテストするには、実車やアフターマーケットヘッドユニットが通常必要でした。今は机で実機 App をデバッグし、Xcode のブレークポイントと Instruments で性能分析できます。

12:38)Simulator は複数の車両動作スイッチも提供します。Limit UI、ライト/ダーク外観の切り替え、切断・再接続のシミュレーション、メインディスプレイサイズの調整、インストルメントクラスタ第二画面の有効化です。

CarPlay Simulator テストチェックリスト:
1. light / dark appearance を切り替え、画像アセットを確認。
2. Limit UI をタップし、走行中コンテンツが適切に短縮されることを確認。
3. main display size を変更し、テンプレートとマップ描画を確認。
4. instrument cluster display を有効化し、第二画面のマップまたはターンカードを確認。
5. disconnect / reconnect をシミュレートし、再接続ロジックをデバッグ。

キーポイント:

  • ステップ 1:Session では Express Lane App がライト/ダーク用に異なるアートワークを提供するデモがあります。
  • ステップ 2:Limit UI ボタンは、走行中に CarPlay が画面コンテンツを制限する要件をシミュレートします。
  • ステップ 3:テンプレート UI は通常システムが適応します。ナビ App のマップ描画コードは重点的に検証が必要です。
  • ステップ 4:インストルメントクラスタ第二画面は主にナビ App 向けです。
  • ステップ 5:電話は Mac に接続されたままなので、切断・再接続シナリオを Xcode で直接デバッグできます。

ナビ App をデジタルインストルメントクラスタに接続

15:07)デジタルインストルメントクラスタのサポートは iOS 13 CarPlay Dashboard のパターンに従います。まず Info.plist でサポートを宣言し、対応する Scene Session Role を追加します。

公式コード断片:

<key>UIApplicationSceneManifest</key>
<dict>
    <!-- Indicate support for CarPlay dashboard -->
    <key>CPSupportsDashboardNavigationScene</key>
    <true/>
    <!-- Indicate support for instrument cluster displays -->
    <key>CPSupportsInstrumentClusterNavigationScene</key>
    <true/>
    <!-- Indicate support for multiple scenes -->
    <key>UIApplicationSupportsMultipleScenes</key>
    <true/>
    <key>UISceneConfigurations</key>
    <dict>
        <!-- For device scenes -->
        <key>UIWindowSceneSessionRoleApplication</key>
        <array>
            <dict>
                <key>UISceneClassName</key>
                <string>UIWindowScene</string>
                <key>UISceneConfigurationName</key>
                <string>Phone</string>
                <key>UISceneDelegateClassName</key>
                <string>MyAppWindowSceneDelegate</string>
            </dict>
        </array>
        <!-- For the main CarPlay scene -->
        <key>CPTemplateApplicationSceneSessionRoleApplication</key>
        <array>
            <dict>
                <key>UISceneClassName</key>
                <string>CPTemplateApplicationScene</string>
                <key>UISceneConfigurationName</key>
                <string>CarPlay</string>
                <key>UISceneDelegateClassName</key>
                <string>MyAppCarPlaySceneDelegate</string>
            </dict>
        </array>
        <!-- For the CarPlay Dashboard scene -->
        <key>CPTemplateApplicationDashboardSceneSessionRoleApplication</key>
        <array>
            <dict>
                <key>UISceneClassName</key>
                <string>CPTemplateApplicationDashboardScene</string>
                <key>UISceneConfigurationName</key>
                <string>CarPlay-Dashboard</string>
                <key>UISceneDelegateClassName</key>
                <string>MyAppCarPlayDashboardSceneDelegate</string>
            </dict>
        </array>
        <!-- For the CarPlay instrument cluster scene -->
        <key>CPTemplateApplicationInstrumentClusterSceneSessionRoleApplication</key>
        <array>
            <dict>
                <key>UISceneClassName</key>
                <string>CPTemplateApplicationInstrumentClusterScene</string>
                <key>UISceneConfigurationName</key>
                <string>CarPlay-Instrument-Cluster</string>
                <key>UISceneDelegateClassName</key>
                <string>MyAppCarPlayInstrumentClusterSceneDelegate</string>
            </dict>
        </array>
    </dict>
</dict>

キーポイント:

  • CPSupportsDashboardNavigationScene:CarPlay Dashboard ナビゲーション scene のサポートを宣言します。
  • CPSupportsInstrumentClusterNavigationScene:デジタルインストルメントクラスタナビゲーション scene のサポートを宣言します。
  • UIApplicationSupportsMultipleScenes:App が複数 scene を同時管理できるようにします。
  • CPTemplateApplicationSceneSessionRoleApplication:ヘッドユニットメイン画面用のメイン CarPlay scene。
  • CPTemplateApplicationDashboardSceneSessionRoleApplication:CarPlay Dashboard 用の Dashboard scene。
  • CPTemplateApplicationInstrumentClusterSceneSessionRoleApplication:ダッシュボードマップまたはターンカード用のインストルメントクラスタ scene。
  • UISceneDelegateClassName:phone、CarPlay、Dashboard、インストルメントクラスタそれぞれに delegate をバインドします。

16:00)scene 宣言後、インストルメントクラスタ関連 delegate を実装します。公式断片:

extension TemplateApplicationSceneDelegate: CPTemplateApplicationInstrumentClusterSceneDelegate {
    
    func templateApplicationInstrumentClusterScene(
        _ templateApplicationInstrumentClusterScene: CPTemplateApplicationInstrumentClusterScene,
        didConnect instrumentClusterController: CPInstrumentClusterController) {
        // Connected to Instrument Cluster
        TemplateManager.shared.clusterController(instrumentClusterController, didConnectWith: templateApplicationInstrumentClusterScene.contentStyle)
    }
    


    func instrumentClusterControllerDidConnect(_ instrumentClusterWindow: UIWindow) {
        // Window in which to draw instrument cluster contents 
       self.instrumentClusterWindow = instrumentClusterWindow
    }

キーポイント:

  • CPTemplateApplicationInstrumentClusterSceneDelegate:scene delegate がインストルメントクラスタ scene の接続イベントを受け取れます。
  • didConnect instrumentClusterController:CarPlay がインストルメントクラスタコントローラーに接続したときに呼ばれます。
  • CPInstrumentClusterController:Session 後半で言及されるズーム、コンパス、制限速度表示タイミングなどを処理します。
  • templateApplicationInstrumentClusterScene.contentStyle:現在のコンテンツスタイルを App のテンプレート管理ロジックへ渡します。
  • instrumentClusterControllerDidConnect(_:):システムが描画可能な UIWindow を App に渡します。
  • self.instrumentClusterWindow:App はこのウィンドウを保持し、その中にインストルメントクラスタコンテンツを描画します。

16:26)インストルメントクラスタには追加の注意点があります。車両がマップのズームを許可する場合、CPInstrumentClusterControllerDelegate の実装が必要です。コンパスや制限速度表示も、delegate が描画に適したタイミングを伝えるまで待つべきです。

16:57)インストルメントクラスタ画面は車内の他要素に隠されることがあります。対処はセーフエリアです。view controller で viewSafeAreaInsetsDidChange をオーバーライドし、cluster view の safeAreaLayoutGuide で重要コンテンツを制約します。

// 概念例:重要なマップコンテンツをセーフエリア内に制限
final class ClusterMapViewController: UIViewController {
    override func viewSafeAreaInsetsDidChange() {
        super.viewSafeAreaInsetsDidChange()
        updateRouteOverlayLayout(using: view.safeAreaLayoutGuide)
    }
}

キーポイント:

  • viewSafeAreaInsetsDidChange():Session ではセーフエリア変化を知るためにオーバーライド可能と明記しています。
  • view.safeAreaLayoutGuide:重要コンテンツを可視領域に保つのに推奨されています。
  • updateRouteOverlayLayout:ルート線、現在地など重要なマップコンテンツを更新する概念関数です。

重要ポイント

1. 運転アクションだけを残したアクセサリ制御 CarPlay UI を作る

  • やること:トレーラー、ルーフボックス、タイヤ空気圧デバイスなどのアクセサリ制御を 1 つの CPInformationTemplate ページに圧縮する。
  • 価値がある理由:Session のトレーラーコントローラー例は、CarPlay UI が状態と少数ボタンだけでよいことを示します。ペアリングや設定など複雑な機能は iPhone に残します。
  • 始め方:運転中に必須の 1〜2 アクションを列挙し、CarPlay テンプレートで表現する。iPhone 設定ページを CarPlay に移さない。

2. 2 ボタンの走行距離記録入口を作る

  • やること:走行開始または終了時に、2 ボタンで personal / business mileage を記録する。
  • 価値がある理由:Apple はこの例で Driving Task App の理想形(単画面、短タスク、数秒完了)を示しています。
  • 始め方CPGridTemplate で少数ボタンを構成し、コールバックは現在の走行分類だけを書き込む。詳細統計は iPhone App に戻す。

3. ナビ App にインストルメントクラスタマップ検証フローを追加

  • やること:CarPlay Simulator で instrument cluster display を有効化し、マップ、ターンカード、セーフエリアを確認する。
  • 価値がある理由:iOS 16 ではナビ App が運転者の視界内デジタルインストルメントクラスタにマップやターンカードを置けます。
  • 始め方:Info.plist に CPSupportsInstrumentClusterNavigationScene と instrument cluster scene role を追加し、CPTemplateApplicationInstrumentClusterSceneDelegate を実装する。

4. CarPlay Simulator 回帰テストチェックリストを確立

  • やること:リリース前にライト/ダーク、Limit UI、画面サイズ、切断・再接続、インストルメントクラスタ第二画面をテストする。
  • 価値がある理由:これらは Session で CarPlay Simulator が明示的にサポートする車両環境シミュレーション能力です。
  • 始め方:Additional Tools for Xcode をチーム開発環境に追加し、実機を Mac に接続して項目ごとに検証する。ナビ App は display size と aspect ratio の違いを重点的にテストする。

関連セッション

  • What’s new in MapKit — MapKit の 3D マップ、オーバーレイ、Look Around 更新を学び、ナビ App のマップ体験をさらに最適化します。
  • Meet Apple Maps Server APIs — ジオコーディングと ETA などサーバー側マップ能力を学び、ルートと地点サービスのバックエンドを補完します。
  • Bring multiple windows to your SwiftUI app — scene とウィンドウ構造を理解し、マルチ scene の考え方を CarPlay 設定へ移します。
  • Explore navigation design for iOS — 情報構造とインタラクション簡素化の観点から、CarPlay の運転シーン制約と照合します。

コメント

GitHub Issues · utterances