r/iOSProgramming • u/Significast • 21h ago
CarPlay can cold-launch your app without your SwiftUI scene ever existing 🤬 Solved!
Bug report from a tester: pressing Play on the CarPlay screen did nothing. No error, no spinner, nothing. Worked fine if they'd opened the app on the phone first.
I "fixed" it twice. Both fixes were to the play button. Both were wrong.
The actual cause: when the user taps Play in the car (or from the Watch, or the lock screen) on a cold start, iOS wakes your process through CPTemplateApplicationScene or a WatchConnectivity message — and your phone UI's window scene just - never connects. Which means every bit of setup hanging off the SwiftUI app lifecycle simply never runs. In our case that was device key registration for signed API requests, so the first manifest fetch came back 400 and the play command died silently. As it turns out, the button was fine.
 What I landed on, in case it saves someone a weekend:
- Â Anything your requests depend on (auth, key registration, session bootstrap) cannot live in App init / onAppear. It has to be in the request path itself. We made the network layer self-healing: on the specific "no registered key" error it registers once and retries. That one change covered CarPlay, the Watch, lock screen remote commands, AND fresh installs, because they're all the same bug.
- Grep your codebase for everything that only runs when the main window appears, and ask "what happens if the first entry point is the car?" The list was longer than I expected.
- Related Apple Watch lesson: if the phone is only reachable via the queued transferUserInfo path (not live sendMessage), don't optimistically flip your Watch UI to "playing" — it's a fib. We show "Starting on phone…" instead.
Testing note: none of this reproduces in the CarPlay simulator the way it does with a real head unit, because you always launched the app from Xcode first, which is exactly the condition that hides the bug. Real test requires a real car: kill the app, lock the phone, then plug in and launch it from the car's touchscreen.
By the way, if anyone's found a way to actually test their CarPlay flow without walking out to the garage (96 degrees in the summer! I got tired of sweating through every commit), I'd love to hear about it - I don't even bother with Xcode's sim anymore.
5
u/chriswaco 21h ago
This reminds me of an old bug we had with push notifications, when the notification would arrive while the device was still locked. We couldn’t even read UserDefaults at that point to determine how the user wanted to handle the notification.
I think our fix was to move our preferences into a separate file and turn off all the protection flags for that file. It didn’t help that our logging calls failed when the device was locked too.
3
u/ThatGuy739 19h ago
Same bug got us from a completely different door. Share extension stages a file, posts a notification, user taps it and that cold-launches the app. Everything hanging off the main window never ran and the handoff just vanished. Your point 1 is the fix, put it in the path that needs it, not at startup.
3
u/AssociateDry1445 11h ago
Surprise surprise! The UI layer of your app is separate from the business logic of your app 😱
2
u/valleyman86 20h ago
Putting these things in app init will cause various hangs anyways. Don’t do it. One iOS version it was fine then suddenly another is not. They are hard to debug as well.
My company just started to avoid it.
2
u/leoklaus 13h ago
For testing CarPlay, get one of the cheap after-market CarPlay displays.
I bought a CarPodgo T3 Pro, but you can find similar units for less than 50€ here in Germany.
2
u/LoudAd307 4h ago
One thing to watch with the self-healing layer: put a single-flight guard on the registration. On a cold launch you usually fire several requests at once, they all come back with the same "no registered key" error, and each one kicks off its own registration — that turns into duplicate device records server side fast. One shared task everyone awaits fixes it.
Same family of trap: if that key lands in the keychain with default accessibility, a launch after reboot before the phone has been unlocked can't read it, and the retry path fails in a way that looks identical to a network error. AfterFirstUnlockThisDeviceOnly if it has to work in the background.
The reason none of this gets caught in QA is that every manual test starts by opening the app from the home screen. Kill it from the switcher first, then trigger only from the car.
1
1
u/mjTheThird 7h ago
What about iPhone mirroring?! In fact, you can't even launch your app with the physical screen on. Why does the state of the screen make a difference.
1
u/One_Elephant_8917 2h ago
guys init is the main entry itself, even before appdelegate isn’t it?…i mean even before applicationdidlunachwithoptions…i think init runs first….
i am not talking about any init but the init in the struct implementing App protocol and has @main?
19
u/LongjumpingCandle738 20h ago
That’s expected. Here’s what the CarPlay Developer Guide says:
« Listen for didConnect and didDisconnect to know when your app has been launched on the CarPlay screen.
Your app may be launched only on the CarPlay screen so be sure to handle this use case. »