使用 CarPlay 框架開發支援 CarPlay 的應用程式。適用於為車載螢幕打造導航、音訊、通訊、電動車充電、停車或快速點餐等 App;處理 CPTemplateApplicationScene、CPInterfaceController 模板階層、CPListTemplate、CPMapTemplate、CPNowPlayingTemplate;設定 CarPlay entitlements 權限;以及整合 CarPlay Simulator 進行測試等情境。
CarPlay
為車載螢幕建構具備類別授權(Category-entitled)、基於模板的 CarPlay 應用程式。
適用範圍:Swift 6.3、iOS 26+。
完整導航會話(Navigation sessions)、儀表板場景(Dashboard scenes)與進階模板組合等延伸模式,請參閱 references/carplay-patterns.md。
範圍界限:完整的 CarPlay 框架 App 會使用類別 Entitlements 權限、CPTemplateApplicationScene、CPTemplateApplicationSceneDelegate、CPInterfaceController,以及系統的 CPTemplate 導航。可在 CarPlay 顯示的 WidgetKit 小工具與 ActivityKit 即時動態(Live Activities)屬於獨立的系統體驗;其實作請劃分至對應領域,本 Skill 僅保留 CarPlay 專屬的驗證邏輯。
目錄
Entitlements and Setup
前往 Apple 的 CarPlay 權限申請表單 申請指定類別的 Entitlement,同意附加條款後,即可在下方配置獲准的類別金鑰。
各類別的 Entitlement 金鑰
| Entitlement 金鑰 | 應用類別 |
|---|---|
com.apple.developer.carplay-audio |
音訊 (Audio) |
com.apple.developer.carplay-communication |
通訊 (Communication) |
com.apple.developer.carplay-maps |
導航 (Navigation) |
com.apple.developer.carplay-charging |
電動車充電 (EV Charging) |
com.apple.developer.carplay-parking |
停車 (Parking) |
com.apple.developer.carplay-quick-ordering |
快速點餐 (Quick Food Ordering) |
專案設定步驟
- 前往 Developer Portal,在 App ID 的 Additional Capabilities 頁籤中勾選對應功能。
- 針對更新後的 App ID 重新產生 Provisioning Profile。
- 在 Xcode 中停用自動簽署(Automatic Signing),並匯入剛下載的 CarPlay Provisioning Profile。
- 新增
Entitlements.plist檔案,並將對應的 Entitlement Key 設定為true。 - 將 Build Settings 中的 Code Signing Entitlements 指向
Entitlements.plist的檔案路徑。
核心類型 (Key Types)
| 類型 | 角色與用途 |
|---|---|
CPTemplateApplicationScene |
專為 CarPlay 螢幕設計的 UIScene 子類別 |
CPTemplateApplicationSceneDelegate |
處理 Scene 連線與斷開的生命週期 |
CPInterfaceController |
由 CarPlay 提供的控制器,負責設定根模板(Root Template)以及 Push、Present 或 Pop 模板 |
CPTemplate |
所有 CarPlay 模板的抽象基底類別 |
CPSessionConfiguration |
提供車載螢幕限制與內容樣式的設定資訊 |
Scene Configuration
在 Info.plist 中宣告 CarPlay Scene,並實作 CPTemplateApplicationSceneDelegate 以回應 CarPlay 的連線事件。
Info.plist Scene Manifest
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>UISceneConfigurations</key>
<dict>
<key>CPTemplateApplicationSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneClassName</key>
<string>CPTemplateApplicationScene</string>
<key>UISceneConfigurationName</key>
<string>CarPlaySceneConfiguration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).CarPlaySceneDelegate</string>
</dict>
</array>
</dict>
</dict>
Scene Delegate(非導航類)
非導航類 App 僅會收到介面控制器(Interface Controller),不會收到 Window。
import CarPlay
final class CarPlaySceneDelegate: UIResponder,
CPTemplateApplicationSceneDelegate {
var interfaceController: CPInterfaceController?
func templateApplicationScene(
_ templateApplicationScene: CPTemplateApplicationScene,
didConnect interfaceController: CPInterfaceController
) {
self.interfaceController = interfaceController
interfaceController.setRootTemplate(buildRootTemplate(),
animated: true, completion: nil)
}
func templateApplicationScene(
_ templateApplicationScene: CPTemplateApplicationScene,
didDisconnectInterfaceController interfaceController: CPInterfaceController
) {
self.interfaceController = nil
}
}
Scene Delegate(導航類)
導航類 App 會同時收到 Interface Controller 與 CPWindow。
請將 Window 的 rootViewController 設定為繪製地圖內容的 Controller。
func templateApplicationScene(
_ templateApplicationScene: CPTemplateApplicationScene,
didConnect interfaceController: CPInterfaceController,
to window: CPWindow
) {
self.interfaceController = interfaceController
self.carWindow = window
window.rootViewController = MapViewController()
let mapTemplate = CPMapTemplate()
mapTemplate.mapDelegate = self
interfaceController.setRootTemplate(mapTemplate, animated: true,
completion: nil)
}
Templates Overview
CarPlay 提供了一套固定的模板類型。App 負責提供數據內容,系統則負責在車載螢幕上渲染畫面。
通用模板 (General Purpose Templates)
| 模板 | 用途 |
|---|---|
CPTabBarTemplate |
包含分頁(Tab)子模板的容器 |
CPListTemplate |
可捲動的分組清單 |
CPGridTemplate |
可點擊圖示按鈕構成的網格(最多 8 個按鈕) |
CPInformationTemplate |
鍵值對資訊展示,最多支援 3 個操作按鈕 |
CPAlertTemplate |
模態警示框(Modal Alert),最多支援 2 個操作按鈕 |
CPActionSheetTemplate |
模態動作選單(Modal Action Sheet) |
類別專屬模板 (Category-Specific Templates)
| 模板 | 適用類別 |
|---|---|
CPMapTemplate |
導航 -- 帶有導航列的地圖覆蓋層 |
CPSearchTemplate |
導航 -- 目的地搜尋 |
CPNowPlayingTemplate |
音訊 -- 共用的「正在播放」畫面 |
CPPointOfInterestTemplate |
電動車充電 / 停車 / 餐飲 -- 興趣點(POI)地圖 |
CPContactTemplate |
通訊 -- 聯絡人卡片 |
導航階層 (Navigation Hierarchy)
使用 pushTemplate(_:animated:completion:) 將模板推入堆疊。
使用 presentTemplate(_:animated:completion:) 以模態方式顯示(Modal)。
使用 popTemplate(animated:completion:) 返回上一頁。
CPTabBarTemplate 必須設為根模板(Root)-- 無法透過 push 或 present 方式顯示。
CPTabBarTemplate
let browseTab = CPListTemplate(title: "Browse",
sections: [CPListSection(items: listItems)])
browseTab.tabImage = UIImage(systemName: "list.bullet")
let tabBar = CPTabBarTemplate(templates: [browseTab, settingsTab])
tabBar.delegate = self
interfaceController.setRootTemplate(tabBar, animated: true, completion: nil)
CPListTemplate
let item = CPListItem(text: "Favorites", detailText: "12 items")
item.handler = { selectedItem, completion in
self.interfaceController?.pushTemplate(detailTemplate, animated: true,
completion: nil)
completion()
}
let section = CPListSection(items: [item], header: "Library",
sectionIndexTitle: nil)
let listTemplate = CPListTemplate(title: "My App", sections: [section])
Navigation Apps
導航類 App 使用 com.apple.developer.carplay-maps。這是唯一能接收 CPWindow 用於繪製地圖內容的 App 類別。根模板必須是 CPMapTemplate。
行程預覽與路線選擇
let routeChoice = CPRouteChoice(
summaryVariants: ["Fastest Route", "Fast"],
additionalInformationVariants: ["Via Highway 101"],
selectionSummaryVariants: ["25 min"]
)
let trip = CPTrip(origin: origin, destination: destination,
routeChoices: [routeChoice])
mapTemplate.showTripPreviews([trip], textConfiguration: nil)
開始導航會話
extension CarPlaySceneDelegate: CPMapTemplateDelegate {
func mapTemplate(_ mapTemplate: CPMapTemplate,
startedTrip trip: CPTrip,
using routeChoice: CPRouteChoice) {
let session = mapTemplate.startNavigationSession(for: trip)
session.pauseTrip(for: .loading, description: "Calculating route...")
let maneuver = CPManeuver()
maneuver.instructionVariants = ["Turn right onto Main St"]
maneuver.symbolImage = UIImage(systemName: "arrow.turn.up.right")
session.upcomingManeuvers = [maneuver]
let estimates = CPTravelEstimates(
distanceRemaining: Measurement(value: 5.2, unit: .miles),
timeRemaining: 900)
session.updateEstimates(estimates, for: maneuver)
}
}
地圖按鈕
let zoomIn = CPMapButton { _ in self.mapViewController.zoomIn() }
zoomIn.image = UIImage(systemName: "plus.magnifyingglass")
mapTemplate.mapButtons = [zoomIn, zoomOut]
CPSearchTemplate
extension CarPlaySceneDelegate: CPSearchTemplateDelegate {
func searchTemplate(_ searchTemplate: CPSearchTemplate,
updatedSearchText searchText: String,
completionHandler: @escaping ([CPListItem]) -> Void) {
performSearch(query: searchText) { results in
completionHandler(results.map {
CPListItem(text: $0.name, detailText: $0.address)
})
}
}
func searchTemplate(_ searchTemplate: CPSearchTemplate,
selectedResult item: CPListItem,
completionHandler: @escaping () -> Void) {
// Navigate to selected destination
completionHandler()
}
}
Audio Apps
音訊類 App 使用 com.apple.developer.carplay-audio。它們在清單中顯示可瀏覽的內容,並使用 CPNowPlayingTemplate 作為播放控制介面。取得音訊授權的 App 無法使用 CPInformationTemplate。
正在播放模板 (Now Playing Template)
CPNowPlayingTemplate 是一個共用的單例物件(Singleton),會自動讀取來自 MPNowPlayingInfoCenter 的中繼資料(Metadata)。請勿自行建立新實例。
let nowPlaying = CPNowPlayingTemplate.shared
nowPlaying.isUpNextButtonEnabled = true
nowPlaying.isAlbumArtistButtonEnabled = true
nowPlaying.updateNowPlayingButtons([
CPNowPlayingShuffleButton { _ in self.toggleShuffle() },
CPNowPlayingRepeatButton { _ in self.toggleRepeat() }
])
nowPlaying.add(self) // Register as CPNowPlayingTemplateObserver
Siri 語音助理 Cell
支援 INPlayMediaIntent 的音訊類 App 可以顯示語音助理 Cell。
通訊類 App 則配合 INStartCallIntent 使用 .startCall。
let config = CPAssistantCellConfiguration(
position: .top, visibility: .always, assistantAction: .playMedia)
let listTemplate = CPListTemplate(
title: "Playlists",
sections: [CPListSection(items: items)],
assistantCellConfiguration: config)
Communication Apps
通訊類 App 使用 com.apple.developer.carplay-communication。
它們用於顯示訊息清單與聯絡人,並支援透過 Siri 發起通話的 INStartCallIntent。
CPMessageListItem 沒有提供 App 自訂的選取處理常式(Selection handler)。當使用者點選時,CarPlay 會根據項目的電話/電子郵件、未讀狀態或現有的對話設定,自動觸發 Siri 的撰寫、讀取或回覆行為。
let leading = CPMessageListItemLeadingConfiguration(
leadingItem: .star, leadingImage: nil, unread: true)
let trailing = CPMessageListItemTrailingConfiguration(
trailingItem: .none, trailingImage: nil)
let message = CPMessageListItem(
conversationIdentifier: "conv-123",
text: "Jane",
leadingConfiguration: leading,
trailingConfig




