avatar
Published on

Accessing Environment Variables in Swift

Authors
  • avatar
    Name
    Mick MacCallum
    Twitter
    @0x7fs

Environment variables are dynamic values that exist outside your application's scope, providing a flexible way to configure and influence your app's behavior. In Swift, you can access these variables using the ProcessInfo class, making it easy to manage different configurations for development, testing, and production environments.

Basic Environment Variable Access

To retrieve the value of an environment variable in Swift, use the environment property of ProcessInfo.processInfo:

if let value = ProcessInfo.processInfo.environment["YOUR_VARIABLE_NAME"] {
    print("The value is: \(value)")
} else {
    print("Environment variable not set.")
}

This simple approach allows you to fetch and utilize environment variable values within your Swift application. The environment property returns a dictionary containing all environment variables available to your process.

Common Use Cases

Configuration Management

Environment variables are perfect for managing different configurations across environments. For example, you might have different server URLs for development and production:

let serverURL = ProcessInfo.processInfo.environment["SERVER_URL"] ?? "https://api.default.com"
let apiVersion = ProcessInfo.processInfo.environment["API_VERSION"] ?? "v1"

API Keys and Secrets

Securing sensitive information like API keys is crucial. Store them as environment variables to keep them separate from your codebase:

let apiKey = ProcessInfo.processInfo.environment["API_KEY"] ?? ""
let secretToken = ProcessInfo.processInfo.environment["SECRET_TOKEN"] ?? ""

Feature Toggles

Use environment variables for feature toggles, enabling controlled feature rollouts and A/B testing:

let isNewFeatureEnabled = ProcessInfo.processInfo.environment["NEW_FEATURE_ENABLED"] == "true"
let debugMode = ProcessInfo.processInfo.environment["DEBUG_MODE"] == "true"

Setting Environment Variables in Xcode

Using Xcode Schemes

The most common way to set environment variables for your app is through Xcode schemes:

  1. Open your Xcode project
  2. Go to ProductSchemeEdit Scheme
  3. Select Run from the left sidebar
  4. Click on the Arguments tab
  5. In the Environment Variables section, click the + button
  6. Add your variable name and value

This approach is perfect for development and testing, as the variables are only available when running through Xcode.

Using xcodebuild Command Line

For CI/CD pipelines or command-line builds, you can set environment variables using xcodebuild:

Method 1: Set environment variables before running xcodebuild

export API_KEY=your_api_key_here
export SERVER_URL=https://api.example.com
xcodebuild -scheme YourScheme -configuration Debug build

Method 2: Set environment variables inline with xcodebuild

API_KEY=your_api_key_here SERVER_URL=https://api.example.com xcodebuild -scheme YourScheme build

Method 3: Use a custom build configuration

xcodebuild -scheme YourScheme -configuration Debug \
  -destination 'platform=iOS Simulator,name=iPhone 15' \
  -xcconfig MyConfig.xcconfig

Using .xcconfig Files

Create a .xcconfig file to manage build settings and preprocessor macros (note: these are primarily for build-time configuration, not runtime environment variables):

// Development.xcconfig
API_KEY = dev_api_key_123
SERVER_URL = https://dev-api.example.com
DEBUG_MODE = true

Then reference this file in your Xcode project settings or use it with xcodebuild:

xcodebuild -xcconfig Development.xcconfig -scheme YourScheme build

Important Note: Variables defined in .xcconfig files are typically build settings and preprocessor macros, not runtime environment variables. To access them in your Swift code, you'll need to define them as preprocessor macros in your build settings.

Best Practices

Provide Default Values

Always provide default values to prevent crashes if an environment variable is not set:

let timeout = ProcessInfo.processInfo.environment["REQUEST_TIMEOUT"] ?? "30"
let maxRetries = ProcessInfo.processInfo.environment["MAX_RETRIES"] ?? "3"

Type Safety

Convert string values to appropriate types when needed:

let timeoutValue = Double(ProcessInfo.processInfo.environment["TIMEOUT"] ?? "30.0") ?? 30.0
let maxRetriesValue = Int(ProcessInfo.processInfo.environment["MAX_RETRIES"] ?? "3") ?? 3

Security Considerations

  • Never commit sensitive environment variables to version control
  • Use different values for different environments
  • Consider using a secure key management service for production secrets

Example: Complete Configuration Manager

Here's a practical example of a configuration manager that uses environment variables:

struct AppConfig {
    static let shared = AppConfig()
    
    let apiKey: String
    let serverURL: String
    let isDebugMode: Bool
    let timeout: TimeInterval
    
    private init() {
        self.apiKey = ProcessInfo.processInfo.environment["API_KEY"] ?? ""
        self.serverURL = ProcessInfo.processInfo.environment["SERVER_URL"] ?? "https://api.default.com"
        self.isDebugMode = ProcessInfo.processInfo.environment["DEBUG_MODE"] == "true"
        self.timeout = TimeInterval(ProcessInfo.processInfo.environment["TIMEOUT"] ?? "30.0") ?? 30.0
    }
}

// Usage
let config = AppConfig.shared
print("Server URL: \(config.serverURL)")
print("Debug mode: \(config.isDebugMode)")

Environment variables in Swift provide a robust mechanism for configuring and adapting your applications to different scenarios. By incorporating them into your development workflow, you can streamline configuration management, enhance security, and promote a more adaptable and scalable codebase.