birkir / react-native-carplay

CarPlay with React Native
https://birkir.dev/react-native-carplay/
MIT License
625 stars 103 forks source link

CarPlay standalone mode won't show anything when react navigation screens are present #154

Open mursang opened 8 months ago

mursang commented 8 months ago

Describe the bug CarPlay works in standalone mode (without phone app opened), but it won't work because of something related to react native navigators

CarPlay (please complete the following information):

Additional context I made some changes on my Swift code, in order to CarPlay work in standalone mode by forcing bridge to be present without the need of the app as stated in this comment: https://github.com/birkir/react-native-carplay/issues/109#issuecomment-1344820783

Everything seems working fine with the app opened, but if I try to use CarPlay without app, it crashes without an error. Just noticed it is related to my React Navigation code, but can't find where and how to fix.

In my App.js (starting point of my app) I return this:

---- code to connect Carplay that is correctly working  --- 

return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <ApplicationNavigator />
      </PersistGate>
    </Provider>
  );

ApplicationNavigator:

const ApplicationNavigator = () => {
  const { Layout, darkMode, NavigationTheme } = useTheme()
  const { colors } = NavigationTheme

  return (
    <SafeAreaView style={[Layout.fill, { backgroundColor: colors.card }]}>
      <NavigationContainer theme={NavigationTheme} ref={navigationRef}>
        <StatusBar barStyle={darkMode ? 'light-content' : 'dark-content'} />
        <Stack.Navigator screenOptions={{ headerShown: false }}>
          <Stack.Screen name="Startup" component={IndexStartupContainer} />
          <Stack.Screen name="Login" component={LoginContainer} />
          <Stack.Screen
            name="Main"
            component={MainNavigator}
            options={{
              animationEnabled: false,
            }}
          />
        </Stack.Navigator>
      </NavigationContainer>
    </SafeAreaView>
  )
}

export default ApplicationNavigator

So, just noticed that if I comment all Stack.Screens in the AppNavigator, CarPlay will work without any kind of problem, without the need of the app to be opened. (Obviously I can't open the app with these lines commented, as I see a blank scene).

I also tried to comment Screen by Screen, but seems something more related to Screens itself than with a specific one (or something that every screen loads, such as libraries?).

Did anyone have this problem and solved it? Do you know how to debug this kind of crashes with CarPlay that don't drop any log?

Thank you very much!

mursang commented 8 months ago

Is there any way to detect in React Native that Carplay is working without opening the app? This way maybe I could make a workaround: App: Load views as usual (tested and works as usual, before installing carplay) Carplay: Don't load navigator (tested and works, but can't open App as it doesn't load any view) App + Carplay: load navigator (tested and works)

this way, all three cases would work I think.

DanielKuhn commented 7 months ago

After fiddling around with this topic for quite some time now, always in doubt of what's happening under the hood and seeing ever more questions around starting on CarPlay without having the app running on phone, I took the liberty to create (and document!) an example app which runs independently of the phone app and supports launching on CarPlay directly (without having the phone app running) in this PR: https://github.com/birkir/react-native-carplay/pull/158 Patches welcome, feel free to add comments and improvements.

mursang commented 7 months ago

After fiddling around with this topic for quite some time now, always in doubt of what's happening under the hood and seeing ever more questions around starting on CarPlay without having the app running on phone, I took the liberty to create (and document!) an example app which runs independently of the phone app and supports launching on CarPlay directly (without having the phone app running) in this PR: #158 Patches welcome, feel free to add comments and improvements.

Thank you for your efforts! Unfortunately, after changing my project files to match yours, it compiles and works good on phone, but when trying to open Carplay in standalone mode, it breaks without any error (as I was experiencing before your changes). However, opening Carplay with phone app works good too. I don't know why, but it seems something related to some library like react-navigation, react-redux or so.. Seems like if you are using it in the project, Carplay is not able to load that library in the background without the need of the phone app.

Do you know any way to debug errors on Carplay?

mursang commented 7 months ago

Well... after some testing I'm starting to suspect that is something related to api calls using axios. Will try to debug and to use another library (or maybe it's not possible to perform api calls when using carplay in standalone mode)

