iOS Dev Tools

Generating xcodeproj’s with Xcodegen

Get rid of unreadable xcodeproj files and say hello to readable project configuration files

Anurag Ajwani
Better Programming
Published in
6 min readFeb 23, 2022

--

Photo by Sven Mieke on Unsplash

Have you ever created pull requests(PR)/merge requests(MR) with changes to the xcodeproj file of your iOS app project?

Barely understandable diff

It is likely that a team of 2 more iOS devs to make changes to the xcodeproj files simultaneously.

For example, both may create new files. In such a case, you may create conflicting changes as both of you modify the same file. Additionally, xcodeproj files are not readable. Reviewing PRs with changes in the xcodeproj files is hard to follow and understand.

Merge conflict in xcodeproj
Merge conflict in xcodeproj

Is there any way we can get rid of xcodeproj files? Unfortunately, there is no easy way to get rid of these xcodeproj files for iOS app development.

However, we can easily generate xcodeproj files from more readable configuration files using Xcodegen.

Simple Xcodegen project.yml file

Xcodegen allows you to store your project configuration in a YAML formatted file. Xcodegen then generates the xcodeproj files based from the YAML file.

In this post, I will show you how to adopt a simple sample project to use Xcodegen. Then I will show how to add Swift Packages using Xcodegen. Finally, I’ll cover how to change build settings for your targets.

I have used Swift 5.5.2 and Xcode 13.2.1 for this article.

How to convert an iOS app project to use Xcodegen

In this section, we’ll start by installing Xcodegen.

We’ll then download an already existing app.

Finally, create an Xcodegen project configuration file, remove the existing xcodeproj file and generate the xcodeproj file using Xcodegen.

Here are the steps we are going to take:

  1. Install Xcodegen
  2. Download the starter pack
  3. Converting the project to use Xcodegen

Let’s get started!

1. Install Xcodegen

There are multiple ways to install Xcodegen. However, in this tutorial, we’ll be using Homebrew to install Xcodegen. Homebrew is a software package management system. It is a very popular tool for macOS. If you haven’t already installed it then go ahead and do so. Follow the installation instruction for Homebrew in its website brew.sh.

Homebrew installation instruction in brew.sh

Once Homebrew is installed let’s install Xcodegen. Run the following command in the terminal:

brew install xcodegen
Xcodegen installation in terminal

2. Download the starter pack

Let’s download an already existing iOS app project. Open a terminal and run the following commands:

cd $HOME
git clone https://github.com/anuragajwani/SaladMaker
cd SaladMaker
open -a Xcode SaladMaker.xcodeproj

3. Converting the project to use Xcodegen

Before we create the YAML file for Xcodegen let’s first analyse the project structure in the xcodeproj files.

First, we have a project named SaladMaker which contains a single target. The single target is an app for the iOS platform named also SaladMaker. The source files and assets for the project is under a directory also named SaladMaker. The minimum deployment target for this app is iOS 14.

Let’s create the YAML file for Xcodegen. In terminal run the following command with <YOUR_NAMESPACE> replaced:

cat > project.yml <<-EOF
name: SaladMaker
options:
bundleIdPrefix: com.<YOUR_NAMESPACE>
targets:
SaladMaker:
type: application
platform: iOS
deploymentTarget: "14.0"
sources:
- SaladMaker
EOF

Next, let’s delete SaladMaker.xcodeproj and run Xcodegen at the root of the project. Run the following command:

rm -rf SaladMaker.xcodeproj && xcodegen && open SaladMaker.xcodeproj
Running xcodegen command

Xcodegen will read the project.yml file and generate an xcodeproj based on the contents of the project.yml.

Let’s breakdown the contents of the project.yml. The name property is the project name. The options property applies configuration setting across the whole project. In this case, all targets identifier will be prefixed with com.<YOUR_NAMESPACE> (you can change here to own identifier). By default, Xcodegen will generate the Bundle Identifier to bundle prefix + target name (i.e. com.anuragajwani.SaladMaker).

