Generating Xcodeproj’s with Tuist | by Anurag Ajwani | Mar, 2022

iOS Dev Instruments

Do away with unreadable xcodeproj information and say howdy to readable venture configuration information

Picture by Hanna Morris on Unsplash

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

It’s possible {that a} crew of two extra iOS devs to make adjustments to the xcodeproj information concurrently.

For instance, each might create new information. In such a case, it’s possible you’ll create conflicting adjustments as each of you modify the identical file. Moreover, xcodeproj information should not readable. Reviewing PRs with adjustments within the xcodeproj information is difficult to observe and perceive.

Git conflicts in xcodeproj after file creations in separate branches
The conflicting traces

Is there any approach we will do away with xcodeproj information? Sadly, there is no such thing as a simple option to do away with these xcodeproj information for iOS app improvement.

Nevertheless, we will simply generate xcodeproj information from extra readable configuration information utilizing Tuist.

Venture.swift instance

Tuist permits you to retailer your venture configuration in a Swift in a file named Venture.swift. Tuist then generates the xcodeproj information primarily based on the Swift code in Venture.swift.

That is just like Swift Package Manager’s Package.swift.

On this put up, I’ll present you easy methods to undertake a pattern venture to make use of Tuist. Then I’ll present easy methods to add Swift Packages to an iOS app goal utilizing Tuist. Subsequent, I’ll present you easy methods to cache modules utilizing Tuist. Lastly I’ll cowl easy methods to change construct settings.

I’ve used Swift 5.6 and Xcode 13.3 for this text.

On this part, we’ll begin by putting in Tuist.

We’ll then obtain an already current app.

Lastly, create an Tuist venture configuration file, take away the prevailing xcodeproj file and generate the xcodeproj file utilizing Tuist.

Listed below are the steps we’re going to take:

  1. Set up Tuist
  2. Obtain the starter pack
  3. Changing the venture to make use of Tuist

Let’s get began!

1. Set up Tuist

There’s solely option to set up Tuist (on the time of writing). Open terminal and run the next command:

curl -Ls | bash
Tuist set up

2. Obtain the starter pack

Let’s obtain an already current iOS app venture. Open a terminal and run the next instructions:

cd $HOME
curl -o -L -s
unzip -q
cd tuist-tut-starter
open -a Xcode SaladMaker.xcodeproj

Run the app to see it in motion.

3. Changing the venture to make use of Tuist

To ensure that us to generate the xcodeproj information we should declare the venture construction, it’s targets and configuration in file named Venture.swift. First let’s check out the venture targets and its configuration inside the present xcodeproj:

Xcode venture construction

The SaladMaker venture is comprised by 2 targets:

  1. SaladMaker iOS app
  2. SayHelloKit framework

The supply code for SaladMaker sits inside a listing named SaladMaker. The supply code for SayHelloKit sits inside a listing named SayHelloKit. Each of those targets help iOS 14 and above. SayHelloKit framework is consumed by the SaladMaker app.

Subsequent let’s create the Venture.swift file. In terminal run the next command:

