0

I have a full SwiftUI project/app (In the AppStore) that I would like to add some CarPlay functionality. I have the entitlement correctly setup and am able to see the icon on the CarPlay simulator.

I have tried various info.plist configurations with various class configurations and only achieve crashes at the moment when starting the app in the simulator.

I'm a bit confused about the way to go about displaying views. I would like to start with a simple "Hello world" but even that is challenging :)

This question seems to be the kind of thing that I require but doesn't go in to enough details on the AppDelegate configuration.

iOS 15.4 - SwiftUI + CarPlay - State not updating

This looks promising but again not enough detail for me:

https://dev.to/nitricware/adding-carplay-to-a-swiftui-life-cycle-app-h9h

This too , but I suspect it's an older way of displaying the views.

https://www.adapptor.com.au/blog/enhance-existing-apps-with-carplay

If I could get help with a simple "Hello World" I would be most grateful!

From info.plist

 <key>UIApplicationSceneManifest</key>
        <dict>
            <key>UIApplicationSupportsMultipleScenes</key>
            <true/>
            <key>UISceneConfigurations</key>
            <dict>
                <key>CPTemplateApplicationSceneSessionRoleApplication</key>
                <array>
                    <dict>
                        <key>UISceneDelegateClassName</key>
                        <string>$(PRODUCT_MODULE_NAME).CarPlaySceneDelegate</string>
                    </dict>
                </array>
            </dict>
        </dict>

CarPlaySceneDelegate.swift

import Foundation
import CarPlay

class CarPlaySceneDelegate: UIResponder, CPTemplateApplicationSceneDelegate {
    
  func templateApplicationScene(_ templateApplicationScene: CPTemplateApplicationScene,
                                  didConnect interfaceController: CPInterfaceController) {
    
    let screen = CPInformationTemplate(title: "Root", layout: .leading, items: [CPInformationItem(title: "Hello", detail: "CarPlay")], actions: [])
    
    interfaceController.setRootTemplate(screen, animated: true, completion: { _,_ in
        // Do nothing
    })
  }
}

Thanks

jat
  • 183
  • 3
  • 14
  • What crash do you get? Have you added a `CPTemplateApplicationSceneSessionRoleApplication` to your `UIApplicationSceneManifest`? – Paulw11 May 08 '23 at 08:27
  • This is the error "application does not implement carplay template application lifecycle methods in its scene delegate", always the same. And yes absolutely, I have added both, as advised by the example links I gave. – jat May 08 '23 at 08:37
  • 1
    Can you edit your question to show the `UIApplicationSceneManifest` section of your info.plist (right click and open as source to get the XML) and your class that implements `CPTemplateApplicationSceneDelegate`? – Paulw11 May 08 '23 at 08:52
  • Added as requested thanks – jat May 08 '23 at 09:05
  • 1
    The files look ok, but that error is a bit misleading. You will also get that error if the class that is nominated as the CarPlay scene delegate can't be loaded. Your code worked for me, so I suspect it can't actually load the class. Try replacing `$(PRODUCT_MODULE_NAME)` with your actual target name (replacing any spaces with _). Also, ensure that if you have multiple targets in your Xcode project you have added the delegate class to the correct target – Paulw11 May 08 '23 at 09:25
  • No luck. I noticed that my original project didn't have the CarPlay framework added. But adding this didn't change anything. Also confirmed and tried your other ideas. I have also created a new SwiftUI project and recreated the setup. Still the same error. – jat May 08 '23 at 13:37
  • 1
    It probably still isn't able to load the class. Check in the device console log when you run your app on CarPlay. There may be more messages to give you a hint. – Paulw11 May 08 '23 at 20:07
  • *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Application does not implement CarPlay template application lifecycle methods in its scene delegate.' *** First throw call stack: 0x1a76c2fe0 0x1a768705c 0x1a76c2c38 0x100ba6038 0x100ba9aa0 0x1a7691188 0x1a7690d24 0x1a76935d0 0x19172c208 0x191738864 0x1916bd6c8 0x1916d31c4 0x1916d84dc 0x1cc94435c 0x193a6437c 0x193a63fe0 0x1950a63d8 0x19500c9b0 0x194ff6a54 0x10078a8ec 0x10078a998 0x1b0b6cdec) libc++abi: terminating due to uncaught exception of type NSException – jat May 09 '23 at 07:29
  • 1
    Was that in the Xcode console or the device console? View the device console via the devices and simulators window. – Paulw11 May 09 '23 at 10:38
  • @Paulw11 I found the device logs in devices and simulators. When clicking on "View Device Logs", is this what you are referring to? Nothing obvious in there unfortunately. – jat May 10 '23 at 08:10
  • 1
    Here is a simple 'hello world' CarPlay app - https://github.com/paulw11/CPHelloWorld - It is an audio CarPlay entitlement app, so you might need to change entitlements.plist. You will also need to change the bundle id and provisioning profile to match your bundle – Paulw11 May 15 '23 at 23:57
  • Perfect thankyou, only differences with your working version seem to be with the info.plist. Will award bounty when I can after the bounty period. – jat May 16 '23 at 09:01
  • 1
    I need to add an answer. Is there anything in particular different in the info.plist ? – Paulw11 May 16 '23 at 09:02
  • I am a bit of loss trying to reproduce the issue I'm afraid. Using your project and replacing the CarPlaySceneDelegate with the one I originally posted above works fine. And the info.plist in your project is the same as the one that I posted too. – jat May 17 '23 at 13:59