Next, we have the targets property. This should be self explanatory. All targets will be specified under this property. We have our SaladMaker target which of type application for the iOS platform. We set the minimum deployment target to 14.0 and set the source files and assets by specifying the sources property.

Xcodegen allows for lots of customisation and configuration. Check out the full specification for the YML file.

That’s it! We’ve gone from a complicated xcodeproj file of over 350 lines of code over multiple files to 10 lines of code.

project.yml vs xcodeproj

Remember to tell git to ignore the xcodeproj files once you ready to use Xcodegen. I won’t be covering how to do that as git is out of scope for this article.

Additionally, all members should remember to run xcodegen command when changing branches.

How to add Swift Packages using Xcodegen

Most applications use open source libraries to aid or speed development. There are multiple ways of importing open source libraries. One of the most popular methods is to use a dependency manager. One of the most popular dependencies managers used in iOS development is Swift Package Manager.

In this section, I will show you how to import a popular open-source library used in iOS development: Alamofire.

Open project.yml at the top level after options: section add the following:

packages:
Alamofire:
url: https://github.com/Alamofire/Alamofire
majorVersion: 5.5.0

Above we added the package at a project level. However, we haven’t linked Alamofire to our SaladMaker app target. Let’s do that next. Under the SaladMaker target add the following:

dependencies:
- package: Alamofire

Your project.yml should look like the following:

name: SaladMaker
options:
bundleIdPrefix: com.anuragajwani
packages:
Alamofire:
url:
https://github.com/Alamofire/Alamofire
majorVersion: 5.5.0

targets:
SaladMaker:
type: application
platform: iOS
deploymentTarget: "14.0"
sources:
- SaladMaker
dependencies:
- package: Alamofire

Next, run xcodegen and then open SaladMaker.xcodeproj in Xcode. In terminal run the following commands:

xcodegen && open SaladMaker.xcodeproj
Added Alamofire as a dependency.

That’s it, we’re ready to use Alamofire in SaladMaker.

How to change build settings

By default, Xcodegen will set the xcodeproj default build settings or not specify it at all and allow Xcode to set the default.

However, in some cases, we might want to tweak build settings based on our app-specific needs. Xcodegen allows us to specify any build settings that you want to set for a target. Let’s say we want to disable bitcode for our SaladMaker app. Open project.yml and under the SaladMaker target add the following:

settings:
ENABLE_BITCODE: NO

Your project.yml should now look like the following:

name: SaladMaker
options:
bundleIdPrefix: com.anuragajwani
packages:
Alamofire:
url: https://github.com/Alamofire/Alamofire
majorVersion: 5.5.0
targets:
SaladMaker:
settings:
ENABLE_BITCODE: NO

type: application
platform: iOS
deploymentTarget: "14.0"
sources:
- SaladMaker
dependencies:
- package: Alamofire

Once again run xcodegen command to generate a new xcodeproj:

xcodegen && open SaladMaker.xcodeproj

See the changes in action:

before and after setting bitcode setting in project.yml

Summary

  • Xcodegen simplifies complicated to read xcodeproj files in project configuration YAML files.
  • Pull Requests/Merge Request are easier to read and follow
  • Conflicts in the project.yml are easier to resolve

There is a lot you can configure of the project with Xcodegen. Make sure to checkout the specs.

Final Thoughts

Xcodeproj files have been around for a long while now. They haven’t got better over time. I don’t know whether Apple is working on replacing these for iOS apps and other application targets.

However, there are positive signs from Apple. For example, for Swift Packages, Apple ditched xcodeproj files in favour of a more readable Package.swift file. Xcode can read these files as project configuration files for packages.

For now, the tools like Xcodegen allows stepping away from xcodeproj files to a certain degree. Xcodegen is not the only tool out there. I will be covering other tools and comparing these in the future.

Want to Connect?For more on iOS development follow me on Twitter.

--

--

Senior iOS Engineer at Travelperk. 7+ years experience with iOS and Swift. Blogging my knowledge and experience.