react-native: Unable to use other configurations than Debug and Release on 0.40

Description

in XCode we can duplicate the default build Configurations by navigating to our Project -> info tab -> click on the plus symbol and duplicate any of the existing configs (debug, Release). Set a new name. Now when edit our scheme and tell XCode to use our new config the build process won’t finish. Most probably you’ll end up with this error:

fatal error: 'React/RCTBundleURLProvider.h' file not found

After staring at the screen for a day I think that the issue is that the build script is copying the React files to either debug-iphoneos or release-iphoneos instead of using the “newconfig”-iphoneos directory.

REPROPDUCTION

Steps to reproduce:

  1. create a new RN project:
react-native init test
  1. Now open the project in XCode, click on your project in the folder tree. Then select the project -> your project and navigate to the Info tab. Duplicate one of the configurations and give it whatever name you like.

  2. Edit your current scheme and select the new configuration in the “build configuration” option. Now run the project. It should fail.

  3. You can repeat the same steps on RN 0.39 and it works…

Here a few screenshots of the proper screens in XCode:

image

image

And on this screen you can see that RTCBundleURLProvider.h is being copied, but to the wrong path image

Solution

Don’t have one yet, most probably the issue happens somewhere in runIOS.js

Additional Information

  • React Native version: 0.40
  • Platform: iOS
  • Operating System: MacOS

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 54
  • Comments: 55 (10 by maintainers)

Commits related to this issue

Most upvoted comments

While adding a configuration with the same name works, it’s not the most CI-friendly or future-proof solution. This is what I did, instead:

  1. Added the React build target under the current scheme for my project. (Sidenote: if you’re using fastlane to deploy, keep your project’s build target in first place, otherwise fastlane gets confused and thinks you’re building a library, so it never builds an ipa).

  2. Added React under [Target] > Build Phases > Target Dependencies, which made Xcode build React before building the rest of the project.

  3. Under [Target] > Build Settings, added a new User-Defined setting, called REACT_HEADERS_PATH. For all configurations not named Debug or Release, I set that to $(BUILD_DIR)/Release-$(PLATFORM_NAME)/include.

  4. Under [Target] > Build Settings > Header Search Paths I added $(REACT_HEADERS_PATH) as an entry.

  5. Repeat for all targets in your project.

When my project builds, React builds first, and since it doesn’t know about configurations other than Release and Debug, it builds with the Release configuration. This places its headers under [build dir]/Products/Release-iphoneos/include. Since this path is now in the Header Search Paths of the main project, it gets picked up and everything else builds fine.

Hope this helps.

Updated 4/13 to mention repeating these steps for all targets (thanks @Twinski) and to change to the much shorter and more reliable $(BUILD_DIR) (thanks @hoolymama).

I think what you are looking for is something like:

productFlavors {
        development {
            applicationId "io.app"
            versionName "${appVersionName}-development"
        }
        staging {
            applicationId "io.app"
            versionName "${appVersionName}-staging"
        }
        production {
            applicationId "io.app"
            versionName "${appVersionName}"
        }
    }

check this out: https://github.com/facebook/react-native/commit/46422ddd99a798d1af9ea337629f2de5334d72fa

Guys, the easiest fix that I found - is to set “CONFIGURATION_BUILD_DIR” in buildSettings of your configuration like: CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)";

Or if you want to set in XCode: Your Project -> Build Settings -> Build Locations -> Per-configuration Build Products Path for your new configuration: $(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)

For anyone coming here, React-Native has inherent problems with adding build configurations because of the way the packenger references the react-native xcode project libraries from the node_modules folder. In hopes this will be solved natively, the best approach for now (React Native Version 0.45.1 and belowish) is this:

(just jottet down for dummies and colleagues who are not that familia with the magic world of xcode)

