-
Notifications
You must be signed in to change notification settings - Fork 131
Draft: Add example and documentation for stand-alone apps with support for launching on vehicle client #158
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Clone the original example as stand-alone-example in order to demonstrate launching an app using this package directly on the CarPlay-/AndroidAuto-client without having the app running on the phone. The stand-alone-example only renders a placeholder text on phone and contains all it's CarPlay-logic inside hooks which listen for - CarPlay connection changes - state changes (via useReducer) The stand-alone-example CarPlay-app features a TabTemplate as root template containing a top-level ListTemplate with two browsable items. Selecting a top-level item pushes a new (sub-level) ListTemplate onto the CarPlay-stack, which contains two non-browsable items. Selecting a sub-level item presents a CarPlay modal.
Do not create multiple bridges in PhoneScene. Reuse the AppDelegates rootView and window.
When launching the CarPlay scene directly on the CarPlay-client, create a bridge for the AppDelegate. Again check for an already existing bridge in order to not create multiple bridges: If the app is already running on the phone, a bridge will already be present on the AppDelegate. If not: create one for the CarPlay scene.
This adds and uses an alternative approach to initializing the app provided by @gavrichards: - Do not call RCTAppDelegate's application:didFinishLaunchingWithOptions but instead cherry-pick the code from RCTAppDelegate's application:didFinishLaunchingWithOptions except for window and rootViewController creation - move window and rootViewController creation to PhoneScene since they're not needed in stand-alone CarScene - call initAppFromScene() both in PhoneScene and CarScene to init the app. This approach works for both startup scenarios, both on Phone and on CarPlay-client. Bonus: The rootView property is stored in AppDelegate, so it can be used in PhoneScene (i.e. to pass to RNBootSplash if used) Caveat: The code in initAppFromScene() needs to be adjusted to the specific version of react native you are using! The version used in stand-alone-example is currently 0.71.13, so the code is taken from that versions RCTAppDelegate and converted to Swift (with a little help from ChatGPT for the C++ block, so no guarantee that it works! I'm not on RN's new architecture yet).
|
This is still a draft, since it covers only CarPlay for now. The Android part is simply a copy of the original example. For a while I thought I'd be fine with the solution from @mitchdowney over at Podverse outlined in this PR (still present but commented out as "Approach 1" in the new stand-alone-example app) but after a while I found that it produced unpredictable and buggy results in combinations of phone app running/not running or starting on CarPlay first, then on phone, then killing phone again, etc... Finally, after inspiration from @gavrichards ("Approach 2" in the new stand-alone-example app, initially outlined in this issue) and a lot of native debugging on the console of the physical device (since you don't have either Xcode nor React Native logs available when in CarPlay stand-alone mode!) I found this solution to work reliably in all circumstances / launch orders / lifecycle states. Thanks to @gavrichards for the groundwork around Feel free to comment and add improvements. |
External display connection invokes scene:willConnectTo:options again with the session.role .windowExternalDisplayNonInteractive: https://developer.apple.com/documentation/uikit/windows_and_screens/presenting_content_on_a_connected_display This needs to be explicitly handled or rejected, otherwise the app crashes with the error: Terminating app due to uncaught exception 'UIViewControllerHierarchyInconsistency', reason: 'A view can only be associated with at most one view controller at a time!"
|
@DanielKuhn For what it is worth, I tried re-opening the discussion about compatibility of RN with scenes here. |
|
Even this works & spawns the RN app but lots of apps have logic embeded inside components withing the App. So this is usefull only to show some "initial" termplate. |
I'm using this approach to render a "stand-alone" CarPlay-app. All logic for the app is encapsulated within a single component with hooks handling the CarPlay-events as outlined in the example I'm also controlling react-native-track-player via these hooks in my production app. |
|
@DanielKuhn Yes but this is not a real world example. In my case I use other player providers that are working only after render(). In this case I have to introduce |
|
It's a very real world example with a couple 100k users 😄 |
|
You are right about that app should not render anything. But I get weird results while app is started. |
|
@DanielKuhn hi, have you already tried to update to react-native 0.74? |
|
@DanielKuhn do you encounter app crash after re-connecting to carplay and clicking on any item that has onClick callback? |
|
@alex-vasylchenko I haven't updated to 0.74 yet, but as I mentioned on Discord: Every RN upgrade requires an adaptation of the @KestasVenslauskas I'm using version 2.3.0 still and I do observe blinking list elements occasionally, but only in the CarPlay Simulator, not on real devices. No crashes either. |
|
@DanielKuhn Did you manage to run the app from Android Auto directly (without running the app on mobile device first)? There is nothing but "RNCarPlay loading..." screen in such scenario. |
I'm not an Android developer, therefore I cannot say whether it is even possible to start a react native app in headless mode directly from Android Auto. Actually that's the main reason this pull request is still a draft. What we did in our production app was to require the "draw over apps"-permission in Android, so that the app can be started while the phone is actually locked. This way, while not headless like in iOS, the app can still handle all events coming from Android Auto. |
|
Has anyone applied these changes to RN 0.74.x-based project? |
|
Hm - I just checked my CarPlay module and my imports look like this: Not sure why that is (autogenerated by IntelliJ IDEA), but it works. Concerning Android: There's no Android code in my fork other than the (empty) example in |
It's just because my codebase is doing imports from 'react-native-carplay' but the package doesn't exist, for the same reason as the IDE is saying. Not specific to Android I don't think. The thing with your code sample is that you're importing from |
|
I presume so, too (the code is over 2 years old, not sure about the ins and outs anymore) |
|
so i do wrap carplay in a hook with paltform.os check, and can safely
unlink android like so; understandable if its not worth refactoring. heres
my patch package to 2.4beta before i moved to unlinking which worked 5mo
ago with 0.77, nothing complicated
https://github.com/lovegaoshi/azusa-player-mobile/blob/v3.2.0/patches/react-native-carplay%2B2.4.1-beta.0.patch
…On Fri, Jun 13, 2025, 8:40 AM Daniel Kuhn ***@***.***> wrote:
*DanielKuhn* left a comment (birkir/react-native-carplay#158)
<#158 (comment)>
I presume so, too (the code is over 2 years old, not sure about the ins
and outs anymore)
—
Reply to this email directly, view it on GitHub
<#158 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AZMOVVWL7NCUDYENXC3ROH33DLWILAVCNFSM6AAAAAA7USZFISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDSNZQG44DEMJYGE>
.
You are receiving this because you commented.Message ID:
***@***.***>
|
|
and good luck folks, just saw RN 0.80 dropped... |
|
In the end I decided to revert to this repository, use |
|
@DanielKuhn have you tried my solution in production yet? I've got a few versions of my whitelabel app in the store, and unbelievable they're still suffering the issue where the screen is blank if opened on CarPlay first, despite it all working fine in development. |
We haven't released the new app version (with React Native 0.79) yet, but I just gave my production TestFlight a quick spin in the CarPlay Simulator and everything looks fine. |
Yes, it works perfectly fine on the CarPlay Simulator, and also when running from Xcode to my iPhone and using a CarPlay physical head unit I use for testing. It seems to be only when released through the App Store that it stops working again. |
|
That sounds seriously strange. There shouldn't be any difference between a production TestFlight and the released version. |
|
Has anyone had any more luck getting this to work in production? We're still stumped as to what's going on over here. Thanks :) |
|
@lovegaoshi I used your CarPlay related code (SceneDelegates and AppDelegate) in my Expo SDK 53 app (Expo dev client), but when starting the phone app, i get a blank (black) screen, the Expo Dev Launcher is not visible. When I inspect the layout in the simulator, it says that the view Did you experience the same? Any ideas how to fix? |
|
unfortunately neither i experience it nor i use expo's framework.
ur references are my app (https://github.com/lovegaoshi/azusa-player-mobile)
and jellify (https://github.com/Jellify-Music/App) where i stole this code
from.
…On Wed, Jul 2, 2025 at 7:19 AM janwiebe-jump ***@***.***> wrote:
*janwiebe-jump* left a comment (birkir/react-native-carplay#158)
<#158 (comment)>
@lovegaoshi <https://github.com/lovegaoshi> I used your CarPlay related
code <https://github.com/lovegaoshi/azusa-player-mobile/tree/master/ios>
(SceneDelegates and AppDelegate) in my Expo SDK 53 app (Expo dev client),
but when starting the phone app, i get a blank (black) screen, the Expo Dev
Launcher is not visible.
When I inspect the layout in the simulator, it says that the view
EXDevLauncherDeferredRCTRootView is shown.
Did you experience the same? Any ideas how to fix?
—
Reply to this email directly, view it on GitHub
<#158 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AZMOVVVYOXCB752M6GO5SUL3GPTAZAVCNFSM6AAAAAA7USZFISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTAMRYGA3DENRRHA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
|
We got to the bottom of our issues. It was because the New Architecture was being unknowingly re-enabled when building for the App Store via Fastlane. |
Great that you found the root of the problem. I still wonder why this hasn't surfaced earlier in TestFlight, though, since the build is the same that's getting released to production. |
I just upgraded to RN 0.81 and can report that the standalone-startup approach from RN 0.79 still seems to work with no further adjustments to the |
|
So as I understand it, the standalone-startup does not work if New Architecture is enabled? |
|
Thanks for sharing your example, it was really helpful for getting our setup working 🙌 We’re running into one strange issue that we haven’t been able to solve. Here’s what we observe: The CarPlay scene stays visible and interactive (UI responds to taps, animations continue). We confirmed it’s not network-related — even a basic setTimeout(() => console.log('done'), 2000) is delayed until the phone wakes. So it really looks like the React Native JS thread or timers get suspended when the device is locked, even though CarPlay remains in the foreground and active. Have you or anyone else noticed this behavior when running standalone CarPlay scenes? |
|
@anna-morawska Is it related to Android and/or iOS? |
|
@anna-morawska yes, I noticed the same thing, This whole CarPlay thing is a bit of a mystery and always involves a lot of trial & error. Not even the Apple devs themselves seem to master it completely: I found that Live Activities on CarPlay in iOS 26 (i.e. a sports match live activity from Apple's own sports app) also get suspended when the phone screen turns off - the current minute timer stops, the score is not getting updated in the UI... As soon as I pick up the phone and the screen lights up, the Live Activity is updated in CarPlay again. I was wondering if the same behavior can be observed for newer phones which have an always-on-display (since maybe it has to do with the iOS UI-rendering cycle), but I didn't get around to checking that yet. Anyways: Good luck on finding the right solutions for your use case, I'm sure you'll get there eventually :) |
|
@mefjuu It’s only an issue on iOS — we’re using this library only for CarPlay @DanielKuhn thanks a lot for the pointers, really appreciate it :) We also experimented with a few native-side tweaks (activating the audio session, enabling background modes, etc), but none of them seemed to prevent the suspension. |
|
not to bring any meaningful discussions, but - i'm not well versed in ios but am greatly interested in a new arch implementation and workarounds to get background networking calls working. |
|
@DanielKuhn - I ran a few more experiments and just wanted to double-check something with you: are you running the CarPlay scene in headless/standalone mode and with the phone screen turned off, are you able to trigger network fetches that return fresh (non-cached) data and have your business logic run normally? That’s exactly our use case — the app needs to load new data on demand, not just from cache. It works fine when the data is cached, but as soon as we hit a screen that requires a fresh fetch, everything pauses until the screen wakes. I’d just like to confirm that our use cases are similar. If your setup really works under those conditions, it gives me a bit of hope that there’s still something we’re missing on our side :) @lovegaoshi - yes, that’s exactly what I was wondering - what would be the iOS equivalent of that mechanism. |
|
@anna-morawska I just re-checked, I was wrong about using TanStack Query: When a tab is selected ( |
|
for those interested - my senses finally came back to me to put a sleep() before loading carplay to allow me to attach xcode debug into my app and catch the error message when launching via carplay. The problem/fix is described in https://community.intercom.com/mobile%2Dsdks%2D24/crash%2Don%2Dcarplay%2D2292?postid=19611#post19611 and now my app has a "functional" standalone scene setup with the new architecture (starting from carplay now properly loads the js runtime and everything inside index.js). Now i'm having the issue that even useState/useEffect do not trigger re-render. This is different than android that now I need to make more workarounds to set up specifically carplay, but it should be workable and i'm only concerned about setTimeout now. I'll try to find some resources in the RN community. quick edit - I tested a simple fetch inside index.js and can see the json results printed when launched solely via carplay. I'm likely to get a workable setup within reach. |
|
while my app still has many bugs regarding carplay (the now playing template doesnt seem to sync well; if launched via carplay, safeview magically doesnt work; my lottie animation acts weird), i think the fundamental problems are clear now (launch from carplay doesnt crash, network req works). Heres my setup with RN 0.81 + new arch. The initialization is inspired and stolen from this PR. The new arch scene setup is stolen from jellify. With this method all functions in your apps entry point (index.js) and the registered component ( the long delay from carplay launch is due to a sleep(10) I put in to give me time to attach debug process. Screen.Recording.2025-11-01.at.7.23.13.PM.mov |
|
hey @lovegaoshi! Thank you for sharing this! Your setup is a bit different from mine, but I’ll take a closer look. Regarding fetch — unfortunately, you won’t be able to reproduce the issue with suspended promises on the simulator. The simulator’s lock feature doesn’t behave the same way as on a physical device. From Apple’s documentation: “For example, you can’t use Simulator to test when iOS locks the iPhone.” |
|
unfortunately that's where my limit is - no ios device nor dev
account/carplay entitlement.
i still have haed time believing this is a hard ios limit as other apps
work. what if u directly call the native fetch as a native module?
…On Wed, Nov 5, 2025, 12:32 AM Anna ***@***.***> wrote:
*anna-morawska* left a comment (birkir/react-native-carplay#158)
<#158 (comment)>
hey @lovegaoshi <https://github.com/lovegaoshi>! Thank you for sharing
this! Your setup is a bit different from mine, but I’ll take a closer look.
Regarding fetch — unfortunately, you won’t be able to reproduce the issue
with suspended promises on the simulator. The simulator’s lock feature
doesn’t behave the same way as on a physical device.
From Apple’s documentation: “For example, you can’t use Simulator to test
when iOS locks the iPhone.”
Using the CarPlay Simulator
<https://developer.apple.com/documentation/carplay/using-the-carplay-simulator>
—
Reply to this email directly, view it on GitHub
<#158 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AZMOVVWJD5ZMYQIVEZIK26T33GYZHAVCNFSM6AAAAAA7USZFISVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTIOBZHEZDKNRXHA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
|
Funny coincidence you’re asking — I actually tried exactly that today, and it worked! 🎉 |

CarPlay and Android Auto apps are expected to be able to get launched without the user having to open the respective app on the phone first - or even worse: have the phone app running at all times in order to use the CarPlay-app properly.
The example iOS-app featured in apps/example does not support launching on the CarPlay-client directly and is heavily intertwined with the phone app by presenting each CarPlay-template via a corresponding screen in the phone app and navigating to each screen when pushing the template onto the CarPlay-stack.
Since a lot of people who are using this package are wondering how to start their CarPlay-scene without having the app running in the background, I think there should be an example which illustrates this workflow and documents what's happening behind the scenes (pun intended).
This PR is an approach to addressing this issue by adding a simple CarPlay-only example app which can either get launched with the phone app open or, more importantly, WITHOUT opening the app on phone first.