facebook/react-native

Unable to use other configurations than Debug and Release on 0.40

compojoom opened this issue Β· 55 comments

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

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: 46422dd

Same Issue for me - could you find a solution @compojoom ?

@javache I think you worked on the compilation stuff. Is there an easy way to get a Staging Target up?

Thank you very much!

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?

@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

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.

tisho commented

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).

@tisho your solution worked for me. Cheers!
I had to use
$(BUILD_DIR)/Release-$(PLATFORM_NAME)/include
not
BUILD_PRODUCTS_DIR

tisho commented

Good catch. It was actually supposed to say BUILT_PRODUCTS_DIR, not BUILD_PRODUCTS_DIR. I edited the original post to correct that.

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!

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.

@tisho solution worked for me too. I also had to follow the same steps to my app's Test target in addition to the main app target

@tisho you deserve a medal for this!

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)

j2kun commented

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

What about the "Per-configuration Immediate Build Products Path"? It'd make sense for Staging to share the same path as Release too?

@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!

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.

natdm commented

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)

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

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 πŸ€”

@natdm I have the same issue. Were you able to solve it?

Update
This solved my issue with the ld -L warnings: oblador/react-native-vector-icons#223 (comment)

@jamesone I think we are in the same boat. Are you by chance trying to integrate code-push? haha. For us we can build our staging config locally using @philipshurpik's solution but only after we have built the project for release (building with the release scheme). If you clean your build then run your staging scheme does it still work? For us @philipshurpik's solution works locally if we build for release first, but Buddy Build doesn't work like that so BB fails

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

@stantoncbradley I'm getting that exact same error. I've also tried using the scheme manager, but it doesn't work for buddybuild :\

Have you contacted buddybuild about this?

D1no commented

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

Okay so here is what I did to get a new build configuration working:

I followed this guide: https://www.buddybuild.com/blog/running-multiple-ios-apps (this is not specific to buddybuild, it shows you how to add a new scheme & build configuration)

NOTE that when you get to:

Finally, update the build configuration referenced from the scheme - so that we build with the Staging build configuration.

You must make sure that the Archive (located here: https://s3-us-west-2.amazonaws.com/buddybuild-public/blog-assets/multi-versions-of-your-app/multiple-versions-of-your-app-8.jpg) build configuration is pointing to your new one

@stantoncbradley

@tisho Thank!! It worked!! I spend almost a week solving this problem. You saved me! Thank you.

D1no commented

@stantoncbradley did you get buddybuild to work with Schema manager?

@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!

@D1no Thanks!!! Your solution works.

D1no commented

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 alt + 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 . πŸ˜‡

@tisho thanks

@tisho I followed your solution,but it didn't work.this is my screenshot:
I also add React in Build Phases --> Target Dependencies,but it didn't work too......
24ecffbb-f589-40ac-a1a6-a82032e33125
b99b7516-1ec8-4926-b0f6-695b7daf0eaa

@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)

Eluss commented

@easybird I had the same issue and setting library search paths indeed solves the problem, thanks!

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.

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????

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

Tried @tisho solution but i got a new error. Not really sure what am i suppose to do next.

library not found for -lRealmReact

@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

I was able to create a staging environment following @philipshurpik and @j2kun suggestions. However, if I create a new scheme to create a staging archive, the build fails with the same error React/RCTBridgeModule.h file not found. If I edit the default scheme to use the staging configuration, then the archive is created successfully. Is there any other trick to get new schemes to work as well using the new staging configuration. I want to avoid having to keep editing the scheme every time I create a staging or a release archive. I fear I may forget to change and create unwanted problems.

I created a staging configuration and I was able to create an IPA file using the staging configuration. But when I upload the IPA to iTunesConnect, I see that the IPA is missing the frameworks that I am using in the app. The frameworks are present when the IPA is created using the release configuration. Below are the screenshots for the staging and the release configuration. Observe that the frameworks are not listed.

Staging
screen shot 2017-09-22 at 9 06 25 am

Release
screen shot 2017-09-22 at 9 06 53 am

Observe that the frameworks are not listed in the staging IPA when I try to upload it iTunesConnect. Due to this, I got an error from iTunesConnect

Invalid Bundle - One or more dynamic libraries that are referenced by your app are not present in the dylib search path.

Below is a screenshot of the framework search paths in the Xcode project. The value is same for both staging and release.

screen shot 2017-09-22 at 12 36 38 pm

Please let me know how can I fix this problem.

D1no commented

@varungupta85 check out schema manager mentioned above. Its purpose is to add the libraries from node_modules to the new release targets.