Use Schemes Manager by @blargity

  • Roll back any changes you did to the xcode project-workspace regarding build configurations. All the header/library search path hacks, manual library inclusion etc. The safest bet is to run a test init project and try to get it working there. Make sure to add cocoa pods first so you are working with the *.xcworkspace and not the *.xcodeproj of your ios/ folder. Than transfer the learnings to your real project.
  • Install Schema Manager from npm as dev dependency (https://www.npmjs.com/package/react-native-schemes-manager)
  • Add build configurations by copying the original release or debug variant respectively. dublicate build config
  • Rename those build configurations to your desired name. I.e. We have two additional Release variants called “angel” and “tester” that carry each a different bundle id, use different logos and connect to different backends. Just some guidance how this looks like (different bundle ids & app icons — under target): image image
  • Add the new config to the package.json as an instruction for Schemes Manager to add those build configs to all the react-native xcode projects in the node modules folder. add schemes
  • Add schemes manager to your post install scripts (as described in the documents). We did it like so: image
  • When you run npm run fix-xcode (with that example), you’ll see the following. This should be done anytime after you run npm install, hence, the postinstall reference: run schemes manager
  • Now add a scheme to xcode that references your new build configuration. In xcode world, it’s like a short cut pre-set of configurations. Those can be shared (are committed to the repository) or personal. If you want CI Systems such as BuddyBuild to pick up those schemes, make sure you tick the “shared” checkbox.
  • Also make sure, that the new schema references the right build configuration in run and archive. To do so <kbd>alt</kbd> + click on the play symbol, duplicate the original scheme and do the following. add scheme
  • You should now be set to build those variants.

Tips & Bottle Necks

  • We were not able to build an archive from a different build config. Run is no problem. Since we use BuddyBuild and only require our release version to be build for archive (to be able to upload to itunes), this did not bother us. However, this means we have two branches. A staging branch for ad’hock distribution and a master branch from where our release is build for archive. image
  • The reason for that are probably build references paths that are auto generated from the new build naming and do not correspond to the hard coded packager references. Such as image
  • If you encounter linking errors, it’s worth to take a look at the header & library search paths and check how they might differ to the original release paths.
  • Since we can not use multiple targets, all files are linked to the same xcode target. That can cause issues when including files that should (for simplicity) be of the same reference but vary between builds. Such an example is the GoogleService-Info.plist for google login (you could reference them in your AppDelegate file). However, we try to touch as little of the native code as possible to have little hassle in upgrading further rn-versions. The best way to solve such situations is to have an extra folder in your ios/ folder, which is not added to the xcode project. And have files, depending on their build config suffix be copied to the app at build time. I.e. we manage our firebase files like so: manage files Here our script (simple shell command):
cp ${SRCROOT}/firebase/GoogleService-Info-${CONFIGURATION}.plist ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleService-Info.plist

Note: I jotted this down because it was quite a hassle to get react-native into a common xcode workflow. So this is also for my colleagues and my memory. I plan for a while to turn this into a proper blog post. But until than, this here is my scratch pad to signal what mess is behind this issue . 😇

I built a package that should help with automatically setting all of the build configurations up in your libraries on each subsequent install:

https://www.npmjs.com/package/react-native-schemes-manager

Please give it a try and let me know how it works for you. We’ve got ~20 native libs now in most of our RN projects, so manually managing this would have been a nightmare.

I would like to second that this is a major headache. Even if I patch it to find React, it can’t find any other native dependencies. Do I have to patch the header search paths for every single dependency I add to the project?

Note, that if you’re using Cocoapods, you may have to change another configuration variable to point to Release, or it won’t be able to find linked Pods:

screen shot 2017-03-08 at 5 52 24 pm

@K-Leon We have had the same issue with our Staging build configuration. Adding Staging as a configuration to the React.xcodeproj sorted our 0.40.0 build issues. Release and Debug worked out of the box. react-staging

When I jotted that down, I hoped a blog article would be obsolete by the time it goes online. Aka improvements of the metro bundler. Oh well - for better SEO I’ll add it to my todo list. Hopefully saving some devs the long path of desperate hacks until they find that comment. 🙃

I can’t quite make it work with $(BUILT_PRODUCTS_DIR)/Release-$(PLATFORM_NAME)/include For me it resolves to build/Staging-iphoneos/Release-iphoneos/include Its probably something with my configuration - I’ll experiment a bit later, but for now BUILD_DIR is working okay. Cheers!

Just figured it out: You need to copy the Release Target in ‘React’ Project too with the same Name as the parent Target has. Now we need an idea how to make it less troublesome ( without touching React) or we just document it somewhere?

I just download CORS extension for chrome and it works for me

https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi/related

@tisho Thx! Did the trick for me. Extra thing that was needed in my case due to link errors: add “$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)” to Library Search Paths (only for the custom configuration)

Just want to add, because I spend all night implementing the iOS build configuration set up for BuddyBuild that it is important to set the library search path recursive. image

@jamesone @blargity’s I’m using react-native-scheme-manager (thanks @blargity!) and works great locally. Buddy Build is still failing though 😦 image

For anyone who comes across this, I managed to piece together a working XCode setup to get:

  • custom build configs working for Build and Archive in my react-native init apps (using Cocoapods); if you’re using fastlane, this supports its deployment, as well
  • Microsoft’s AppCenter and CodePush iOS SDKs working with said custom build configs (Staging, Angel, etc.)

