When developing iOS apps, managing sensitive configuration data like API keys and server URLs across different environments—such as development, staging, and production—can be a tricky task. These data must be kept secure, yet easily accessible during the build process.
This blog will show you how to streamline the management of sensitive data using .xcconfig
files and environment variables, both in your local development setup and continuous integration (CI) pipelines, ensuring a more secure and efficient workflow.
Overview
The solution involves creating .xcconfig
files for each environment, with placeholder values for sensitive data. These placeholder values are then replaced with real values from environment variables at build time.
For example, a ConfigDev.xcconfig
file could look like this:
API_KEY = API_KEY_PLACEHOLDER
SDK_LICENSE_KEY = SDK_LICENSE_KEY_PLACEHOLDER
During the build process, the API_KEY_PLACEHOLDER
is replaced with the actual API key specific to the development environment.
Local Setup
Step 1
Create a shell script like setup_env.sh
and place it in your project, for example, under the Scripts/EnvSetup
directory. Here is the script gist: Link
Step 2
Run the setup_env.sh
script to create the required .env
and .local.xcconfig
files.
sh setup_env.sh
This will generate .env.dev
, .env.stage
, and .env.prod
files, as well as corresponding .local.xcconfig
files in the Configs
directory.
Step 3
Open each .env
file and populate them with the appropriate values for each corresponding environment variable.
Step 4
Before building your project in Xcode, run the update_xcconfig_from_env.sh
script to substitute the placeholders in the .xcconfig
files with values from the corresponding .env
file.
Here is the update_xcconfig_from_env.sh
gist: Link
sh update_xcconfig_from_env.sh dev
Replace dev with stage or prod as needed.
Step 5
Keep in mind that the .env
and .local.xcconfig
files should not be committed to version control, so make sure to add them to your .gitignore
file. The project's build settings are set to use the .local.xcconfig
files, so ensure you're always working in debug mode.
CI Setup
In your CI system, instead of using .env
files, set up environment variables with the same names and values.
Before building the project, run the same update_xcconfig_from_ci_variables.sh
script to replace the placeholders in the .xcconfig
files with the values from the environment variables.
Script gist: Link
Benefits
This solution has several benefits:
- Sensitive data is not exposed in version control.
- It’s easy to manage configuration settings for different environments.
- It’s easy to update configuration settings without modifying the source code.
Bonus
For an easy and robust way to use.xcconfig
variables, I created a property wrapper named @XCConfigValue. Check it out here
The usage should look like this:
enum Environment {
@XCConfigValue(key: "API_BASE_URL")
static var baseUrl: String
@XCConfigValue(key: "SUBSCRIBE_LIMIT")
static var subscribeLimit: Int
}
Conclusion
Managing sensitive data across multiple environments in iOS projects can be challenging, but using .xcconfig
and .env
files provides a secure and flexible solution. By keeping sensitive information out of version control and streamlining the configuration process for both local development and CI systems, you ensure your app stays secure while maintaining an efficient workflow.
At Povio, we're experts in building secure, high-performance iOS apps. If you're looking for help with your next project or need guidance on best practices for managing sensitive data, reach out to us—we’re here to help you take your app development to the next level.