29

I have different build configurations (Debug, Stage, Prod) defined for my app and I use User-Defined build settings:

enter image description here

to set up Facebook login and other stuff in Info.plist file:

enter image description here

In this scenario the $(USER_DEFINED_SETTINGS) notation does work.

When I tried to set up Google SignIn, which requires using additional .plist file (GoogleService-Info.plist), and I used User-Defined settings in the same way I do in the Info.plist file, it doesn't work.

How can I use User-Defined settings in custom .plist files? If I can't, how can I workaround this?

KlimczakM
  • 12,576
  • 11
  • 64
  • 83
  • Check **xcconfig** functional. Maybe it can help https://stackoverflow.com/questions/38328837/change-user-defined-variable-from-fastlane – Nike Kov Oct 13 '21 at 09:26

4 Answers4

46

It's NOT possible to use User-Defined settings in custom .plist file.

BUT you can copy your custom .plist file to the right place when building the app:

  1. Create a new folder (for example: Resources/GoogleServiceInfoPlists).

  2. Copy there all .plist files for build configuration. For example:

  3. GoogleService-Info-Debug.plist

  4. GoogleService-Info-Stage.plist

  5. GoogleService-Info-Prod.plist

  6. Add new Run Script Phase - Xcode: Target-->Build Phases-->"+" button (top left corner).

  7. Use the script below to copy (replace) .plist file for given build configuration to the project directory:

    cp "${SRCROOT}/${PRODUCT_NAME}/Resources/GoogleServiceInfoPlists/GoogleService-Info-$CONFIGURATION.plist" "${SRCROOT}/${PRODUCT_NAME}/GoogleService-Info.plist"
    
  8. Under Output Files, you should possibly also enter the target file in order to ensure the next phase begins only if the file was actually copied.

    "${SRCROOT}/${PRODUCT_NAME}/GoogleService-Info.plist"
    
  9. Important: move newly added script before Copy Bundle Resources phase, or it will use the default file, ignoring replaced file.

Used variables/paths:

${SRCROOT} - predefined, it points to your project location.

${PRODUCT_NAME} - predefined, product name.

$CONFIGURATION - predefined, it's your build configuration. By default, it is: Debug, Release. In my case: Debug, Stage, Prod. You can change build configurations in Xcode: Project (not Target!)-->Info.

Note:

GoogleService-Info.plist file must be added to the Xcode project resources (Build Phases-->Copy Bundle Resources) while Resources/GoogleServiceInfoPlists/GoogleService-Info-* files not necessarily.

If the above doesn't work try clicking in your disired .plist file > File Inspector > Target Membership > Check your main project so it can be bundled together in final output.

Ely Dantas
  • 705
  • 11
  • 23
KlimczakM
  • 12,576
  • 11
  • 64
  • 83
  • 2
    +1 Although I don't like the solution itself, I cannot find any other way to achieve it. Google should provide at least the way to change the tracking identifier through the API (and not modify the .plist ourselves). – GoRoS Mar 23 '16 at 09:13
  • @GoRoS I agree it's not the best solution I can imagine, but unfortunately, it's the only way I could achieve that after spending a lot of time trying to solve this nicely. – KlimczakM Mar 23 '16 at 11:11
  • 1
    I think you can use ${USER_DEFINED_SETTINGS} not in a custom plist, but in your project`s Info.plist, but I haven´t tried it yet. – 最白目 May 11 '16 at 07:01
  • 1
    Sure, but Google sign-in requires separate (custom) .plist file. – KlimczakM May 11 '16 at 07:02
  • This is minor but is there a way to have the script run before the app starts? It doesn't seem to copy the file until after the app launches and you can test this by changing the settings and running. The only way to make sure is to Build first, then run. – pixelfreak May 28 '16 at 08:06
  • 1
    I applied this solution and came across the following issue. I do see the file getting copied into my main directory, however, I think the file didn't get linked with my Xcode project so it still resulted in "missing GoogleService-Info.plist file". Does anyone else have this issue? – howly Jul 15 '16 at 23:30
  • 2
    @howly I have 4 files in my repository `GoogleService-Info.plist` and these 3 mentioned in my answer. `GoogleService-Info.plist` is **replaced** (not just copied) by 1 of these, so Xcode doesn't complain about it. – KlimczakM Jul 16 '16 at 09:44
  • 2
    @pixelfreak, have you tried clicking and dragging the build phases to ensure the copying takes place before the files are linked? – Dr.Seuss Aug 24 '16 at 09:04
  • @howly beside adding a 'Run Script Phase' you have click in your custom .plist file > File Inspector > Target Membership to your project so it can be bundled together in final output – Ely Dantas Mar 03 '21 at 23:12
4
  1. Create a new folder (for example: GoogleServiceInfoPlists).

  2. Copy there all .plist files for each Configuration

for example:

GoogleService-Info-Debug.plist, 
GoogleService-Info-Alpha.plist,
GoogleService-Info-Beta.plist,
GoogleService-Info-Release.plist
  1. Add new Run Script Phase at last (Xcode: Target -> Build Phases -> "+" button).

  2. Use script below to copy .plist file for given environment to the build directory.

script:

RESOURCE_PATH=${SRCROOT}/${PRODUCT_NAME}/GoogleServiceInfoPlists/GoogleService-Info-$CONFIGURATION.plist

BUILD_APP_DIR=${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app

echo "Copying ${RESOURCE_PATH} to ${BUILD_APP_DIR}"
cp "${RESOURCE_PATH}" "${BUILD_APP_DIR}/GoogleService-Info.plist"

PS: You do not need to add the file to project. Just create a new folder in the main directory.

enter image description here

c-chavez
  • 7,237
  • 5
  • 35
  • 49
  • @Cleversou I get the issue `Could not locate configuration file: 'GoogleService-Info.plist'.` Are you using the new build settings? – smj2393 Sep 30 '19 at 16:47
  • @smj2393 try clicking in your disired .plist file > File Inspector > Target Membership > Check your main project so it can be bundled together in final output. – Ely Dantas Mar 03 '21 at 23:27
2

I put two files with the (same) name GoogleService-Info.plist into my project.

enter image description here

One is at the root and one is in a folder called 'staging', so as to avoid a naming conflict in the file system.

Include the plist in only one project each

Including one in one target and the other in another makes it so that each target has a unique plist file with the correct name.

KlimczakM
  • 12,576
  • 11
  • 64
  • 83
mevdev
  • 701
  • 8
  • 16
2

Actually there's a better solution.

You can replace Env variables(including User-Defined) manually using my swift script.

It takes two arguments: input and output paths. Goes through all input plist values recursively (if you need to can add dict keys to be processed too), and replaces all Env variables it founds. And writes to output path.

This is how you use it in your Run script phase:

/usr/bin/xcrun --sdk macosx swift "${PROJECT_DIR}/scripts/replacePlistEnvironmentVariables.swift"  "${PROJECT_DIR}/GoogleService-Info.plist" "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.app/GoogleService-Info.plist"
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220