Made a post on an issue in Microsoft’s code-push repo detailing my setup.

I am getting this error on Buddybuild - I’m unsure how it can be fixed! I tried using @philipshurpik solution but got the same errors on buddybuild, but when I ran the same xcode build command that buddybuild uses locally, it fixed it 🤔

After @j2kun 's step, I had to add "$PODS_CONFIGURATION_BUILD_DIR" as recursive to Framework Search path to pass the build with cocoapods.

image

How do I Added the React build target under the current scheme for my project ? It’s not working for me so far. Seems like that’s the only step I’m missing. Still getting this error:


ld: warning: directory not found for option '-L/Users/nathanhyland/Library/Developer/Xcode/DerivedData/bideasy_rn-ddevhacvgkjqoigndhxjmlrtyyog/Build/Products/Staging'
ld: warning: directory not found for option '-L/Users/nathanhyland/Library/Developer/Xcode/DerivedData/bideasy_rn-ddevhacvgkjqoigndhxjmlrtyyog/Build/Products/Staging-iphoneos/AFNetworking'
ld: warning: directory not found for option '-L/Users/nathanhyland/Library/Developer/Xcode/DerivedData/bideasy_rn-ddevhacvgkjqoigndhxjmlrtyyog/Build/Products/Staging-iphoneos/Lock'
ld: warning: directory not found for option '-L/Users/nathanhyland/Library/Developer/Xcode/DerivedData/bideasy_rn-ddevhacvgkjqoigndhxjmlrtyyog/Build/Products/Staging-iphoneos/Masonry'
ld: warning: directory not found for option '-L/Users/nathanhyland/Library/Developer/Xcode/DerivedData/bideasy_rn-ddevhacvgkjqoigndhxjmlrtyyog/Build/Products/Staging-iphoneos/SimpleKeychain'
ld: warning: directory not found for option '-L/Users/nathanhyland/Library/Developer/Xcode/DerivedData/bideasy_rn-ddevhacvgkjqoigndhxjmlrtyyog/Build/Products/Staging-iphoneos/TouchIDAuth'
ld: warning: directory not found for option '-F/Users/nathanhyland/Library/Developer/Xcode/DerivedData/bideasy_rn-ddevhacvgkjqoigndhxjmlrtyyog/Build/Products/Staging'
ld: library not found for -lAFNetworking
clang: error: linker command failed with exit code 1 (use -v to see invocation)

This is a bug/feature of Xcode. It attempts to build sub-projects using the same configuration as the main project. If that configuration does not exist, Xcode uses the Release configuration. With the latest changes to public headers exposed by React.xcodeproj, these headers now go to the build path of the sub-project, which is configuration-dependent.

Shout out to @D1no! your solution worked for me! Been banging my head against the wall for the past few days. The solution worked for my CI system as well (buddybuild).

@tisho Your answer is very exciting, according to your guidance, I built a number of new target, and can build success. But the new target fails in archive: image

Just want to add that this error occurs with a clean project boilerplate based on react-native init. The error mentioned and error icon are there from the start. However the error mentioned didn’t cause the build to fail, the simulator was still able to load up.

Steps to reproduce:

  1. In Terminal, create the project: react-native init <project-name>
  2. Open the project in Xcode and open “AppDelegate.m” file, you should see the red error icon next to the code: #import <React/RCTBundleURLProvider.h>

Package/Software Versions installed as follows:

  • “react”: “16.0.0-alpha.12”,
  • “react-native”: “0.46.4”
  • NPM: 3.10.10
  • XCode: 8.2.1

What a mess!!! I just spent several days trying to figure out what is going on with my XCode project. We rely on custom configs heavily - this completely broke our project. When is this going to be fixed proper???

In case anyone else runs into this issue and wants to test out the schemes-manager solution, I created an example project that incorporates @D1no 's guide as a github project you can pull and play around with. I spent some time hard-coding paths to header files and realized that this would not scale well once more developers ended up working on our projects, so decided to go the schemes-manager route, and everything works great so far.

@D1no @jamesone yes finally! all I ended up having to do was set our Build Configuration to Staging for Archive as jamesone suggested. D’oh! Was setting it for Run, just not for Archive. Thanks!

If anyone is running into this issue when using xcode’s workspaces, just make sure to check the settings of all your projects within the workspace.

@tisho Fix seems to be working! Maybe it’s also useful to say that you also should repeat the $(REACT_HEADERS_PATH) for the VigiTest Target!

@tisho you deserve a medal for this!