React-native-navigation: [V7] App is stuck on the Splashscreen when using RCTBridgeDelegate in Swift

Created on 10 Sep 2020  ยท  4Comments  ยท  Source: wix/react-native-navigation

Hello there! ๐Ÿ‘‹

First of all, congrats on the v7 release! ๐ŸŽ‰ ๐Ÿ‘

Issue Description

โš ๏ธ Related to Swift.

The upgrade from 6.12.0 to 7.0.0 isn't working well for us, the app is getting stuck on the Splashscreen.

It seems like the bridge isn't correctly initialized. I can see JavaScript console logs happening in Xcode and the packager, but I can't see those screens in the app.

I created a repro case in the Playground app for an easier debugging session: https://github.com/charpeni/react-native-navigation/tree/swift-v7.0.0.

Steps to Reproduce / Code Snippets / Screenshots

import UIKit

@UIApplicationMain
-class AppDelegate: UIResponder, UIApplicationDelegate {
+class AppDelegate: UIResponder, UIApplicationDelegate, RCTBridgeDelegate {
  var window: UIWindow?

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
-     ReactNativeNavigation.bootstrap(jsCodeLocation, launchOptions: launchOptions)
+     ReactNativeNavigation.bootstrap(with: self, launchOptions: launchOptions)

      return true
    }

+  func sourceURL(for bridge: RCTBridge?) -> URL? {
+    #if DEBUG
+    return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index", fallbackResource: nil)
+    #else
+    return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
+    #endif
+  }

+  private func extraModules(for bridge: RCTBridge?) -> [RCTBridgeModule?]? {
+    return ReactNativeNavigation.extraModules(for: bridge)
+  }
}

I went back to 6.12.0, and I tried with ReactNativeNavigation.bootstrap(jsCodeLocation!, launchOptions: nil, bridgeManagerDelegate: self) and it's working fine.

Not sure what's wrong with this actual setup? ๐Ÿค” It could be something stupid that I'm not aware of in Swift.

@yogevbd @danilobuerger Any thoughts?


Environment

  • React Native Navigation version: 7.0.0
  • React Native version: 0.63.2
  • Platform(s) (iOS, Android, or both?): iOS
  • Device info (Simulator/Device? OS version? Debug/Release?): iPhone 11 Pro, 13.7, Debug

Most helpful comment

The problem is that the bridge delegate isn't exposed to objective-c in this case. Try this:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        ReactNativeNavigation.bootstrap(with: RNModuleInitialiser.init(), launchOptions: launchOptions)

        return true
    }
}

@objc(RNModuleInitialiser)
final class RNModuleInitialiser: NSObject {}
extension RNModuleInitialiser: RCTBridgeDelegate {

    func sourceURL(for bridge: RCTBridge!) -> URL! {
        #if DEBUG
        return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index", fallbackResource: nil)
        #else
        return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
        #endif
    }

    func extraModules(for bridge: RCTBridge!) -> [RCTBridgeModule]! {
        return ReactNativeNavigation.extraModules(for: bridge);
    }

}

Also, you might need to add -D DEBUG flag to your Project Settings > Build Settings > Other Swift flags > Debug configuration

All 4 comments

Put a breakpoint inside extraModules. Is it getting called?

The problem is that the bridge delegate isn't exposed to objective-c in this case. Try this:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        ReactNativeNavigation.bootstrap(with: RNModuleInitialiser.init(), launchOptions: launchOptions)

        return true
    }
}

@objc(RNModuleInitialiser)
final class RNModuleInitialiser: NSObject {}
extension RNModuleInitialiser: RCTBridgeDelegate {

    func sourceURL(for bridge: RCTBridge!) -> URL! {
        #if DEBUG
        return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index", fallbackResource: nil)
        #else
        return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
        #endif
    }

    func extraModules(for bridge: RCTBridge!) -> [RCTBridgeModule]! {
        return ReactNativeNavigation.extraModules(for: bridge);
    }

}

Also, you might need to add -D DEBUG flag to your Project Settings > Build Settings > Other Swift flags > Debug configuration

Thanks for sending this @yogevbd, it worked as expected! ๐Ÿ™‡โ€โ™‚๏ธ

Do you mind explaining why the bridge delegate isn't exposed to Objective-C and how to know that?

Could we do something within RNN to expose it? Or is this a common Swift thing?

I tried to debug it and extraModules(for: bridge) and sourceURL(for: bridge) never got called.
Then I realised that it isn't exposed to Objective-C, so I created this new class RNModuleInitialiser which extends RCTBridgeDelegate protocol and the most important thing, I added @objc(RNModuleInitialiser) which instructs Swift to make those things available to Objective-C.
It's not related to RNN but to the build system.

I hope that helped and I'm glad it's working as expected ๐ŸŽ‰

Was this page helpful?
0 / 5 - 0 ratings

Related issues

edcs picture edcs  ยท  3Comments

tmaly1980 picture tmaly1980  ยท  3Comments

zhanguangao picture zhanguangao  ยท  3Comments

yayanartha picture yayanartha  ยท  3Comments

zagoa picture zagoa  ยท  3Comments