Carplay

作者 dpearson26998d90fd121a26無授權條款1.1K 個星標收錄於 2026年10月8日更新於 2026年10月8日儲存庫2 個月前更新

Build CarPlay-enabled apps using the CarPlay framework. Use when creating navigation, audio, communication, EV charging, parking, or food ordering apps for the car display, working with CPTemplateApplicationScene, CPInterfaceController template hierarchies, CPListTemplate, CPMapTemplate, CPNowPlayingTemplate, configuring CarPlay entitlements, or integrating with CarPlay Simulator for testing.

AI 產生的概覽

指導使用 CarPlay 框架建置支援 CarPlay 的 iOS 應用程式,涵蓋權限、場景、樣板與測試。

功能
提供使用 Swift 為 iOS 26 以上版本建置依類別授權的樣板式 CarPlay 應用程式的參考說明。內容涵蓋權限鍵、Info.plist 場景設定、場景委派設定,以及導航、音訊、通訊與興趣點應用程式的樣板階層,並說明 CarPlay 模擬器測試方式。此外也列出常見錯誤與審查清單。
適用情境
適用於建立或審查導航、音訊、通訊、電動車充電、停車或訂餐類 CarPlay 應用程式。也適用於設定 CarPlay 權限、CPTemplateApplicationScene、CPInterfaceController 樣板階層,或進行 CarPlay 模擬器測試。
執行需求
不含指令碼,僅為說明文件。需要 Xcode 與 iOS SDK(Swift 6.3、iOS 26 以上)、Apple 核准的 CarPlay 類別權限與佈建設定描述檔,以及具備 CarPlay 外接顯示器的 iOS 模擬器進行測試。

CarPlay

Build category-entitled, template-based CarPlay apps for the vehicle display. Scope: Swift 6.3, iOS 26+.

See references/carplay-patterns.md [blocked] for extended patterns including full navigation sessions, dashboard scenes, and advanced template composition.

Scope boundary: full CarPlay framework apps use category entitlements, CPTemplateApplicationScene, CPTemplateApplicationSceneDelegate, CPInterfaceController, and system CPTemplate navigation. CarPlay-visible WidgetKit widgets and ActivityKit Live Activities are separate system experiences; route their implementation to those domains while keeping CarPlay-specific validation here.

Contents

Entitlements and Setup

Request the category-specific entitlement from Apple's CarPlay entitlement form, accept the addendum, then provision the approved category key below.

Entitlement Keys by Category

EntitlementCategory
com.apple.developer.carplay-audioAudio
com.apple.developer.carplay-communicationCommunication
com.apple.developer.carplay-mapsNavigation
com.apple.developer.carplay-chargingEV Charging
com.apple.developer.carplay-parkingParking
com.apple.developer.carplay-quick-orderingQuick Food Ordering

Project Configuration

  1. Update the App ID in the developer portal under Additional Capabilities.
  2. Generate a new provisioning profile for the updated App ID.
  3. In Xcode, disable automatic signing and import the CarPlay provisioning profile.
  4. Add an Entitlements.plist with the entitlement key set to true.
  5. Set Code Signing Entitlements build setting to the Entitlements.plist path.

Key Types

TypeRole
CPTemplateApplicationSceneUIScene subclass for the CarPlay display
CPTemplateApplicationSceneDelegateScene connect/disconnect lifecycle
CPInterfaceControllerCarPlay-provided controller for setting the root template and pushing, presenting, or popping templates
CPTemplateAbstract base for all CarPlay templates
CPSessionConfigurationVehicle display limits and content style

Scene Configuration

Declare the CarPlay scene in Info.plist and implement CPTemplateApplicationSceneDelegate to respond when CarPlay connects.

Info.plist Scene Manifest

plist
<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 (Non-Navigation)

Non-navigation apps receive an interface controller only. No window.

swift
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 (Navigation)

Navigation apps receive both an interface controller and a CPWindow. Set the window's root view controller to draw map content.

swift
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 provides a fixed set of template types. The app supplies content; the system renders it on the vehicle display.

General Purpose Templates

TemplatePurpose
CPTabBarTemplateContainer with tabbed child templates
CPListTemplateScrollable sectioned list
CPGridTemplateGrid of tappable icon buttons (max 8)
CPInformationTemplateKey-value info with up to 3 actions
CPAlertTemplateModal alert with up to 2 actions
CPActionSheetTemplateModal action sheet

Category-Specific Templates

TemplateCategory
CPMapTemplateNavigation -- map overlay with nav bar
CPSearchTemplateNavigation -- destination search
CPNowPlayingTemplateAudio -- shared Now Playing screen
CPPointOfInterestTemplateEV Charging / Parking / Food -- POI map
CPContactTemplateCommunication -- contact card

Navigation Hierarchy

