Leveraging Xcodegen for Hassle-free iOS Development

mrasyadc

Muhammad Rasyad Caesarardhi

Posted on September 1, 2024

Leveraging Xcodegen for Hassle-free iOS Development

Why Use XcodeGen?

Managing Xcode project files manually can quickly become a cumbersome task, especially as projects grow in complexity. With multiple targets, configurations, and dependencies, it's easy for inconsistencies and errors to creep in. XcodeGen addresses these issues by automating the generation of Xcode project files from a configuration file, usually written in YAML or JSON.

Key Benefits:

  • Consistency Across Teams: XcodeGen ensures that every developer generates the same project structure, minimizing version control conflicts and reducing onboarding time for new team members.
  • Scalability and Maintainability: As projects evolve, XcodeGen simplifies managing multiple targets and build configurations, making it easier to scale and maintain the project over time.
  • Reducing Manual Work: By automating the project setup, XcodeGen eliminates the need for tedious manual configuration, reducing the risk of human error.

Current State

In many iOS development teams, managing the Xcode project file (.xcodeproj) manually is the norm. This approach has its drawbacks, particularly in larger teams or projects:

  • Merge Conflicts: The .xcodeproj file is notorious for generating merge conflicts in version control systems. These conflicts are often difficult to resolve and can lead to wasted time and frustration.
  • Inconsistent Configurations: When multiple developers manually manage project settings, inconsistencies can arise, leading to unexpected build issues or discrepancies between development environments.
  • Time-Consuming Processes: Setting up new targets, schemes, or configurations manually can be time-consuming, diverting focus from actual development work.

Our team experienced these issues firsthand. As the project grew, we found ourselves constantly dealing with frustrating conflicts in the .xcodeproj file. The merge conflicts were so frequent and disruptive that they started to slow down our progress significantly. This frustration led us to explore alternatives, and we finally decided to adopt XcodeGen mid-development. It was a game-changer, resolving our conflicts and making the project more manageable.

How Does It Improve Our Development Team?

XcodeGen significantly enhances team productivity and collaboration by addressing several common pain points in iOS development.

Improved Collaboration:

With a single source of truth for the project configuration, XcodeGen minimizes the chances of inconsistencies and conflicts. Team members can work more effectively, knowing that any changes to the project settings are controlled and predictable.

Easier Configuration Management:

Centralizing the project configuration in a project.yml file simplifies making global changes across the project. Whether adding a new target, modifying build settings, or managing dependencies, XcodeGen makes it easy to update and maintain the project.

How to Implement It?

First Configuration of XcodeGen

