How to support multiple RCTRootViews on iOS after ejecting?

We ejected in order to use the native module react-native-carplay for iOS. This module registers an additional component with AppRegistry.registerComponent, and then instantiates another RCTRootView to display on an external Apple CarPlay display.

The challenge we ran into: in Expo-ejected apps, the additional RCTRootView doesn’t show anything on the screen. In non-Expo apps, RCTRootView.m immediately calls bundleFinishedLoading during initialization to kick off the JS code via AppRegistry.runApplication. In Expo apps, on the other hand, the RCTRootView never calls bundleFinishedLoading so the JS code for additional root components never runs.

We came up with a workaround: detecting whether we’re in an Expo-ejected app or not, and then manually triggering bundleFinishedLoading to start the JS: react-native-carplay/RNCarPlay.m at 680005c95016db0a49f42eccf6a98c3a592d3daf · dart-technologies/react-native-carplay · GitHub. However, it seems like this might be brittle, so we want to know if there’s a better approach before submitting a fix to react-native-carplay.

  1. Is there a good way to detect from Obj-C if we’re in an Expo-ejected app or not? We’re currently checking whether a subview of RCTRootView exists, which seems to work for additional RCTRootViews.

  2. Once we detect we’re in Expo, what’s the best way to call AppRegistry.runApplication? Since bundleFinishedLoading is private, we instead send the notification RCTJavaScriptDidLoadNotification to the RCTRootView… is that the best thing to do?

Or is there another approach entirely that would be better?