Use pushTemplate(_:animated:completion:) to add templates to the stack. Use presentTemplate(_:animated:completion:) for modal display. Use popTemplate(animated:completion:) to go back. CPTabBarTemplate must be set as root -- it cannot be pushed or presented.

CPTabBarTemplate

swift
let browseTab = CPListTemplate(title: "Browse",                               sections: [CPListSection(items: listItems)])browseTab.tabImage = UIImage(systemName: "list.bullet")
let tabBar = CPTabBarTemplate(templates: [browseTab, settingsTab])tabBar.delegate = selfinterfaceController.setRootTemplate(tabBar, animated: true, completion: nil)

CPListTemplate

swift
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

Navigation apps use com.apple.developer.carplay-maps. They are the only category that receives a CPWindow for drawing map content. The root template must be a CPMapTemplate.

Trip Preview and Route Selection

swift
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)

Starting a Navigation Session

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

Map Buttons

swift
let zoomIn = CPMapButton { _ in self.mapViewController.zoomIn() }zoomIn.image = UIImage(systemName: "plus.magnifyingglass")mapTemplate.mapButtons = [zoomIn, zoomOut]

CPSearchTemplate

swift
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

Audio apps use com.apple.developer.carplay-audio. They display browsable content in lists and use CPNowPlayingTemplate for playback controls. CPInformationTemplate is not available to audio-entitled apps.

Now Playing Template

CPNowPlayingTemplate is a shared singleton. It reads metadata from MPNowPlayingInfoCenter. Do not instantiate a new one.

swift
let nowPlaying = CPNowPlayingTemplate.sharednowPlaying.isUpNextButtonEnabled = truenowPlaying.isAlbumArtistButtonEnabled = truenowPlaying.updateNowPlayingButtons([    CPNowPlayingShuffleButton { _ in self.toggleShuffle() },    CPNowPlayingRepeatButton { _ in self.toggleRepeat() }])nowPlaying.add(self) // Register as CPNowPlayingTemplateObserver

Siri Assistant Cell

Audio apps supporting INPlayMediaIntent can show an assistant cell. Communication apps use INStartCallIntent with .startCall.

swift
let config = CPAssistantCellConfiguration(    position: .top, visibility: .always, assistantAction: .playMedia)let listTemplate = CPListTemplate(    title: "Playlists",    sections: [CPListSection(items: items)],    assistantCellConfiguration: config)

Communication Apps

Communication apps use com.apple.developer.carplay-communication. They display message lists and contacts, and support INStartCallIntent for Siri-initiated calls. CPMessageListItem has no app-provided selection handler. When selected, CarPlay invokes Siri compose, read, or reply behavior based on the item's phone/email, unread state, or existing conversation configuration.

swift
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,    trailingConfiguration: trailing,    detailText: "Meeting at 3pm",    trailingText: "2:45 PM")
let messageList = CPListTemplate(title: "Messages",                                 sections: [CPListSection(items: [message])])

Point of Interest Apps

EV charging, parking, and food ordering apps use CPPointOfInterestTemplate and CPInformationTemplate to display locations and details. CPPointOfInterestTemplate displays a maximum of 12 points of interest.

CPPointOfInterestTemplate

swift
let poi = CPPointOfInterest(    location: MKMapItem(placemark: MKPlacemark(        coordinate: CLLocationCoordinate2D(latitude: 37.7749,                                           longitude: -122.4194))),    title: "SuperCharger Station", subtitle: "4 available",    summary: "150 kW DC fast charging",    detailTitle: "SuperCharger Station", detailSubtitle: "$0.28/kWh",    detailSummary: "Open 24 hours",    pinImage: UIImage(systemName: "bolt.fill"))
poi.primaryButton = CPTextButton(title: "Navigate",                                 textStyle: .confirm) { _ in }
let poiTemplate = CPPointOfInterestTemplate(    title: "Nearby Chargers", pointsOfInterest: [poi], selectedIndex: 0)poiTemplate.pointOfInterestDelegate = self

CPInformationTemplate

swift
let infoTemplate = CPInformationTemplate(    title: "Order Summary", layout: .leading,    items: [        CPInformationItem(title: "Item", detail: "Burrito Bowl"),        CPInformationItem(title: "Total", detail: "$12.50")],    actions: [        CPTextButton(title: "Place Order", textStyle: .confirm) { _ in            self.placeOrder() },        CPTextButton(title: "Cancel", textStyle: .cancel) { _ in            self.interfaceController?.popTemplate(animated: true,                                                  completion: nil) }])

Testing with CarPlay Simulator

  1. Build and run in Xcode with the iOS simulator.
  2. Choose I/O > External Displays > CarPlay.

Default window: 800x480 at @2x. Enable extra options for navigation apps:

bash
defaults write com.apple.iphonesimulator CarPlayExtraOptions -bool YES

Recommended Test Configurations