DanielKuhn commented 7 months ago

@mursang The only way of debugging the stand-alone CarPlay app that I found was to add native logging as described here to my code and then checking the logs in the console (/System/Applications/Utilities/Console.app) of the physical device by filtering by process to only my app while the CarPlay-app is running in stand-alone mode. I also had a black screen on CarPlay for a while - in my case the problem was the splash-screen call (RNSplashScreen.show()) which I still had in the AppDelegate's application:didFinishLaunchingWithOptions that CarPlay couldn't handle. After moving that to the PhoneDelegate everything worked.

mursang commented 7 months ago

@DanielKuhn thank you for pointing me in the right direction and for sharing your code. My code was crashing due to react-native-screens that is installed by default with react-navigation. I could disable (not uninstalling) the use or react-native-screens, and now it works perfectly.

import { enableScreens } from 'react-native-screens';

enableScreens(false);

You saved my life!!

DanielKuhn commented 7 months ago

@mursang great to hear that you got it fixed. Could you elaborate on the problem you had with react-native-screens, though? I'm also using react-navigation with enableScreens(true) and so far there doesn't seem to be a problem. What exactly went wrong in your case?

Which versions of react native, react-navigation and react-native-screens are you using? I'm on

"react-native": "0.71.14",
"@react-navigation/bottom-tabs": "6.5.11",
"@react-navigation/drawer": "6.6.6",
"@react-navigation/material-top-tabs": "6.6.5",
"@react-navigation/native": "6.1.9",
"@react-navigation/native-stack": "6.9.17",
"@react-navigation/stack": "6.3.20",
"react-native-screens": "3.27.0",
mursang commented 7 months ago

@DanielKuhn After some debugging I found an error in the logs file:

0   CoreFoundation                         0x1b4294870 __exceptionPreprocess + 164
1   libobjc.A.dylib                        0x1ac5afc00 objc_exception_throw + 59
2   CoreFoundation                         0x1b432519c -[NSObject(NSObject) doesNotRecognizeSelector:] + 343
3   UIKitCore                              0x1b71f8154 -[UIResponder doesNotRecognizeSelector:] + 259
4   CoreFoundation                         0x1b41d9ff8 ___forwarding___ + 1563
5   CoreFoundation                         0x1b431ab10 _CF_forwarding_prep_0 + 95
6   AppName                                0x1049069c8 __56+[RNSScreenWindowTraits enforceDesiredDeviceOrientation]_block_invoke + 580

So I searched for that error and found it was related to orientation calculation in react-native-screens. I don't know exactly what fails, but disabling screens worked for me.

"react-native": "0.71.13",
"@react-navigation/bottom-tabs": "6.5.8",
"@react-navigation/native": "6.1.7",
"@react-navigation/stack": "5.14.9",
"react-native-screens": "3.27.0",

Seems like I am using an old version of the stack package. Maybe the latest version fixes the problem.

uzegonemad commented 4 months ago

FYI I just opened https://github.com/software-mansion/react-native-screens/pull/2035 to address this issue.

I also created a patch in the meantime.

DanielKuhn commented 4 months ago

@uzegonemad Good to see you found the root cause and an actual fix for the problem.

My CarPlay-app does not render anything or navigate in the phone app, that's probably why this isn't a problem in my case. I did run into similar problems after switching to scenes as well, though. It seems to be a common misconception to always use the first connected scene, assuming it's the window scene.

My scene-finding code looks like this:

let activeWindowScene = UIApplication.shared.connectedScenes.filter { scene in
    return scene.activationState == .foregroundActive && scene is UIWindowScene
}.first

The latest bug I found when using scenes is that in iOS, when you connect an external display, the app crashes. I fixed this in my PhoneSceneDelegate and opened #168 to fix it in the example app.

tboba commented 2 months ago

Hi, everyone! React Native Screens maintainer here. I see that this issue is related to https://github.com/software-mansion/react-native-screens/issues/1857, which has been closed today. Do you know if this issue has been resolved on your side?