2 Answers2

4

I had been having the same issue as described above. I was trying to add CarPlay functionality to an existing SwiftUI app; but, launching the app in CarPlay resulted in the 'NSGenericException', reason: 'Application does not implement CarPlay template application lifecycle methods in its scene delegate.' error.

I downloaded Paulw11's CPHelloWorld project (Thanks, Paul!) and got it to function as expected. I then compared the CPHelloWorld's entitlements, info.plist, CarPlaySceneDelegate, etc. with mine, and everything seemed to be the same. Yet, his worked and mine didn't. I then started a new SwiftUI template project and brought the CarPlay functionality in from CPHelloWorld and confirmed it worked. Then, I brought in all the source code, package dependencies, and project settings from my project - checking at every step that the CarPlay app still launched correctly. Eventually I had my app pieced back together in this new project with a functioning CarPlay scene.

So why was my original attempt still failing? I started comparing build settings and found something involving scenes that was different. I the apps that worked with CarPlay the "Application Scene Manifest (Generation)" was set to NO. In my original app, (which wasn't working despite the entitlements, info.plist, and CarPlaySceneDelegate being the same), this was set to YES. No idea when it got turned on, but there it was.

I went back to my not-working-with-CarPlay app and turned off this build setting ("Application Scene Manifest (Generation)" == NO), and then I could launch my app in CarPlay and see the root template in the simulator.

Target -> Build Settings -> "Application Scene Manifest (Generation)" == NO

  • Good find thanks. Sounds very similar to my experience. I had to piece together as you described and eventually got my project to work (Thanks Paul too :) – jat Jun 04 '23 at 06:01
  • brilliant thanks - maybe this is because I started my project as a Multiplatform swiftUI app ? and not just pure iOS – Halpo Jul 16 '23 at 19:35
1

Not sure if it will change anything but your dictionary in Indi.plist seems incomplete , try this one :

<key>UISceneConfigurations</key>
<dict>
    <key>CPTemplateApplicationSceneSessionRoleApplication</key>
    <array>
        <dict>
            <key>UISceneClassName</key>
            <string>CPTemplateApplicationScene</string>
            <key>UISceneDelegateClassName</key>
            <string>$(PRODUCT_MODULE_NAME).CarPlaySceneDelegate</string>
            <key>UISceneConfigurationName</key>
            <string>CarPlay</string>
        </dict>
    </array>
</dict>
Ptit Xav
  • 3,006
  • 2
  • 6
  • 15
  • Didn't help but thanks. Doesn't having a "UISceneConfigurationName" mean that I require an appDelegate configuration with : let scene = UISceneConfiguration(name: "CarPlay" etc ? Which I don't currently have, and haven't been able to get to work. – jat May 08 '23 at 20:01
  • 1
    @jat I have these extra keys in my plist, but I commented them when I saw you didn't have them and my app still worked – Paulw11 May 08 '23 at 20:05
  • Ok will check - would it be possible for you to share your most basic working “Hello world” project by any chance? – jat May 09 '23 at 04:39
  • @Paulw11 are you using AppDelegate and SceneDelegate in your project ? I wonder if this is what I am missing somehow – jat May 09 '23 at 06:55
  • 1
    I have an AppDelegate but no scene delegate. My app is SwiftUI based. The only reason I have an app delegate is I need to create a Bluetooth manager object in `didFinishLaunching` to handle Bluetooth state restoration. – Paulw11 May 09 '23 at 07:13
  • @Paulw11 Just out of interest are you running the simulator on an m1/m2 mac or an intel with T2 security chip ? Thanks – jat May 09 '23 at 08:04
  • 1
    I am running on an m1 Mac. I also connect my device to my car and use a real CarPlay head unit – Paulw11 May 09 '23 at 09:19
  • @Paulw11 OK, thanks. That rules out the issue with the simulator on an M1/M2 Mac then. Is there any possibility of you sharing a very basic working project please ? – jat May 10 '23 at 08:11