-
Notifications
You must be signed in to change notification settings - Fork 99
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
Draft: Add example and documentation for stand-alone apps with support for launching on vehicle client #158
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? |
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.