@D1no Thanks for your reply. I looked at the react-native-schemes-manager when I was going to through the comments. I felt that it is doing a lot of magic in the background which always worries me because if things start to break in future, I am not sure where to look at. I tried the suggestions from @philipshurpik and @j2kun using which I was able to build the app using staging configuration. I feel that I should be able to get the frameworks to be also present in the IPA with some change in settings in Xcode.

I will use the react-native-schemes-manager if I don't find a solution to this problem soon.

D1no commented

Actually there is not much magic. Just automation of a very annoying Xcode manual task. Read more at the bottom of the package, it’s sources and what it does. If all react native packages would be cocoa pods, the problem would not exist. But as they all require the rn packanger which has just two build configurations, those need to be copied for all of them. Thinkmill and we use it in production, and probably many more, and it works fine with version react-native@latest with Xcode 9.

So, requiring xproject files from node_modules was never something Xcode was designed for. I mean, sometimes it feels likeXcode projects were not even designed for a code revision system, due to its cryptic uid file steucture.

Until all that changes, or the guys at the metro bundler tackle this problem in a very smart way, the work stays the same. And it is very hard to configure yourself out of that.

@D1no Thanks for the detailed reply. I feel more confident about using the scheme manager now and since I haven't been able to work around the problem I reported, I will start using it.

I just wanted to point out one small thing that after I updated the CONFIGURATION_BUILD_DIR AND POD_CONFIGURATION_BUILD_DIR, I was able to build the app. The missing frameworks in the IPA are all pods that I have installed in my app mainly Sentry, KSCrash, RSKImageCropper and QBImagePicker`. I am not sure if it sheds any more light on the problem I am having since you said that the said issue doesn't occur with packages installed using cocoa pods and that the scheme manager is mainly to fix the projects installed using npm.

Thanks again for taking the time to post your comments.

stale commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. If you think this issue should definitely remain open, please let us know why. Thank you for your contributions.

worked.

@varungupta85 even i am facing the issue of frameworks not being listed in staging scheme. Did you find a solution for this?

@shohey1226 i tried the same thing but its not working for me. Looks like the pod libraries are getting copied into Staging folder instead of release which leads to #11813 (comment)

/Users/harkirat/Library/Developer/Xcode/DerivedData/wlv1-grovuwlrhzpjbvenlreejvbtlwol/Build/Intermediates.noindex/ArchiveIntermediates/wlv1 Staging/BuildProductsPath
tests-MBP:BuildProductsPath harkirat$ ls
Release-iphoneos	Staging-iphoneos
tests-MBP:BuildProductsPath harkirat$
tests-MBP:BuildProductsPath harkirat$ cd Staging-iphoneos/
tests-MBP:Staging-iphoneos harkirat$ ls
GTMOAuth2		Mixpanel		QBImagePickerController
GTMSessionFetcher	Pods_wlv1.framework	RSKImageCropper
GoogleToolboxForMac	Protobuf		nanopb
tests-MBP:Staging-iphoneos harkirat$
tests-MBP:BuildProductsPath harkirat$ cd Release-iphoneos/
tests-MBP:Release-iphoneos harkirat$ ls
49D27CAF-3566-30BB-9FF1-63E20D4D5231.bcsymbolmap	libRCTMaterialKit.a
57C7F55D-A2AE-30F3-A6EA-9F38A1651329.bcsymbolmap	libRCTNetwork.a
5maFL9							libRCTSettings.a
B00A891C-B9FD-3621-85B1-D7ACEEB3888C.bcsymbolmap	libRCTText.a
B881CB00-A637-3C8C-90B1-36E49E358AA1.bcsymbolmap	libRCTVibration.a
GeneratedInfoPlistDotEnv.h				libRCTWebSocket.a
Hhe8NH							libRNDeviceInfo.a
QBImagePicker.framework					libRNFIRMessaging.a
QBImagePicker.framework.dSYM				libRNFS.a
RSKImageCropper.framework				libRNFetchBlob.a
RSKImageCropper.framework.dSYM				libRNIntercom.a
include							libRNMixpanel.a
libBVLinearGradient.a					libReact.a
libBugsnagReactNative.a					libReactNativeConfig.a
libBugsnagStatic.a					libcxxreact.a
libCodePush.a						libdouble-conversion.a
libRCTActionSheet.a					libimageCropPicker.a
libRCTAnimation.a					libjschelpers.a
libRCTCamera.a						libthird-party.a
libRCTFBSDK.a						libyoga.a
libRCTGeolocation.a					wlv1.app
libRCTImage.a						wlv1.swiftmodule
libRCTLinking.a

I tried adding "$PODS_CONFIGURATION_BUILD_DIR" as recursive to FRAMEWORK_PATH but still it creates 2 folders.

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.

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).

@D1no you should post that in a medium article !! nice !

D1no commented

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. πŸ™ƒ