expo: Xcode build fails Property 'reactDelegate' not found on object of type 'AppDelegate *'
Summary
After adding Expo using npx install-expo-modules@latest to an existing project, Xcode then fails to build. Android works perfectly.
The 4 x Xcode errors i am getting are: 3 x Property ‘reactDelegate’ not found on object of type ‘AppDelegate *’ 1 x No visible @interface for ‘EXAppDelegateWrapper’ declares the selector ‘application:didFinishLaunchingWithOptions:’
I have created a new AwesomeProject and then added installed expo in the same way and this works as expected so i cannot reproduce this error.
After researching, it would suggest that i am using an expo SDK 43 or below, however SDK47 is installed.
I have copied the AppDelegate.h and AppDelegate.mm from the react-native repo to simulate before expo was installed and this boots. From this i have then run the above install command and still the same issue, i cant find anyone anywhere with a similar issue.
If anyone could shed any light on this that would be great! Thanks!
AppDelegate.h
#import <React/RCTBridgeDelegate.h>
#import <Expo/Expo.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : EXAppDelegateWrapper <UIApplicationDelegate, RCTBridgeDelegate>
@property (nonatomic, strong) UIWindow *window;
@end
AppDelegate.mm
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTAppSetupUtils.h>
#if RCT_NEW_ARCH_ENABLED
#import <React/CoreModulesPlugins.h>
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <ReactCommon/RCTTurboModuleManager.h>
#import <react/config/ReactNativeConfig.h>
static NSString *const kRNConcurrentRoot = @"concurrentRoot";
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
RCTTurboModuleManager *_turboModuleManager;
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
facebook::react::ContextContainer::Shared _contextContainer;
}
@end
#endif
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTAppSetupPrepareApp(application);
RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions];
#if RCT_NEW_ARCH_ENABLED
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
_bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
#endif
NSDictionary *initProps = [self prepareInitialProps];
UIView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"mobilityapp" initialProperties:initProps];
if (@available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor systemBackgroundColor];
} else {
rootView.backgroundColor = [UIColor whiteColor];
}
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [self.reactDelegate createRootViewController];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
[super application:application didFinishLaunchingWithOptions:launchOptions];
return YES;
}
/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off.
///
/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html
/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture).
/// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`.
- (BOOL)concurrentRootEnabled
{
// Switch this bool to turn on and off the concurrent root
return true;
}
- (NSDictionary *)prepareInitialProps
{
NSMutableDictionary *initProps = [NSMutableDictionary new];
#ifdef RCT_NEW_ARCH_ENABLED
initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]);
#endif
return initProps;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
#if RCT_NEW_ARCH_ENABLED
#pragma mark - RCTCxxBridgeDelegate
- (std::unique_ptr<facebook::react::JSExecutorFactory>)jsExecutorFactoryForBridge:(RCTBridge *)bridge
{
_turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge
delegate:self
jsInvoker:bridge.jsCallInvoker];
return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager);
}
#pragma mark RCTTurboModuleManagerDelegate
- (Class)getModuleClassFromName:(const char *)name
{
return RCTCoreModulesClassProvider(name);
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
return nullptr;
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
initParams:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return nullptr;
}
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
return RCTAppSetupDefaultModuleFromClass(moduleClass);
}
#endif
@end
Podfile
require File.join(File.dirname(`node --print "require.resolve('expo/package.json')"`), "scripts/autolinking")
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
platform :ios, '13.0'
install! 'cocoapods', :deterministic_uuids => false
$RNFirebaseAsStaticFramework = true
target 'mobilityapp' do
use_expo_modules!
post_integrate do |installer|
begin
expo_patch_react_imports!(installer)
rescue => e
Pod::UI.warn e
end
end
# React Native Maps dependencies
# rn_maps_path = '../node_modules/react-native-maps'
# pod 'react-native-google-maps', :path => rn_maps_path
# END React Native Maps dependencies
config = use_native_modules!
use_frameworks! :linkage => :static
# Flags change depending on the env values.
flags = get_default_flags()
use_react_native!(
:path => config[:reactNativePath],
# Hermes is now enabled by default. Disable by setting this flag to false.
# Upcoming versions of React Native may rely on get_default_flags(), but
# we make it explicit here to aid in the React Native upgrade process.
:hermes_enabled => true,
:fabric_enabled => flags[:fabric_enabled],
# Enables Flipper.
#
# Note that if you have use_frameworks! enabled, Flipper will not work and
# you should disable the next line.
#:flipper_configuration => FlipperConfiguration.enabled, //Due to conflict with RN Firebase
# An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
post_install do |installer|
react_native_post_install(
installer,
# Set `mac_catalyst_enabled` to `true` in order to apply patches
# necessary for Mac Catalyst builds
:mac_catalyst_enabled => false
)
# installer.pods_project.targets.each do |target|
# target.build_configurations.each do |config|
# # Using the un-qualified names means you can swap in different implementations, for example ccache
# config.build_settings["CC"] = "clang"
# config.build_settings["LD"] = "clang"
# config.build_settings["CXX"] = "clang++"
# config.build_settings["LDPLUSPLUS"] = "clang++"
# end
# end
__apply_Xcode_12_5_M1_post_install_workaround(installer)
end
end
What platform(s) does this occur on?
iOS
Environment
expo-env-info 1.0.5 environment info: System: OS: macOS 13.1 Shell: 5.8.1 - /bin/zsh Binaries: Node: 18.10.0 - /usr/local/bin/node Yarn: 1.22.19 - ~/.yarn/bin/yarn npm: 9.2.0 - /usr/local/bin/npm Watchman: 2021.11.15.00 - /usr/local/bin/watchman Managers: CocoaPods: 1.11.2 - /usr/local/bin/pod SDKs: iOS SDK: Platforms: DriverKit 22.2, iOS 16.2, macOS 13.1, tvOS 16.1, watchOS 9.1 IDEs: Android Studio: 2021.3 AI-213.7172.25.2113.9014738 Xcode: 14.2/14C18 - /usr/bin/xcodebuild npmPackages: babel-preset-expo: ~9.2.1 => 9.2.2 expo: ^47.0.0 => 47.0.13 react: 18.1.0 => 18.1.0 react-native: 0.70.5 => 0.70.5 npmGlobalPackages: eas-cli: 2.6.0 expo-cli: 6.1.0 Expo Workflow: bare
Minimal reproducible example
none
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 2
- Comments: 27 (3 by maintainers)
I don’t know why it’s working but it works. Changing
sourcecode.c.objcintosourcecode.cpp.objcppfix the problem.For people who perfer to use the Xcode GUI, you can also change this by having the
AppDelegate.mmfile open and changing the “Type” option in the right menu’s document tab to “Objective-C++ Source”Note that this is slightly different in the Xcode project file as you are explisitly setting the type, whereas the default is “last known type”, but the effect will be the same in that the
#if __cpluspluscase will betrueand the correct code block will be used.that’s interesting to me where
sourcecode.c.objcforAppDelegate.mmwork until now you awesome folks find the issue. if anyone still havesourcecode.c.objcforAppDelegate.mm. please update it rather than removing the#if __cpluspluschange. usesourcecode.cpp.objcppshould be correct solution. thanks @nesbite @TomCorvus @TheWirv for the great findings 👏@guillaume-g
I searched within
ios/Puma.xcodeproj/project.pbxprojfor the stringsourcecode.c.objcand updated the one that referred to theAppDelegate.mmfile. To update it, you literally just swap the stringsourcecode.c.objcwithsourcecode.cpp.objcppI’ve also been having the same issue and can confirm that the following patch gets the build working again for me (Thanks @TheWirv). Let me know if you would like any more info to help identify the root cause @Kudo
(I’m using RN 0.70.6)
expo-modules-core+1.1.1.patchTks i
Tks it has worked for me ❤️
Just ran into this problem and this fixed it! Thank you so much 🙏
@TheWirv I edited my comment to avoid error, but yes I changed
sourcecode.c.objcintosourcecode.cpp.objcpp. I just copied/pasted @nesbite answer because I’m a little lazy when I haven’t had my coffee. Thanks @nesbite btwI mean, it does make sense either way, both @robwalkerco’s and my patch solution as well as changing the
lastKnownFileType. Changing the declaration of the file type makes the compiler run in Objective C++ mode which in turn makes it go the#if __cplusplusroute which executes the code path that has already been there before.Since it is mentioned in the upgrade helper, the “change
lastKnownFileTypetosourcecode.cpp.objcpp” solution is the official one though, in my opinion.@TomCorvus here, man ☕️ have a good one
@robwalkerco
Thanks, I was afraid to change it directly there, I though it was an option in Xcode!
I was wondering why fresh project works fine with latest expo-modules-core, but my old one doesn’t and dragging
AppDelegate.mmto another group and back made it work. It turned outAppDelegate.mmhadlastKnownFileType = sourcecode.c.objcin my old project instead ofsourcecode.c.objcpp. Check if it solves your problems too.