carplay-ordering
Guide for building CarPlay quick-ordering apps (food ordering, pickup, etc.) using the CarPlay framework. Use this skill whenever the user wants to build a CarPlay ordering app, integrate CarPlay templates for food/drink/pickup ordering, work with CPPointOfInterestTemplate, CPListTemplate, CPTabBarTemplate, or CPInterfaceController for ordering workflows. Also trigger when the user mentions CarPlay entitlements, Live Activities with CarPlay ordering, or push notification updates for order status. Covers the full lifecycle: entitlement setup, template hierarchy, map-based POI selection, order placement, Live Activity integration, and push token management.
What this skill does
# CarPlay Quick-Ordering App Integration
Build a CarPlay-enabled ordering app that displays custom ordering options in a vehicle using Apple's CarPlay framework.
## When to Use This Skill
- Building a food/drink ordering app with CarPlay support
- Integrating `CPPointOfInterestTemplate`, `CPListTemplate`, or `CPTabBarTemplate`
- Setting up CarPlay entitlements and provisioning profiles
- Implementing order status with Live Activities from a CarPlay context
- Handling map region changes and location-based search in CarPlay
- Managing push notifications for order status updates
## Prerequisites
- iOS 17.2+ / iPadOS 17.2+ / Mac Catalyst 17.2+ / macOS 14.0+
- Xcode 15.4+
- CarPlay quick-ordering entitlement (request at https://developer.apple.com/contact/carplay)
## Entitlement Setup
1. Log in to Apple Developer and create a provisioning profile with the CarPlay quick-ordering entitlement
2. Import the provisioning profile into Xcode
3. Create an `Entitlements.plist` (if not already present)
4. Add the CarPlay quick-ordering entitlement key as a Boolean
5. Ensure `CODE_SIGN_ENTITLEMENTS` in target build settings points to the `Entitlements.plist`
## Architecture Overview
The app connects to CarPlay via `CPTemplateApplicationSceneDelegate`. The template hierarchy is:
```
CPInterfaceController (root controller)
└── CPTabBarTemplate
└── CPPointOfInterestTemplate (map with ordering locations)
└── CPListTemplate (order details/menu items)
```
Key classes and their roles:
- **`CPInterfaceController`** — Manages the template stack and presentation
- **`CPTabBarTemplate`** — Top-level tab container
- **`CPPointOfInterestTemplate`** — Map view showing up to 12 POI locations
- **`CPListTemplate`** — Displays menu items and order options
- **`CPTextButton`** — Action buttons (Order, Directions, Call)
- **`CPAlertTemplate`** — Alert dialogs (e.g., location permission prompts)
- **`CPSessionConfiguration`** — Session configuration delegate
## Connection Lifecycle
When CarPlay connects, implement `CPTemplateApplicationSceneDelegate`:
```swift
func interfaceControllerDidConnect(
_ interfaceController: CPInterfaceController,
scene: CPTemplateApplicationScene
) {
carplayInterfaceController = interfaceController
carplayScene = scene
carplayInterfaceController?.delegate = self
sessionConfiguration = CPSessionConfiguration(delegate: self)
locationManager.delegate = self
requestLocation()
setupMap()
}
```
Set the root template as a `CPTabBarTemplate` containing a `CPPointOfInterestTemplate`:
```swift
func setupMap() {
let poiTemplate = CPPointOfInterestTemplate(
title: "Options",
pointsOfInterest: [],
selectedIndex: NSNotFound
)
poiTemplate.pointOfInterestDelegate = self
poiTemplate.tabTitle = "Map"
poiTemplate.tabImage = UIImage(systemName: "car")!
let tabTemplate = CPTabBarTemplate(templates: [poiTemplate])
carplayInterfaceController?.setRootTemplate(tabTemplate, animated: true) { done, error in
self.search(for: "YourSearchTerm")
}
}
```
> **Important:** A maximum of 12 POI locations can appear on the CarPlay display.
## Map Region Updates
Implement `CPPointOfInterestTemplateDelegate` to refresh results as the user pans the map:
```swift
extension TemplateManager: CPPointOfInterestTemplateDelegate {
func pointOfInterestTemplate(
_ aTemplate: CPPointOfInterestTemplate,
didChangeMapRegion region: MKCoordinateRegion
) {
boundingRegion = region
search(for: "yourQuery")
}
}
```
## POI Action Buttons
Each point of interest supports a primary and secondary button. Use the primary for ordering, and the secondary for navigation or calling:
```swift
// Primary: Order button
let orderButton = CPTextButton(title: "Order", textStyle: .normal) { button in
self.showOrderTemplate(place: place)
}
place.primaryButton = orderButton
// Secondary: Directions (via Maps) or Call
if let address = place.summary,
let encoded = address.addingPercentEncoding(withAllowedCharacters: .alphanumerics),
let lon = place.location.placemark.location?.coordinate.longitude,
let lat = place.location.placemark.location?.coordinate.latitude,
let url = URL(string: "maps://?q=\(encoded)&ll=\(lon),\(lat)") {
place.secondaryButton = CPTextButton(title: "Directions", textStyle: .normal) { _ in
self.carplayScene?.open(url, options: nil, completionHandler: nil)
}
} else if let phone = place.subtitle,
let url = URL(string: "tel://" + phone.replacingOccurrences(of: " ", with: "")) {
place.secondaryButton = CPTextButton(title: "Call", textStyle: .normal) { _ in
self.carplayScene?.open(url, options: nil, completionHandler: nil)
}
}
```
## Location Permission Handling
Handle authorization changes gracefully. If location is denied, present an alert and clear the root template:
```swift
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch manager.authorizationStatus {
case .denied, .restricted, .notDetermined:
let alert = CPAlertTemplate(
titleVariants: ["Please enable location services."],
actions: [
CPAlertAction(title: "Ok", style: .default) { [weak self] _ in
self?.carplayInterfaceController?.setRootTemplate(
CPTabBarTemplate(templates: []),
animated: false,
completion: nil
)
}
]
)
// Dismiss any existing presented template first
if carplayInterfaceController?.presentedTemplate != nil {
dismissAlertAndPopToRootTemplate {
self.carplayInterfaceController?.presentTemplate(alert, animated: false, completion: nil)
}
} else {
carplayInterfaceController?.presentTemplate(alert, animated: false, completion: nil)
}
default:
dismissAlertAndPopToRootTemplate {
self.setupMap()
}
}
}
```
## Order Status with Live Activities
After a user places an order, start a Live Activity to show status on the Lock Screen. Live Activities don't display in CarPlay but provide glanceable updates:
```swift
let attrs = OrderStatusAttributes(order: order)
let initialState = OrderStatusAttributes.ContentState(
isPickedUp: false,
isReady: false,
isPreparing: false,
isConfirmed: true
)
let activity = try Activity.request(
attributes: attrs,
content: .init(state: initialState, staleDate: Date(timeIntervalSinceNow: 60 * 30)),
pushType: .token
)
```
### Listening for Updates
Set up listeners for content updates, state changes, and push token updates. This is critical because quick-ordering apps spend time in the background — use push notifications for updates:
```swift
// Content updates
Task { @MainActor in
for await change in activity.contentUpdates {
try saveOrderState(state: change.state)
WidgetCenter.shared.reloadAllTimelines()
}
}
// Activity state (ended/dismissed)
Task { @MainActor in
for await state in activity.activityStateUpdates {
if state == .dismissed || state == .ended {
await activity.end(nil, dismissalPolicy: .immediate)
}
WidgetCenter.shared.reloadAllTimelines()
}
}
// Push token for remote updates
Task { @MainActor in
for await pushToken in activity.pushTokenUpdates {
let tokenString = pushToken.reduce("") { $0 + String(format: "%02x", $1) }
try await sendPushToken(order: order, pushTokenString: tokenString)
}
}
```
### Push Notification JWT
For server-side push notifications to update Live Activities, create a JWT using P256 signing:
```swift
let privateKey = try P256.Signing.PrivateKey(pemRepresentation: pemString)
let header = try JSONEncoder().encode(header).urlSafeBase64EncodedString()
let payload = try JSONEncoder()Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.