software-mansion / react-native-screens

Native navigation primitives for your React Native app.
MIT License
3.01k stars 510 forks source link

App Crashes with message "-[RCTView setSheetLargestUndimmedDetent:]: unrecognized selector sent to instance" #2166

Open hoonjoo-park opened 3 months ago

hoonjoo-park commented 3 months ago

Description

Problem

First of all, I've integrated ReactNative with my iOS native App. There is no problem with using the basic components of ReactNative. However, when I register RootStackNavigator as an entryPoint, the app crashes with the following error:

-[RCTView setSheetLargestUndimmedDetent:]: unrecognized selector sent to instance

As I said above, my app is based on iOS, and only a few screens are implemented with ReactNative. so I had to implement my custom BridgeManager which returns rootViewFactory to render ReactNative View.


React Native Code Example:

index.js

const { AppRegistry } = require('react-native')
import 'react-native-gesture-handler'
import 'react-native-reanimated'
import NoticeRootStackNavigator from './src/navigation/notice/NoticeRootStackNavigator'

AppRegistry.registerComponent('NoticeList', () => NoticeRootStackNavigator)

NoticeRootStackNavigator

export type NoticeStackParamList = {
  NoticeList: undefined;
  NoticeDetail: undefined;
}

export type NoticeNavigationProp = StackNavigationProp<NoticeStackParamList>;

const NoticeStack = createStackNavigator<NoticeStackParamList>();

const NoticeRootStackNavigator = () => {
  const screenOptions = useNavigatorScreenOptions();

  return (
    <NavigationContainer>
      <NoticeStack.Navigator screenOptions={screenOptions} initialRouteName="NoticeList">
        <NoticeStack.Screen name="NoticeList" component={NoticeList} />
        <NoticeStack.Screen name="NoticeDetail" component={NoticeDetail} />
      </NoticeStack.Navigator>
    </NavigationContainer>
  );
}

export default memo(NoticeRootStackNavigator);

iOS Code Example

CustomRCTBridgeManager.mm

#import "CustomRCTBridgeManager.h"
#import "RCTAppSetupUtils.h"
#import <React/RCTComponentViewFactory.h>
#import <React/CoreModulesPlugins.h>

@interface CustomRCTBridgeManager () <RCTTurboModuleManagerDelegate>
@end

@implementation CustomRCTBridgeManager

+ (instancetype)shared {
    static CustomRCTBridgeManager *shared = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        shared = [[self alloc] init];
    });
    return shared;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        [self configureBridge];
    }
    return self;
}

- (void)configureBridge {
    _rootViewFactory = [self createRCTRootViewFactory];
    _bridge = _rootViewFactory.bridge;
}

- (UIView *)createRootView: (NSString *)moduleName andInitialProperties:(NSDictionary * _Nullable)initialProperties {
    if (initialProperties == nil) {
        initialProperties = self.initialProps;
    }

    return [self.rootViewFactory viewWithModuleName:moduleName
                                  initialProperties:initialProperties
                                      launchOptions:nil];
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
#if DEBUG
    return [NSURL URLWithString:@"http://localhost:8081/index.bundle?platform=ios"];
#else
    return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

#endif
}

#pragma mark - New Arch Enabled settings

- (BOOL)newArchEnabled
{
#if RCT_NEW_ARCH_ENABLED
    return YES;
#else
    return NO;
#endif
}

- (BOOL)turboModuleEnabled
{
    return [self newArchEnabled];
}

- (BOOL)fabricEnabled
{
    return [self newArchEnabled];
}

- (BOOL)bridgelessEnabled
{
    return [self newArchEnabled];
}

#pragma mark - RCTTurboModuleManagerDelegate

- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
    return RCTAppSetupDefaultModuleFromClass(moduleClass);
}

- (Class)getModuleClassFromName:(const char *)name {
#if RN_DISABLE_OSS_PLUGIN_HEADER
    return RCTTurboModulePluginClassProvider(name);
#else
    return RCTCoreModulesClassProvider(name);
#endif
}

- (RCTRootViewFactory *)createRCTRootViewFactory
{
    __weak __typeof(self) weakSelf = self;
    RCTBundleURLBlock bundleUrlBlock = ^{
        return [weakSelf sourceURLForBridge:weakSelf.bridge];
    };

    RCTRootViewFactoryConfiguration *configuration =
    [[RCTRootViewFactoryConfiguration alloc] initWithBundleURLBlock:bundleUrlBlock
                                                     newArchEnabled:self.fabricEnabled
                                                 turboModuleEnabled:self.turboModuleEnabled
                                                  bridgelessEnabled:self.bridgelessEnabled];

    return [[RCTRootViewFactory alloc] initWithConfiguration:configuration andTurboModuleManagerDelegate:self];
}

@end

NoticeViewController

final class NoticeListViewController: ReactNativeViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        self.navigationItem.title = "NoticeList"

        configureRCTView()
    }

    private func configureRCTView() {
        guard let bridgeManager = QandaRCTBridgeManager.shared() else { return }

        let reactView = bridgeManager.createRootView(ReactNativeScreen.notice, andInitialProperties: nil)

        self.view = reactView
    }
}

Steps to reproduce

  1. enable new architecture by running RCT_NEW_ARCH_ENABLED=1 bundle exec pod install
  2. navigate to ViewController which it's view is RNScreen
  3. it successfully loads bundle from metro server
  4. after loading finished, app crashes.

Snack or a link to a repository

sorry it's my company's private repo

Screens version

3.31.1

React Native version

0.74.2

Platforms

iOS

JavaScript runtime

Hermes

Workflow

React Native (without Expo)

Architecture

Fabric (New Architecture)

Build type

Debug mode

Device

iOS simulator

Device model

iPhone 15 Pro

Acknowledgements

Yes

github-actions[bot] commented 3 months ago

Hey! 👋

The issue doesn't seem to contain a minimal reproduction.

Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?

github-actions[bot] commented 3 months ago

Hey! 👋

It looks like you've omitted a few important sections from the issue template.

Please complete Description section.

hoonjoo-park commented 1 month ago

Setting detachInactiveScreens to false resolved the issue, However, this seems to be a workaround rather than addressing the root cause.