ConfigurationPixelsScale
Minimum748 x 456@2x
Portrait768 x 1024@2x
Standard800 x 480@2x
High-resolution1920 x 720@3x

Simulator cannot test locked-iPhone behavior, Siri, audio coexistence with car radio, or physical input hardware (knobs, touch pads). Test on a real CarPlay-capable vehicle or aftermarket head unit when possible. Design primary CarPlay flows so they do not require iPhone input while CarPlay is active.

Common Mistakes

DON'T: Use the wrong scene delegate method

Navigation apps must implement templateApplicationScene(_:didConnect:to:) (with CPWindow). Non-navigation apps use templateApplicationScene(_:didConnect:) (no window). Using the wrong variant produces no CarPlay UI.

DON'T: Draw custom UI in the navigation window

CPWindow is exclusively for map content. All overlays, alerts, and controls must use CarPlay templates.

DON'T: Push or present CPTabBarTemplate

CPTabBarTemplate can only be set as root. Pushing or presenting it fails. Use setRootTemplate(_:animated:completion:).

DON'T: Instantiate CPNowPlayingTemplate

Use CPNowPlayingTemplate.shared. Creating a new instance causes issues.

DON'T: Add handlers to CPMessageListItem

CPMessageListItem is Siri-managed, unlike CPListItem. Do not set message.handler; use the item configuration and userInfo for context.

DON'T: Treat widgets as CarPlay template apps

CarPlay-visible widgets and Live Activities belong to WidgetKit and ActivityKit. Use this skill for category-entitled CarPlay template app scenes and for validating those surfaces in the car context.

DON'T: Ignore vehicle display limits

Check CPSessionConfiguration.limitedUserInterfaces and respect maximumItemCount / maximumSectionCount on list templates.

DON'T: Forget to call the completion handler

CPListItem.handler must call its completion handler in every code path. Failure leaves the list in a loading state.

Review Checklist

  • Correct CarPlay entitlement key in Entitlements.plist
  • UIApplicationSupportsMultipleScenes set to true
  • CPTemplateApplicationSceneSessionRoleApplication scene in Info.plist
  • Scene delegate class name matches UISceneDelegateClassName
  • Correct delegate method used (with/without CPWindow)
  • Root template set in didConnect before returning
  • Interface controller and window references cleared on disconnect
  • CPTabBarTemplate only used as root, never pushed
  • CPNowPlayingTemplate.shared used, not a new instance
  • Communication rows use CPMessageListItem without custom handlers
  • WidgetKit/ActivityKit surfaces routed outside CarPlay template app code
  • maximumItemCount/maximumSectionCount checked before populating lists
  • CPListItem.handler calls completion in every path
  • Map-only content in CPWindow root view controller (navigation apps)
  • App functions while iPhone is locked
  • Tested at minimum, standard, and high-resolution simulator sizes
  • Audio session deactivated when not actively playing

References

來源與署名

來源:dpearson2699/swift-ios-skills位於skills/carplay提交8d90fd1

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架

更多來自 dpearson2699/swift-ios-skills 的技能

Widgetkit

dpearson2699

指導實作、審查與改進 iOS、iPadOS、watchOS 與 CarPlay 上的 WidgetKit 小工具與控制項。

Software Development1.1K2 個月前更新

Weatherkit

dpearson2699

指導 iOS 開發者使用 WeatherService 取得 WeatherKit 預報、警報與署名資訊。

Software Development1.1K2 個月前更新

Vision Framework

dpearson2699

Implement computer vision features including text recognition (OCR), face detection, barcode scanning, image segmentation, object tracking, and document scanning in iOS apps. Covers both the modern Swift-native Vision API (iOS 18+) and legacy VNRequest patterns, VisionKit DataScannerViewController for live camera scanning, and CoreMLRequest/VNCoreMLRequest for custom model inference. Use when adding OCR, barcode scanning, face detection, or custom Core ML model inference with Vision.

待分類1.1K2 個月前更新

Tipkit

dpearson2699

Implement and review Apple TipKit feature-discovery UI for iOS 17+ apps. Use when adding or auditing in-app tips, contextual help, coach marks, Tip, TipView, popoverTip, rules, events, actions, display frequency, testing overrides, reusable tip identifiers, or iOS 18+ TipGroup and CloudKit tip sync; avoid for generic SwiftUI navigation or layout outside tip presentation.

待分類1.1K2 個月前更新

Tabletopkit

dpearson2699

指導使用 TabletopKit 在 visionOS 上打造多人空間桌遊,涵蓋棋具、座位、動作與 RealityKit 算繪。

Software Development1.1K2 個月前更新

Swiftui Webkit

dpearson2699

指導在 iOS 26 及更新版本的 SwiftUI App 中使用 WebKit for SwiftUI 嵌入與控制網頁內容。

Software Development1.1K2 個月前更新