Search code examples
iosswiftswiftuicarplay

Adding CarPlay to a SwiftUI lifecycle app


What is the recommended way to integrate CarPlay into an app which uses a SwiftUI lifecycle ?

@main
struct MyApp: App {
  var body: some Scene {
    WindowGroup {
      ContentView()
    }
  }
}

How do I use the CPTemplateApplicationSceneDelegate here ?


Solution

  • If you don't have a custom app delegate and/or scene delegate (you might need it eventually for stuff like push notifications) it should be enough to let your app know via the info.plist. You need a scene delegate for the CarPlay scene and add the following to your info.plist:

    <dict>
        <key>UIApplicationSupportsMultipleScenes</key>
        <true/>
        <key>UISceneConfigurations</key>
        <dict>
            <key>CPTemplateApplicationSceneSessionRoleApplication</key>
            <array>
                <dict>
                    <key>UISceneClassName</key>
                    <string>CPTemplateApplicationScene</string>
                    <key>UISceneConfigurationName</key>
                    <string>TemplateSceneConfiguration</string>
                    <key>UISceneDelegateClassName</key>
                    <string>AppFeature.CarPlaySceneDelegate</string>
                </dict>
            </array>
        </dict>
    </dict>
    

    The value for UISceneConfigurationName is handed to you in the scene delegate's scene(_:willConnectTo:options:) session.configuration.name. The value for UISceneDelegateClassName has to match your CarPlay scene delegate's Type name. Note that if you encapsulate your CarPlay code in a package/framework you need to prefix the delegate's name with the module name (in this case AppFeature). If the delegate is in your app target just use CarPlaySceneDelegate.

    An excerpt of the scene delegate might look like this:

    class CarPlaySceneDelegate: UIResponder, CPTemplateApplicationSceneDelegate {
      let templateManager = TemplateManager() // see Apple's sample code
    
      func templateApplicationScene(_: CPTemplateApplicationScene, didConnect interfaceController: CPInterfaceController) {
        templateManager.connect(interfaceController)
      }
    
      func templateApplicationScene(_: CPTemplateApplicationScene, didDisconnectInterfaceController _: CPInterfaceController) {
        templateManager.disconnect()
      }
    }