When you enter the realm of the project editor's "Build Settings" tab, you're met with an extensive array of configuration options scattered across projects, targets, and configurations. Fortunately, there is a more efficient method for handling this labyrinthine configuration that doesn't involve navigating through a maze of tabs and disclosure arrows. Xcode build configuration files, often referred to by their .xcconfig extension, offer a means to declare and manage build settings for your application independently of Xcode.
In essence, each configuration file comprises a series of key-value assignments following this syntax:
MERCHANT_ID=merchantId
All environmental variables defined in the JSON files are similarly mirrored within this file.
Limitations
Xcconfig files interpret the sequence // as a comment delimiter, irrespective of whether it's enclosed in quotation marks. The easiest thing to do when we want to pass a specific path in our env variable is to simply exclude the scheme and prefix URLs with https:// in our code instead.
Starting with Flutter 3.16, handling dart-define for iOS requires additional setup. The environment variables passed via dart-define are Base64-encoded, and this necessitates decoding them manually during the build process to make them accessible in the iOS native environment. It’s mandatory to edit the scheme of the runner to add the following on the pre-actions build script:
function entry_decode() { echo "${*}" | base64 --decode; }
IFS=',' read -r -a define_items <<< "$DART_DEFINES"
for index in "${!define_items[@]}"
do
define_items[$index]=$(entry_decode "${define_items[$index]}");
done
printf "%s\n" "${define_items[@]}" > ${SRCROOT}/Flutter/Environment.xcconfig
What the Script Does:
Decode Base64 Variables: It defines a function entry_decode to decode Base64 strings.
Process DART_DEFINES: Reads the DART_DEFINES environment variable (a comma-separated list of encoded key-value pairs).
Transform into Key-Value Pairs: Decodes each pair and writes them into the Environment.xcconfig file.
The next step is to add new line with the following in both Debug.xcconfig & Release.xcconfig :
#include "Environment.xcconfig"
How to Add the Script
Open the Xcode Project:
Edit the Scheme:
Add Pre-actions:
In the scheme editor, go to Build > Pre-actions.
Click the + button to add a new pre-action script.
Set the Provide build settings from option to Runner.
Paste the script into the text field.
Interesting case
Let's assume we need access to our env variable in AppDelegate.swift. We also know that build settings defined by the Xcode project file, xcconfig files, and environment variables are only available at build time. The solution to this problem is to use the Info.plist file. Info.plist file is compiled according to the build settings provided and copied into the resulting app bundle. Therefore, by adding references to specific env variables, e.g. $(MERCHANT_ID), we can access the values for those settings through the infoDictionary property of Foundation’s Bundle API.
Info.plist
<key>MerchantId</key>
<string>$(MERCHANT_ID)</string>
AppDelegate.swift
guard let brazeApiKey = Bundle.main.object(forInfoDictionaryKey: "MerchantId") as? String
else {
throw NSError(
domain: "Merchant id error", code: 1,
userInfo: ["reason": "Problem with getting merchant id"])
}