Getting started with XcodeGen is straightforward. Here’s a step-by-step guide to setting up your first configuration:

  1. Installation:

    • Install XcodeGen via Homebrew by running (Alternatively, download and install it from the official GitHub repository):
     brew install xcodegen
    
  2. Adding .gitignore:

    • Before configuring XcodeGen, ensure that you have a .gitignore file set up in your project. This is crucial to avoid committing the generated .xcodeproj file to your repository.
    • Add the following to your .gitignore:
     # Ignore Xcode project files
     *.xcworkspace/
     *.xcodeproj/
    
  3. Creating project.yml:

    • Create a new file named project.yml in the root of your project directory. This file will define the structure and settings of your Xcode project.
    • Here’s our implementation of project.yml file which defines four targets: App (an iOS application), PukPuk-Tests (a test suite and PukPukIntentsExtension and PukPukIntentsExtensionUI for Extensions (shortcut)
     name: PukPuk
     settings:
      MARKETING_VERSION: '1.0'
      CURRENT_PROJECT_VERSION: 1
     options:
      bundleIdPrefix: com.PukPuk
    
     targets:
      App:
       type: application
       platform: iOS
       sources: [PukPuk]
       resources: [Resources]
       settings:
        PRODUCT_BUNDLE_IDENTIFIER: com.PukPuk.App
        INFOPLIST_FILE: PukPuk/Info.plist
        GENERATE_INFOPLIST_FILE: true
        base:
         TARGETED_DEVICE_FAMILY: '1' # iPhone only
         SUPPORTED_INTERFACE_ORIENTATIONS: 'UIInterfaceOrientationPortrait' # Portrait only
    
      PukPuk-Tests:
       type: bundle.unit-test
       platform: iOS
       sources: [PukPuk-Tests]
       dependencies:
        - target: App
       settings:
        base:
         INFOPLIST_FILE: PukPuk/Info.plist
         GENERATE_INFOPLIST_FILE: true
         TEST_HOST: '$(BUILT_PRODUCTS_DIR)/App.app/App'
         BUNDLE_LOADER: '$(TEST_HOST)'
    
      PukPukIntentsExtension:
       type: app-extension
       platform: iOS
       sources: [PukPukIntentsExtension]
       settings:
        PRODUCT_BUNDLE_IDENTIFIER: com.PukPuk.AppIntentsExtension
        INFOPLIST_FILE: PukPukIntentsExtension/Info.plist
        GENERATE_INFOPLIST_FILE: true
       dependencies:
        - target: App
    
      PukPukIntentsExtensionUI:
       type: app-extension
       platform: iOS
       sources: [PukPukIntentsExtensionUI]
       settings:
        PRODUCT_BUNDLE_IDENTIFIER: com.PukPuk.AppIntentsExtensionUI
        INFOPLIST_FILE: PukPukIntentsExtensionUI/Info.plist
        GENERATE_INFOPLIST_FILE: true
       dependencies:
        - target: PukPukIntentsExtension
    
     schemes:
      PukPuk:
       build:
        targets:
         App: all
         PukPuk-Tests: all
         PukPukIntentsExtension: all
         PukPukIntentsExtensionUI: all
       test:
        targets:
         - name: PukPuk-Tests
           gatherCoverageData: true
    
  4. Generating the Xcode Project:

    • To generate the Xcode project based on the project.yml configuration., run:
     xcodegen generate
    
  5. Adding ci_post_clone.sh:

    • To ensure the project is correctly generated in your CI environment, create a ci_post_clone.sh script in a folder named ci_scripts:
     mkdir -p ci_scripts
     touch ci_scripts/ci_post_clone.sh
    
  • Add the following content to ci_post_clone.sh:

     #!/bin/bash
    
     # Exit immediately if a command exits with a non-zero status
     set -e
    
     # Print commands and their arguments as they are executed
     set -x
    
     # Install Homebrew if it's not already installed
     if ! command -v brew &>/dev/null; then
        echo "Homebrew not found. Installing Homebrew..."
        /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
     fi
    
     # Install xcodegen if it's not already installed
     if ! command -v xcodegen &>/dev/null; then
        echo "xcodegen not found. Installing xcodegen..."
        brew install xcodegen
     fi
    
     # Clean any previous builds or project files
     echo "Cleaning previous builds..."
     rm -rf ./build
     rm -rf ./DerivedData
     rm -rf ./YourProject.xcodeproj
    
     echo "Moving to the project directory..."
     cd ../
     # Generate the Xcode project using xcodegen
     echo "Generating Xcode project..."
     xcodegen generate
    
     # # Install CocoaPods dependencies if your project uses CocoaPods
     # if [ -f "Podfile" ]; then
     #  echo "Installing CocoaPods dependencies..."
     #  pod install
     # fi
    
     echo "Pre-build setup complete!"
    
  • Make sure to set the script as executable:

     chmod +x ci_scripts/ci_post_clone.sh
    
  • This script ensures that every time the CI pipeline runs, it installs XcodeGen and generates the project before building.

Conclusion

XcodeGen is a powerful tool for automating and streamlining iOS project management, offering significant benefits in terms of consistency, maintainability, and collaboration. By integrating XcodeGen into your development workflow, you can reduce manual work, minimize errors, and improve team productivity. Whether you're working on a small project or a large-scale app with multiple targets and configurations, XcodeGen is a must-have tool for modern iOS development.

💖 💪 🙅 🚩
mrasyadc
Muhammad Rasyad Caesarardhi

Posted on September 1, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related