-
Notifications
You must be signed in to change notification settings - Fork 109
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
Scenes on React Native 0.71 #132
Comments
I am updating our scene example to RN 71, so stay tuned! |
Thanks, I'll give this a try. |
I have got this working on iPhone, not yet tested CarPlay. Do you know anything about launchOptions versus connectionOptions? launchOptions is used to pass information about how the app was launched, for example the payload from a push notification, or info about a Siri Shortcut. With Scenes, "launchOptions" in the AppDelegate is always empty, and instead similar data is provided to the scene delegate as "connectionOptions". But the RN Bridge expects launchOptions to be passed when it's initialised, and that happens in AppDelegate. So you can see how this is an issue. To get around it, pre RN 0.71, I had to intercept connectionOptions in the Scene delegate's willConnectTo method, parse and rebuild it in the "launchOptions" format, and then initialise the Bridge there instead of AppDelegate. I did this by checking if "appDelegate.bridge == nil", as it could've already been initialised by the other scene delegate. But with RN 0.71, initialisation of the bridge is abstracted, so there's seemingly no way to still do this. Any help would be hugely appreciated. As things stand, RN CarPlay using Scenes, along with RN 0.71, can't really be used in an app that also uses push notifications or Siri Shortcuts. |
This is all the "abstraction", that was previously in RN70 and older inside AppDelegate.m, as you can see its rather easy to copy this into your own swift code. For example in the PhoneScene you could initialize the bridge like this. guard let appDelegate = (UIApplication.shared.delegate as? AppDelegate) else { return }
if appDelegate.bridge == nil {
appDelegate.bridge = appDelegate.createBridge(delegate: appDelegate, launchOptions: launchOptions)
} Or create a wrapper function in your AppDelegate.swift and call it from a scene delegate. func application() {
return true;
}
func initStuff() {
let application = UIApplication.shared;
let launchOptions = /* your previously mapped options */
let app = super.application(application, didFinishLaunchingWithOptions: launchOptions);
// rest of code
} |
Thanks @birkir. I would be inclined to go with the latter approach, but I think it suffers two issues:
|
Hi @gavrichards - while adding CarPlay-support to my react native app (with push notifications support) I am now stuck at exactly this point. Did you manage to find a solution yet? I'm using |
@DanielKuhn If it helps, my PhoneScene.swift now looks like this:
and then in my AppDelegate I have:
|
@gavrichards Thanks a ton! Thanks to @birkir for the awesome work on this package by the way! |
Can you tell me if it's possible to do it without transforming the project into Swift? |
@eduardooris : I found that the Podverse sources contain a "regular" ObjC implementation using scenes: https://github.com/podverse/podverse-rn |
@DanielKuhn I'm building a screen for CarPlay in a Swift class. But my application is in React Native with Objective-c. As I'm using the carplay-driving-task right, if I don't declare the scenes in the .plist, xcode gives me the error: application does not implement carplay template application lifecycle methods in its scenedelegate. I already configured the entire .plist. But, my iPhone app is completely dark. I realized it was because I hadn't declared the scenes in Delegate. |
@eduardooris as commented above: Check the |
@DanielKuhn I gave it a read. But, I saw that there is no AppDelegate |
@eduardooris I don't understand. The link points specifically to the AppDelegate |
Hi @DanielKuhn . I ended up using AppDelegate for Swift to be able to handle the scenes. But, I ended up having a problem with SplashScreen. Could you tell me how you resolved it? |
@eduardooris : If you're using
|
@DanielKuhn I tried same scene files from podverse project but I am still getting the blank screen. I get this message in bundler Running "App" with {"rootTag":1,"initialProps":{}} in terminal but still it shows blank screen on CarPlay |
Hey @gavrichards I'm finally debugging startup on CarPlay without the app running on phone. I have two separate approaches, both of which are not working properly. The one I posted above seems to render the app twice(?) when starting on phone. But it does launch the carplay app without the app running on phone - even though all my hooks get fired twice and the CarPlay app isn't working properly when the phone app isn't running. Once I start the app on phone alongside with CarPlay it works perfectly. The other approach is your setup from above (with So I think I'm missing some initialization code in my Thanks! |
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 |
@DanielKuhn hi, are you in a discord group? if so, what is your nickname? i have something to tell you |
Now I am, nick is DanielKuhn |
This is my solution. I had to refactor the app initialization logic to be UI-independent. I think this approach is pretty efficient as it doesn't create a RootView if the app is only opened on CarPlay.
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
// We are not calling the super method as RCTAppDelegate does not support
// SceneDelegate at the moment
RCTAppSetupPrepareApp(application, false)
// This must be called before setting ReactRootView
bridge = RCTBridge(
delegate: self,
launchOptions: launchOptions
)
return true
}
class SceneDelegate: UIResponder, UIWindowSceneDelegate,
CPTemplateApplicationSceneDelegate
{
var window: UIWindow?
func scene(
_ scene: UIScene,
willConnectTo _: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
let rootViewController = UIViewController()
let rootView = RCTRootView(
bridge: (UIApplication.shared.delegate as! AppDelegate).bridge,
moduleName: "main",
initialProperties: nil
)
rootViewController.view = rootView
window!.rootViewController = rootViewController
window!.tintColor = UIColor(
red: 0.0,
green: 0.0,
blue: 0.0,
alpha: 1.0
)
window!.makeKeyAndVisible()
}
// MARK: - CPTemplateApplicationSceneDelegate
func templateApplicationScene(
_: CPTemplateApplicationScene,
didConnect interfaceController: CPInterfaceController,
to window: CPWindow
) {
RNCarPlay.connect(with: interfaceController, window: window)
}
func templateApplicationScene(
_: CPTemplateApplicationScene,
didDisconnect _: CPInterfaceController,
from _: CPWindow
) {
RNCarPlay.disconnect()
}
} |
Anyone here had any luck with upgrading to React Native 0.74 while using Scenes, and also needing to convert I attempted it today, but the changes that have been made by React Native to Any pointers appreciated! |
@gavrichards +1 |
@DanielKuhn : I'm not sure how you got the standalone app to work, given that Based on the discussion in that thread, which led me here, I've created a Swift version of the approach and have gotten it working. I think the sample app can also be updated to use this approach if you'd like. @gavrichards : here's what I did. In AppDelegate: var rootViewFactoryConfig: RCTRootViewFactoryConfiguration?
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
// Taken from https://github.com/facebook/react-native/issues/46184#issuecomment-2311992358
// to get CarPlay working on RN 0.75.2. You should use bundleURL() or whatever function you use
// to get the bundle URL; mine was called sourceURL().
rootViewFactoryConfig = RCTRootViewFactoryConfiguration(bundleURL: self.sourceURL(for: nil),
newArchEnabled: self.fabricEnabled(),
turboModuleEnabled: self.turboModuleEnabled(),
bridgelessEnabled: self.bridgelessEnabled())
...
}
...
// This function follows the convention set up by @DanielKuhn in the samples
func initAppFromScene(connectionOptions: UIScene.ConnectionOptions?) {
if (self.bridge != nil || self.rootViewFactoryConfig == nil) {
print("Totally unexpected initappFromScene business")
return;
}
/**
ReactNativeCarPlay requires a bridge and is not compatible with the bridgeless new architecture introduced in React Native 0.74.
Therefore we need to eject when the new architecture is enabled
*/
if (self.newArchEnabled) {
print("ReactNativeCarPlay can't stand RCT_NEW_ARCH_ENABLED")
return
}
// These two lines come from this project's samples. I honestly haven't researched what they do
// or whether they can be removed.
RCTSetNewArchEnabled(self.newArchEnabled)
RCTColorSpaceUtils.applyDefaultColorSpace(self.defaultColorSpace)
let launchOptions = self.connectionOptionsToLaunchOptions(connectionOptions: connectionOptions);
self.rootViewFactoryConfig!.sourceURLForBridge = { (bridge: RCTBridge) -> URL? in
return self.sourceURL(for: bridge)
}
// Note that the following two lines only work if you adopt the rest of the sample in this project (i.e.
// the bit about PhoneScene and CarScene).
let rootViewFactory = RCTRootViewFactory(configuration: rootViewFactoryConfig!)
self.rootView = rootViewFactory.view(withModuleName: self.moduleName!, initialProperties: self.prepareInitialProps(), launchOptions: launchOptions)
}
// Also not sure whether this is needed vs [:]. Taken from elsewhere in this project.
func prepareInitialProps() -> [String: Any] {
return self.initialProps as? [String: Any] ?? [String: Any]()
} |
@fivecar Thanks for your input, I'll test your approach when I find the time. |
I saw this today and wondered if this could help us in future: facebook/react-native@391680f |
I posted this issue on the React Native Github but haven't had a response, maybe it's a bit too niche as most RN devs probably aren't using scenes.
facebook/react-native#37278
I wondered if anyone here might have any thoughts, particularly as this repository now relies on Scenes for newer functionality, or the Now Playing template.
The text was updated successfully, but these errors were encountered: