Accelerate your app with CarPlay
System & Services 进阶 25m

使用 CarPlay 加速你的应用

Accelerate your app with CarPlay

2020年6月25日

在 Apple 官方观看视频

一句话判断

CarPlay 在 2020 年开放了更多应用类型——如果你的 App 涉及停车、充电或快餐点餐,现在可以在车机上了。

这场 Session 讲了什么

这场 Session 介绍了 CarPlay 在 2020 年的更新。CarPlay 是 Apple 的车载系统投影方案,将 iPhone 的界面投射到汽车的中控屏幕上。在此之前,CarPlay 只支持有限的应用类型(音频、导航、通信)。2020 年 Apple 新增了几种应用类型:停车、电动汽车充电和快餐点餐。

演讲者首先介绍了 CarPlay 的整体架构。CarPlay App 实际上运行在 iPhone 上,但 UI 通过 CarPlay 协议投射到汽车屏幕。你的 App 需要包含一个 CarPlay Scene,在用户连接 CarPlay 时系统会自动激活。

Session 的核心部分讲解了如何为 CarPay 创建 UI。CarPlay 的界面模板(Template)是预定义的——你不能自由绘制 UI,只能使用 Apple 提供的几种模板,如列表模板、网格模板、地图模板等。这种限制是为了保证驾驶安全——所有 CarPlay 界面都经过 Apple 的人机界面指南审核。

新增的应用类型部分,演讲者展示了如何实现停车应用的 CarPlay 界面——搜索附近停车场、显示价格和可用车位、导航到停车场。电动汽车充电应用类似,展示附近充电站和实时可用状态。

值得深挖的点

  • CarPlay Template 的限制与哲学:CarPlay 不允许自定义 UI——你只能使用 Apple 预定义的 Template。这是刻意的设计决策:驾驶场景下,UI 必须简单、一致、不需要学习。如果你需要在车机上展示的信息无法映射到现有 Template,你可能需要重新设计信息架构。
  • CarPlay 与主 App 的数据同步:CarPlay Scene 和主 App Scene 运行在同一个进程中,共享数据空间。但它们的 UI 线程是独立的。你需要确保两个 Scene 之间的数据同步(如用户在 CarPlay 上选了一个停车场,主 App 上也要更新)。

代码片段

// 配置 CarPlay Scene
class CarPlaySceneDelegate: UIResponder, CPTemplateApplicationSceneDelegate {
    var interfaceController: CPInterfaceController?

    func templateApplicationScene(
        _ templateApplicationScene: CPTemplateApplicationScene,
        didConnect interfaceController: CPInterfaceController
    ) {
        self.interfaceController = interfaceController

        // 创建 CarPlay 主界面
        let tabTemplate = CPTabBarTemplate(
            templates: [
                createParkingTemplate(),
                createFavoritesTemplate(),
                createRecentTemplate()
            ]
        )
        interfaceController.setRootTemplate(tabTemplate, animated: true)
    }
}
// 创建停车列表模板
func createParkingTemplate() -> CPListTemplate {
    let items = nearbyParkingLots.map { lot in
        CPListItem(
            text: lot.name,
            detailText: "\(lot.availableSpots) 个空位 · ¥\(lot.price)/小时",
            image: loadImage(url: lot.iconURL)
        )
    }

    let section = CPListSection(items: items)
    let template = CPListTemplate(
        title: "附近停车场",
        sections: [section]
    )

    template.listTemplateDelegate = self
    return template
}

// 处理列表项点击
func listTemplate(
    _ listTemplate: CPListTemplate,
    didSelect listItem: CPListItem,
    completionHandler: @escaping () -> Void
) {
    // 导航到选中的停车场
    let parking = selectedParkingLot
    let trip = CPTrip(
        origin: MKMapItem.forCurrentLocation(),
        destination: parking.mapItem,
        routeChoices: []
    )
    // 开始导航
    completionHandler()
}
// 在 Info.plist 中声明 CarPlay 支持
// <key>UIApplicationSceneManifest</key>
// <dict>
//   <key>UIApplicationSupportsMultipleScenes</key>
//   <true/>
//   <key>UISceneConfigurations</key>
//   <dict>
//     <key>CPTemplateApplicationSceneSessionRoleApplication</key>
//     <array>
//       <dict>
//         <key>UISceneClassName</key>
//         <string>CPTemplateApplicationScene</string>
//         <key>UISceneDelegateClassName</key>
//         <string>$(PRODUCT_MODULE_NAME).CarPlaySceneDelegate</string>
//       </dict>
//     </array>
//   </dict>
// </dict>

最佳实践

  • CarPlay 界面只展示驾驶时真正需要的信息,不要把手机 App 的完整 UI 照搬上去
  • 列表项的文字控制在两行以内,字体大小让驾驶员一眼就能看清
  • 所有交互操作控制在两步以内完成——用户不应需要多次点击才能执行关键操作
  • 测试时使用真实的 CarPlay 环境或 Xcode 的 CarPlay 模拟器
  • 适配不同尺寸的车机屏幕,确保在小屏和大屏上都清晰可读

还有什么值得关注

  • CarPlay 后来支持了更多的应用类型,包括加油和道路救援
  • iOS 14 的 Widgets 也可以在 CarPlay 中显示关键信息
  • 如果你在做导航类 App,Apple 的 MapKit 提供了完整的 CarPlay 导航模板
WWDC 2020