Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Availability in Build settings and Info.plist problem #391

Closed
majidln opened this issue Sep 24, 2019 · 33 comments · Fixed by #454
Closed

Availability in Build settings and Info.plist problem #391

majidln opened this issue Sep 24, 2019 · 33 comments · Fixed by #454

Comments

@majidln
Copy link

majidln commented Sep 24, 2019

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"

@JanithaR
Copy link

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"

@rafaelmaeuer
Copy link
Contributor

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?

@JanithaR
Copy link

Looks like @rafaelmaeuer 's comment and #409 are related.

@export-mike
Copy link

why was the code generating, GeneratedInfoPlistDotEnv.h removed?

@JanithaR
Copy link

GeneratedInfoPlistDotEnv.h removed?

Yep

why was the code generating,

I don't really understand the context to give an answer to this.

@export-mike
Copy link

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

@dunghuynh
Copy link

dunghuynh commented Dec 20, 2019

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

@luis-f-lins
Copy link

luis-f-lins commented Jan 7, 2020

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

@tpucci
Copy link

tpucci commented Jan 8, 2020

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

@geraintwhite
Copy link

@rafaelmaeuer did you end up using a workaround that worked? Currently my workaround is to build the first env of the app twice.

@rafaelmaeuer
Copy link
Contributor

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

@leemcmullen
Copy link

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

@tpucci
Copy link

tpucci commented Apr 17, 2020

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

@leemcmullen
Copy link

@tpucci Good idea, thanks Thomas! 👍

@export-mike
Copy link

anyplans to release this patch as a fix?

@ghost
Copy link

ghost commented May 13, 2020

If anyone needs #391 (comment) 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

@socialcode-rob1
Copy link

@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

@ghost ghost mentioned this issue May 19, 2020
@ghost
Copy link

ghost commented May 19, 2020

@socialcode-rob1 #454

luancurti pushed a commit that referenced this issue May 19, 2020
Resolves #391
Based on #391 (comment)
Add correct output file.
Update input file to use correct root path.
@rafaelmaeuer
Copy link
Contributor

rafaelmaeuer commented May 21, 2020

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 create GeneratedInfoPlistDotEnv.h for Info.plist preprocessing #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.

@geraintwhite
Copy link

@rafaelmaeuer Can your steps be added to the README, or should a more automatic solution be investigated?

@rafaelmaeuer
Copy link
Contributor

If this is wanted I can update the readme to include my solution. @luancurti what do you think?

@tnghia944
Copy link

working on: "react-native-config": "1.2.1",

@luancurti
Copy link
Collaborator

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

@HinHin86197
Copy link

HinHin86197 commented Aug 17, 2020

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.

@yksingh12
Copy link

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.

@Voltron369
Copy link

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

@abdeali41
Copy link

abdeali41 commented Sep 30, 2020

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"

@devoto13
Copy link
Contributor

devoto13 commented Oct 5, 2020

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 #391 (comment).

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.

@blazlew
Copy link

blazlew commented Oct 14, 2020

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

@arcollector
Copy link

arcollector commented Oct 21, 2020

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

Screen Shot 2020-10-21 at 18 41 49

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

Screen Shot 2020-10-21 at 17 25 15

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|

full file

I recommend to use patch-package to build your own patch.

@SameeraMadushan
Copy link

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 #391 (comment).

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.

This worked for me as well. Im developing with multiple targets (dev, stage, prod). So I had to add Pre-actions to every target.

@adrach
Copy link

adrach commented Jan 8, 2021

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 

@Andarius
Copy link

@adrach when running this commande manually, how do you determine what the BUILD_DIR used by the script is ?

venus-heaven pushed a commit to venus-heaven/config-React-native that referenced this issue Mar 11, 2024
Resolves lugg/react-native-config#391
Based on lugg/react-native-config#391 (comment)
Add correct output file.
Update input file to use correct root path.
dev-arrow added a commit to dev-arrow/react-native-config that referenced this issue Nov 25, 2024
Resolves lugg/react-native-config#391
Based on lugg/react-native-config#391 (comment)
Add correct output file.
Update input file to use correct root path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.