cat > Venture.swift <<-EOF
import ProjectDescription
let venture = Venture(
identify: "SaladMaker",
organizationName: "com.anuragajwani",
targets: [
name: "SaladMaker",
platform: .iOS,
product: .app,
bundleId: "com.anuragajwani.SaladMaker",
deploymentTarget: .iOS(targetVersion: "14.0", devices: .iphone),
infoPlist: "SaladMaker/Info.plist",
sources: ["SaladMaker/**"],
sources: ["SaladMaker/Assets.xcassets/"],
dependencies: [.target(name: "SayHelloKit")]
identify: "SayHelloKit",
platform: .iOS,
product: .framework,
bundleId: "com.anuragajwani.SayHelloKit",
deploymentTarget: .iOS(targetVersion: "14.0", gadgets: .iphone),
sources: ["SayHelloKit/**"],
settings: .settings(base: ["GENERATE_INFOPLIST_FILE": "YES"])

Above we’ve create a venture named SaladMaker with 2 targets; the SaladMaker iOS app and the SayHelloKit framework. We’ve got specified every:

  • goal identify
  • bundle identifier
  • the platform it serves
  • the product sort
  • the place its supply code lies
  • the place its property lies (pictures, textual content information and different non-code information)

Notice we’ve additionally declared a construct setting for the framework goal. Don’t fear about this, we’ll come again to this later within the “Methods to change construct settings” part of this put up. Moreover we’ve declared that the SaladMaker app is determined by SayHelloKit:

dependencies: [.target(name: "SayHelloKit")]

Subsequent, let’s delete SaladMaker.xcodeproj and inform Tuist to generate the xcodeproj information for the venture. Run the next command:

rm -rf SaladMaker.xcodeproj && tuist generate

Tuist will robotically open Xcode for you. Run the app and it ought to run simply because it did earlier than.

That’s it we are actually producing unreadable xcodeproj over 500 traces from 31 traces of Swift code!

Evaluating Venture.swift vs Xcodeproj information

Most functions use open supply libraries to help or pace improvement. There are a number of methods of importing open supply libraries. One of the crucial fashionable strategies is to make use of a dependency supervisor. One of the crucial fashionable dependencies managers utilized in iOS improvement is Swift Package Manager.

On this part, I’ll present you easy methods to import a well-liked open-source library utilized in iOS improvement: Alamofire.

In terminal run the next instructions on the root of the venture:

mkdir Tuist && cd Tuist
cat > Dependencies.swift <<-EOF
import ProjectDescription
let dependencies = Dependencies(
swiftPackageManager: [
.remote(url: "", requirement: .upToNextMajor(from: "5.0.0")),
platforms: [.iOS]

To ensure that us to make use of third celebration exterior dependencies in our venture utilizing Tuist we should declare these dependencies in file named Dependencies.swift underneath a listing named Tuist on the root of the venture.

Notice the dependencies declared in Dependencies.swift should help Swift Package Manager.

We are able to now inform Tuist to fetch these exterior dependencies by working the next command on the root of the venture:

tuist fetch
Fetching exterior dependencies

We haven’t but instructed Tuist that we need to use Alamofire within the SaladMaker app. Let’s try this subsequent. Open Venture.swift and alter the SaladMaker dependencies to the next:

dependencies: [
.target(name: "SayHelloKit"),
.external(name: "Alamofire")

Subsequent let’s inform Tuist to re-generate xcodeproj information. Run the next command in terminal:

tuist generate

We are actually able to devour Alamofire inside the SaladMaker app:

Linked frameworks and libraries of SaladMaker

When growing iOS apps Xcode will compile all the supply code as a part of the construct course of together with its third celebration dependencies. Within the SaladMaker app for instance we began utilizing Alamofire. It’s unlikely that we are going to ever want to alter Alamofire code. But Xcode will hold constructing Alamofire over and over many occasions by way of the event course of.

Moreover we may fit on sure options that don’t require engaged on our SayHelloKit module. Once more Xcode will construct this over and over many occasions.

What if we may it construct it as soon as and reuse the constructed or compiled kind from that time onwards for our builds throughout improvement? In different phrases: can we cache modules?

On this part we’ll take a look at:

  1. Methods to cache exterior third celebration dependencies
  2. Methods to cache venture modules

1. Methods to cache exterior third celebration dependencies

We are able to cache Alamofire and different third celebration dependencies (declared in Dependencies.swift) and use a compiled type of these in the course of the construct means of our app throughout improvement. To take action run the next command:

tuist cache heat --dependencies-only
Caching exterior dependencies

Tuist will construct and cache Alamofire. Subsequent let’s we have to inform Tuist to re-generate the venture and it’ll robotically use the cached Alamofire. Run the next command:

tuist generate
Utilizing cached exterior dependencies

2. Methods to cache venture modules

We are able to additionally cache our personal modules. If we all know we received’t be making any adjustments to sure modules it’s price to cache these too. This may help to hurry the event means of the function we’re at the moment constructing. To cache SayHelloKit run the next command:

tuist cache heat SayHelloKit
Caching SayHelloKit

If we need to solely must work on the SaladMaker goal then we should inform Tuist that we solely need to develop that focus on:

tuist generate SaladMaker

Tuist will then substitute its dependencies with cached variations of such dependencies.

Utilizing cached SayHelloKit

By default, Tuist will set the xcodeproj default construct settings or not specify it in any respect and permit Xcode to set the default.

Nevertheless, in some circumstances, we would need to tweak construct settings primarily based on our app-specific wants. Tuist permits us to specify any construct settings that you simply need to set for a goal. Let’s say we need to disable bitcode for our SaladMaker app. Open Venture.swift and on the finish of the SaladMaker app goal declaration add the next line:

dependencies: [
.target(name: "SayHelloKit"),
.external(name: "Alamofire")
settings: .settings(base: ["ENABLE_BITCODE": "NO"])

As soon as once more let’s inform Tuist to re-generate the xcodeproj information:

tuist generate

See the adjustments in motion:

Disabled Bitcode on SaladMaker

More Posts