react-native-config: Availability in Build settings and Info.plist problem

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"

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 7
  • Comments: 33 (5 by maintainers)

Commits related to this issue

Most upvoted comments

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

  1. 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 }
    
  2. 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.

  3. 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
    
  4. 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.

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

  6. 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
    
  7. 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:

  • Maybe there is a cleaner solution using only tmp.xcconfig but this is out of my scope
  • I remember I used ReactNativeConfig 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.

This is my solution :

  • react-native 0.61.5
  • react-native-config 1.3.3
  • Create a variable on config.xcconfig file (ex: APP_NAME_TEST = AppNameTest)
  • Call it on info.plist : ${APP_NAME_TEST} --> Build
  • Try with another variable on your env file(staging, production…) --> Rebuild
  • Enjoy !!! —> Hope to help you.

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

image

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.

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

If anyone needs https://github.com/luggit/react-native-config/issues/391#issuecomment-571948199 as a permanent patch:

  1. Add patch-package
yarn add --dev patch-package # or npm install -D patch-package
  1. Add 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",
  1. Create the patchfile at patches/react-native-config+1.0.0.patch
diff --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) 4. yarn or npm install 5. cd ios && pod install --repo-update && cd -

Confirmed working on:

react-native: 0.61.5 react-native-config: 1.0.0

PS Note that variables don’t have RNC_ prefix as with the legacy approach involving the Info.plist preprocessing.

Ty bro! That was my issue

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?

leaving here a note in case someone else has the same issue I was still having an issue with Info.plist not being processed correctly when building in bitrise I have pre-action defined in both “build” and “archive”, and I can see that the file tmp.xcconfig exists but I guess there is some race condition after all.

Running manually after npm install before the build step solves the issue

#!/usr/bin/env bash
./node_modules/react-native-config/ios/ReactNativeConfig/BuildXCConfig.rb . ios/tmp.xcconfig 

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 input shell -> /bin/sh and in Provide build settings from -> "your target"

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

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

Worked for me.

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

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

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();