where we must to add below code in step 6 of Availability in Build settings and Info.plist section:
"${SRCROOT}/../node_modules/react-native-config/ios/ReactNativeConfig/BuildXCConfig.rb" "${SRCROOT}/.." "${SRCROOT}/tmp.xcconfig"
In your scheme settings, Build -> Pre-actions
If you haven't followed this approach then follow these steps first and then add the line you have quoted above,
Expand the "Build" settings on left
Click "Pre-actions", and under the plus sign select "New Run Script Action"
Since the update from 0.11.7 to 0.12.0 all variables used in info.plist are only updated on the second build. The Build log shows RN-config updates the variables correct on first build, but the info.plist in the produced app is not updated correspondingly.
This was better in v0.11.7 when plist-preprocessing was possible using the GeneratedInfoPlistDotEnv.h file. As this file is not longer produced after the update (due to changes in BuildDotenvConfig.ruby now BuildDotenvConfig.rb) this convenient way of updating variables on first build is no longer available.
Any thoughs on this?
Looks like @rafaelmaeuer 's comment and #409 are related.
why was the code generating, GeneratedInfoPlistDotEnv.h removed?
GeneratedInfoPlistDotEnv.h removed?
Yep
why was the code generating,
I don't really understand the context to give an answer to this.
Yeah so on my circle ci build, I'm now running this custom script which is a temporary measure.
patches in the .env file into info.plist
#!/usr/bin/env node
const fs = require('fs');
const dotenv = require('dotenv');
const promisify = require('util').promisify;
const writeFile = promisify(fs.writeFile);
const readFile = promisify(fs.readFile);
async function main() {
try {
console.log('===================== THIS IS A TEMPORARY SCRIPT ===================');
console.log('===================== UPDATING Info.plist with .env ================');
console.log('====================================================================');
console.log('see Issue: https://github.com/luggit/react-native-config/issues/391');
const envfile = await readFile('./.env', 'utf-8');
const plist = await readFile('./ios/medapp/Info.plist', 'utf-8');
const env = dotenv.parse(Buffer.from(envfile));
let plistupdated = plist;
Object.entries(env).forEach(([key,value]) => {
plistupdated = plistupdated.replace(new RegExp(`\\$\\(${key}\\)`, 'g'), value);
});
await writeFile('./ios/medapp/Info.plist', plistupdated, 'utf-8');
await writeFile('./ios/medapp/Info.plist.bak', plist, 'utf-8');
} catch (e) {
console.error(e);
console.error(`Unable to read .env file`);
process.exit(1);
}
}
main();
My temporary workaround is to remove the app and build again:
ENVFILE=.env.test node_modules/.bin/detox build --configuration ios.sim.release
rm -rf ios/build/Build/Products/Release-iphonesimulator/xxx.app
ENVFILE=.env.test node_modules/.bin/detox build --configuration ios.sim.release
ENVFILE=.env.test node_modules/.bin/detox test --configuration ios.sim.release
@export-mike I'm using Bitrise as my CI/CD platform, and your custom script worked for me, thank you. I hope a proper fix is released soon.
Hi ! If your issue is Build input file cannot be found: GeneratedDotEnv.m and if you are using pods and RN > 0.60, you can patch the podspec with this commit : https://github.com/bamlab/react-native-config/commit/05761868680ad46c9dbd1f56d7d504f056f444db
(file located at node_modules/react-native-config/react-native-config.podspec)
s.script_phase = {
name: 'Config codegen',
script: %(
- set -ex
- HOST_PATH="$SRCROOT/../.."
- "${PODS_TARGET_SRCROOT}/ios/ReactNativeConfig/BuildDotenvConfig.rb" "$HOST_PATH" "${PODS_TARGET_SRCROOT}/ios/ReactNativeConfig"
- ),
+ set -ex
+ HOST_PATH="$SRCROOT/../.."
+ ${PODS_TARGET_SRCROOT}/ios/ReactNativeConfig/BuildDotenvConfig.rb $HOST_PATH ${PODS_TARGET_SRCROOT}/ios/ReactNativeConfig
+ ),
execution_position: :before_compile,
- input_files: ['$(SRCROOT)/ReactNativeConfig/BuildDotenvConfig.rb']
+ input_files: ['$PODS_TARGET_SRCROOT/ios/ReactNativeConfig/BuildDotenvConfig.rb'],
+ output_files: ['$PODS_TARGET_SRCROOT/ios/ReactNativeConfig/GeneratedDotEnv.m']
}
s.source_files = 'ios/**/*.{h,m}'
Explanation: The custom pod script generates the GeneratedDotEnv.m file at the same time XCode requires it. There is a race condition. In order to fix that, we need to tell XCode that our script outputs one file that is required in another step. Doing so, XCode new Build system will create a correct dependency graph and erase this race condition.
Source: http://www.gietal.net/blog/xcode10-and-prebuild-script-output-files-xcfilelist
@rafaelmaeuer did you end up using a workaround that worked? Currently my workaround is to build the first env of the app twice.
I didn't had the time to test any workaround yet, so I am doing the same: building the app twice is annoying but it works...
@tpucci Thanks for your suggestion (https://github.com/luggit/react-native-config/issues/391#issuecomment-571948199), it's the only thing which seems to work for me, only issue is remembering to edit the podspec if/when node_modules is rebuilt 馃槱
@tpucci Thanks for your suggestion (#391 (comment)), it's the only thing which seems to work for me, only issue is remembering to edit the podspec if/when node_modules is rebuilt
@leemcmullen I recommend that you use 'patch-package' in order not to worry about that.
@tpucci Good idea, thanks Thomas! 馃憤
anyplans to release this patch as a fix?
If anyone needs https://github.com/luggit/react-native-config/issues/391#issuecomment-571948199 as a permanent patch:
yarn add --dev patch-package # or npm install -D patch-package
patch-package to postinstall step in package.json...
"scripts": {
...
"postinstall": "patch-package",
...
},
...
In our script we also need react-native-inhibit-warnings and jetifier
"postinstall": "react-native-inhibit-warnings && jetifier && patch-package",
patches/react-native-config+1.0.0.patchdiff --git a/node_modules/react-native-config/react-native-config.podspec b/node_modules/react-native-config/react-native-config.podspec
index 918eb47..e0dfec7 100644
--- a/node_modules/react-native-config/react-native-config.podspec
+++ b/node_modules/react-native-config/react-native-config.podspec
@@ -25,7 +25,8 @@ HOST_PATH="$SRCROOT/../.."
"${PODS_TARGET_SRCROOT}/ios/ReactNativeConfig/BuildDotenvConfig.rb" "$HOST_PATH" "${PODS_TARGET_SRCROOT}/ios/ReactNativeConfig"
),
execution_position: :before_compile,
- input_files: ['$(SRCROOT)/ReactNativeConfig/BuildDotenvConfig.rb']
+ input_files: ['$PODS_TARGET_SRCROOT/ios/ReactNativeConfig/BuildDotenvConfig.rb'],
+ output_files: ['$PODS_TARGET_SRCROOT/ios/ReactNativeConfig/GeneratedDotEnv.m']
}
s.source_files = 'ios/**/*.{h,m}'
(Note I removed whitespace changes from @tpucci 's patch)
yarn or npm installcd ios && pod install --repo-update && cd -Confirmed working on:
react-native: 0.61.5
react-native-config: 1.0.0
@jacobcabantomski-ct any reason why this needs to stay as a match and not merged, I've seen others fork the project just to make this change
@socialcode-rob1 https://github.com/luggit/react-native-config/pull/454
Thanks for adding the patch to the latest release, but the plist variables on first build are still not working for me. Can someone post a working example on how to configure this correctly?
EDIT: I figured it out by myself
Necessary modification in BuildDotenvConfig.rb line 28 (Pull-Request https://github.com/luggit/react-native-config/pull/457) to re-enable the creation of GeneratedInfoPlistDotEnv.h which was lost in update 0.11.7 to 0.12.0.
- #File.delete('/tmp/envfile') if custom_env
+ # create header file with defines for the Info.plist preprocessor
+ info_plist_defines_objc = dotenv.map { |k, v| %Q(#define RNC_#{k} #{v}) }.join("\n")
+
+ # write it so the Info.plist preprocessor can access it
+ path = File.join(ENV["BUILD_DIR"], "GeneratedInfoPlistDotEnv.h")
+ File.open(path, "w") { |f| f.puts info_plist_defines_objc }
Add this 2 scripts to a scripts folder in project root
generate-dot-env-files.sh:
#!/usr/bin/env bash
# get script parameter
SRC_ROOT=$1
# create config files
RNC_ROOT=./node_modules/react-native-config/ &&
export SYMROOT=$RNC_ROOT/ios/ReactNativeConfig &&
ruby $RNC_ROOT/ios/ReactNativeConfig/BuildDotenvConfig.rb ${SRC_ROOT}/../ ${SYMROOT}
This script creates/updates necessary GeneratedDotEnv.m and GeneratedInfoPlistDotEnv.h files.
generate-env-config.sh:
#!/usr/bin/env bash
# get script parameter
SRC_ROOT=$1
# Generate tmp.xcconfig
"${SRC_ROOT}/../node_modules/react-native-config/ios/ReactNativeConfig/BuildXCConfig.rb" "${SRC_ROOT}/.." "${SRC_ROOT}/tmp.xcconfig"
This script generates tmp.xcconfig from .env file which is used to access variables from JavaScript side.
In Xcode select your main project file and add 2 External Build Tool Configurations in the Targets area
GenerateEnvFiles:
Build Tool: ${SRCROOT}/../scripts/generate-dot-env-files.sh
Arguments: ${SRCROOT}
Directory: ${SRCROOT}/..
[x] Pass build settings in environment
GenerateEnvConfigFiles:
Build Tool: ${SRCROOT}/../scripts/generate-env-config.sh
Arguments: ${SRCROOT}
Directory: ${SRCROOT}/..
[x] Pass build settings in environment
Open your build scheme, disable option Parallelize Build and add both newly created targets before your app targets, place GenerateEnvConfigFiles on first, GenerateEnvFiles at second position.
In your build scheme select Build -> Pre-Actions, set /bin/sh as Shell and add following script:
exec > ${PROJECT_DIR}/prebuild.log 2>&1
echo "Prebuild Script" ${BUILD_STYLE}
rm "${TEMP_DIR}/Preprocessed-Info.plist"
if [ $? -eq 0 ]; then
echo "Removed prebuilt plist from ${TEMP_DIR}"
fi
This logs the script output to prebuild.log file in ios folder. It removes the preprocessed info.plist so variable changes gets updated on every build.
Open up the Build Settings of your app target, search for preprocess and add following:
Info.plist Other Preprocessor Flags = -traditional
Info.plist Preprocessor Prefix File = ${BUILD_DIR}/GeneratedInfoPlistDotEnv.h
Preprocess Info.plist File = YES
Finally you can use your variables defined in .env file (e.g. APP_VERSION and APP_BUILD) in your Info.plist with RNC_APP_VERSION and RNC_APP_BUILD and the variables are updated on every build.
Some further thoughts:
tmp.xcconfig but this is out of my scopeReactNativeConfig instead of GenerateEnvFiles target because the necessary files were generated on build (BuildDotenvConfig.rb is called as run script) but it didn't worked this time.@rafaelmaeuer Can your steps be added to the README, or should a more automatic solution be investigated?
If this is wanted I can update the readme to include my solution. @luancurti what do you think?
working on: "react-native-config": "1.2.1",
If this is wanted I can update the readme to include my solution. @luancurti what do you think?
I think it's a good idea to add this throubleshoting in the README @rafaelmaeuer feel free to make this PR
This is my solution :
Hi ! If your issue is
Build input file cannot be found: GeneratedDotEnv.mand if you are using pods and RN > 0.60, you can patch the podspec with this commit : bamlab@0576186(file located at
node_modules/react-native-config/react-native-config.podspec)s.script_phase = { name: 'Config codegen', script: %( - set -ex - HOST_PATH="$SRCROOT/../.." - "${PODS_TARGET_SRCROOT}/ios/ReactNativeConfig/BuildDotenvConfig.rb" "$HOST_PATH" "${PODS_TARGET_SRCROOT}/ios/ReactNativeConfig" - ), + set -ex + HOST_PATH="$SRCROOT/../.." + ${PODS_TARGET_SRCROOT}/ios/ReactNativeConfig/BuildDotenvConfig.rb $HOST_PATH ${PODS_TARGET_SRCROOT}/ios/ReactNativeConfig + ), execution_position: :before_compile, - input_files: ['$(SRCROOT)/ReactNativeConfig/BuildDotenvConfig.rb'] + input_files: ['$PODS_TARGET_SRCROOT/ios/ReactNativeConfig/BuildDotenvConfig.rb'], + output_files: ['$PODS_TARGET_SRCROOT/ios/ReactNativeConfig/GeneratedDotEnv.m'] } s.source_files = 'ios/**/*.{h,m}'_Explanation:_ The custom pod script generates the
GeneratedDotEnv.mfile at the same time XCode requires it. There is a race condition. In order to fix that, we need to tell XCode that our script outputs one file that is required in another step. Doing so, XCode new Build system will create a correct dependency graph and erase this race condition._Source:_ http://www.gietal.net/blog/xcode10-and-prebuild-script-output-files-xcfilelist
Worked for me.
I'm using pod generated xcconfig files, so I created a post_install that appends #include? "tmp.xcconfig"
post_install do |installer|
puts "Updating Targets to include react-native-config env variables"
installer.generated_aggregate_targets.each do |target|
["Debug", "Release"].each do |config|
rpath = target.xcconfig_relative_path(config)
puts " updating #{target.name} :#{config}"
open(rpath, 'a') { |f|
f.puts "#include? \"tmp.xcconfig\""
}
end
end
end
I was having the same issue but I found that my bash script was not properly written in the prebuild scripts. It should be like
cp ${PROJECT_DIR}/../.env.dev ${PROJECT_DIR}/../.env
"${SRCROOT}/../node_modules/react-native-config/ios/ReactNativeConfig/BuildXCConfig.rb" "${SRCROOT}/.." "${SRCROOT}/tmp.xcconfig"
also, you have to write in the inputshell -> /bin/sh
and in Provide build settings from -> "your target"
It was not very clear from README instructions where to add the script to generate tmp.xcconfig, so I mistakenly added it to the Build Phases under my application target. As it turned out it was too late: Info.plist is copied to the BUILD_DIR as a first step of the build and tmp.xcconfig is generated after that. As a result on the first build values from the tmp.xcconfig are not picked up and changes to the .env file are only picked up by the second build after the change is made.
The correct place where to add BuildXCConfig.rb is in Edit scheme... -> Build -> Pre-actions. Also make sure to select your target for "Provide build settings from".

Otherwise the approach seems to work correctly and you don't need to make loads of manual work as described in https://github.com/luggit/react-native-config/issues/391#issuecomment-632331803.
PS Note that variables don't have RNC_ prefix as with the legacy approach involving the Info.plist preprocessing.
UPD
Apparently one needs to setup same Pre-Action for the Archive schema, so values are available during the Archive build. And likely for every single schema you use. So I decided to to run this script manually before invoking Xcode to avoid maintaining same code in multiple places.
PS Note that variables don't have
RNC_prefix as with the legacy approach involving theInfo.plistpreprocessing.
Ty bro! That was my issue
This is my solution
This is my pre action build script, I use /tmp/envfile where I copy my current env file based on a User-defined variable, ie ${RNCONFIG_ENVIRONMENT}
# Type a script or drag a script file from your workspace to insert its path.
# exec > ${PROJECT_DIR}/prebuil#d.log 2>&1
# ie, copy .env.development to /tmp/envfile
cp "${SRCROOT}/../.env.${RNCONFIG_ENVIRONMENT}" "/tmp/envfile"
# same as always, not changes here
"${SRCROOT}/../node_modules/react-native-config/ios/ReactNativeConfig/BuildXCConfig.rb" "${SRCROOT}/.." "${SRCROOT}/tmp.xcconfig"
To setup a user defined variable, do this,
Xcode -> Left panel (select top root project) -> Targets (your project) -> Build settings -> (click) Plus icon -> Add user defined settings

Add a variable called RNCONFIG_ENVIRONMENT with both values, for debug and release

Remember to create both env files in your root react native project, ie, .env.development and .env.production
The final changed is to modified the file node_modules/react-native-config/ios/ReactNativeConfig/ReadDotEnv.rb
diff --git a/old.txt b/new.txt
index 4e9fd89..51bd95e 100644
--- a/old.txt
+++ b/new.txt
@@ -14,28 +14,30 @@ def read_dot_env(envs_root)
# pick a custom env file if set
if File.exist?('/tmp/envfile')
custom_env = true
- file = File.read('/tmp/envfile').strip
+ raw = File.read('/tmp/envfile').strip
else
custom_env = false
file = ENV['ENVFILE'] || defaultEnvFile
end
-
dotenv = begin
# https://regex101.com/r/cbm5Tp/1
dotenv_pattern = /^(?:export\s+|)(?<key>[[:alnum:]_]+)\s*=\s*((?<quote>["'])?(?<val>.*?[^\\])\k<quote>?|)$/
- path = File.expand_path(File.join(envs_root, file.to_s))
- if File.exist?(path)
- raw = File.read(path)
- elsif File.exist?(file)
- raw = File.read(file)
- else
- defaultEnvPath = File.expand_path(File.join(envs_root, "#{defaultEnvFile}"))
- unless File.exist?(defaultEnvPath)
- # try as absolute path
- defaultEnvPath = defaultEnvFile
+ unless custom_env
+ path = File.expand_path(File.join(envs_root, file.to_s))
+ if File.exist?(path)
+ raw = File.read(path)
+ elsif File.exist?(file)
+ raw = File.read(file)
+ else
+ defaultEnvPath = File.expand_path(File.join(envs_root, "#{defaultEnvFile}"))
+ puts defaultEnvPath
+ unless File.exist?(defaultEnvPath)
+ # try as absolute path
+ defaultEnvPath = defaultEnvFile
+ end
+ raw = File.read(defaultEnvPath)
end
- raw = File.read(defaultEnvPath)
end
raw.split("\n").inject({}) do |h, line|
I recommend to use patch-package to build your own patch.
It was not very clear from README instructions where to add the script to generate
tmp.xcconfig, so I mistakenly added it to the Build Phases under my application target. As it turned out it was too late:Info.plistis copied to the BUILD_DIR as a first step of the build andtmp.xcconfigis generated after that. As a result on the first build values from thetmp.xcconfigare not picked up and changes to the.envfile are only picked up by the second build after the change is made.The correct place where to add
BuildXCConfig.rbis in Edit scheme... -> Build -> Pre-actions. Also make sure to select your target for "Provide build settings from".
Otherwise the approach seems to work correctly and you don't need to make loads of manual work as described in #391 (comment).
PS Note that variables don't have
RNC_prefix as with the legacy approach involving theInfo.plistpreprocessing.UPD
Apparently one needs to setup same Pre-Action for the Archive schema, so values are available during the Archive build. And likely for every single schema you use. So I decided to to run this script manually before invoking Xcode to avoid maintaining same code in multiple places.
This worked for me as well. Im developing with multiple targets (dev, stage, prod). So I had to add Pre-actions to every target.
Most helpful comment
Thanks for adding the patch to the latest release, but the plist variables on first build are still not working for me. Can someone post a working example on how to configure this correctly?
EDIT: I figured it out by myself
Necessary modification in
BuildDotenvConfig.rbline 28 (Pull-Request https://github.com/luggit/react-native-config/pull/457) to re-enable the creation ofGeneratedInfoPlistDotEnv.hwhich was lost in update 0.11.7 to 0.12.0.Add this 2 scripts to a
scriptsfolder in project rootgenerate-dot-env-files.sh:This script creates/updates necessary
GeneratedDotEnv.mandGeneratedInfoPlistDotEnv.hfiles.generate-env-config.sh:This script generates
tmp.xcconfigfrom.envfile which is used to access variables from JavaScript side.In Xcode select your main project file and add 2
External Build Tool Configurationsin theTargetsareaGenerateEnvFiles:GenerateEnvConfigFiles:Open your build scheme, disable option
Parallelize Buildand add both newly created targets before your app targets, placeGenerateEnvConfigFileson first,GenerateEnvFilesat second position.In your build scheme select Build -> Pre-Actions, set
/bin/shas Shell and add following script:This logs the script output to
prebuild.logfile iniosfolder. It removes the preprocessed info.plist so variable changes gets updated on every build.Open up the
Build Settingsof your app target, search forpreprocessand add following:Finally you can use your variables defined in .env file (e.g. APP_VERSION and APP_BUILD) in your Info.plist with RNC_APP_VERSION and RNC_APP_BUILD and the variables are updated on every build.
Some further thoughts:
tmp.xcconfigbut this is out of my scopeReactNativeConfiginstead ofGenerateEnvFilestarget because the necessary files were generated on build (BuildDotenvConfig.rbis called as run script) but it didn't worked this time.