18. Aug 2021
iOSXcode project templates and where to find them
Have you ever wondered why creating new projects is taking such a long time? You don't have to anymore. If you want to set up a new project template, which you can use for many more projects, I’ve prepared a quick startup guide on how to do it. So let’s dive in.
If you ever had the honor to set up a project for development, you know it takes a long time to do if you start from scratch. If you have any projects that you want to get inspired by, it takes a bit less time since you can copy and paste some basic architecture and extensions you will likely use, but it still takes quite a while. Especially if you try to keep some consistent project structure and naming in your company. That's why we've put together a series of guidelines on how to set up your Xcode templates. After reading this article, you can continue on how to auto-configure a project and how to automate the configuration of swiftlint and swiftgen.
This tool comes in handy since it takes away a lot of the human factor out of the equation.
If only there were some tools to make your job easier. Well, I am here to show you that you might be in luck.
Project templates are quite a powerful tool.
The primary use is to link files, create folders, in a specific order, with a dynamic file header. In this article, I will show you how to set up your project hierarchy using project templates.
There are file templates that allow you to create files in an existing project, and there are project templates for creating entire projects from scratch.
The differences between file templates and project templates and basic information about the Xcode templates are in my previous article on Medium. So make sure you read that one first.
To sum up, you need to navigate to this folder (if not existent, create it): /Users/$USER_NAME/Library/Developer/Xcode/Templates/Project Templates everything within the templates folder is going to be listed in your Project creation wizard when as long as it is in a valid format.
Here is how the project template that I’ve been working on looks. The path is just a matter of organization, but the important part is that the file has: the .xctemplate suffix, the Icon files, and the TemplateInfo.plist.
For the icons, you can choose any png and a copy of it with the suffix @2x.png.
The plist file is where the magic happens. Put all the files you want to use in your project template. Unless you link the file within the plist file, they do not show in the created project. The order in the folder is irrelevant since the plist file is going to set the final order.
To view the plist file, I am using Atom since it highlights the XML syntax of the file. If you are comfortable using another tool, it is up to you.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Kind</key>
<string>Xcode.Xcode3.ProjectTemplateUnitKind</string>
<key>Identifier</key>
<string>com.apple.dt.unit.singleViewApplication</string>
<key>Ancestors</key>
<array>
<string>com.apple.dt.unit.applicationBase</string>
<string>com.apple.dt.unit.iosBase</string>
</array>
<key>Concrete</key>
<true/>
<key>Definitions</key>
<dict>
<key>Application/AppDelegate.swift</key>
<dict>
<key>Path</key>
<string>Application/AppDelegate.swift</string>
<key>Group</key>
<array>
<string>Application</string>
</array>
</dict>
<key>Models/Response/SampleResponse.swift</key>
<dict>
<key>Path</key>
<string>Models/Response/SampleResponse.swift</string>
<key>Group</key>
<array>
<string>Models</string>
<string>Response</string>
</array>
</dict>
<key>Models/Request/SampleRequest.swift</key>
<dict>
<key>Path</key>
<string>Models/Request/SampleRequest.swift</string>
<key>Group</key>
<array>
<string>Models</string>
<string>Request</string>
</array>
</dict>
<key>Managers/Dependency/DependencyContainer.swift</key>
<dict>
<key>Path</key>
<string>Managers/Dependency/DependencyContainer.swift</string>
<key>Group</key>
<array>
<string>Managers</string>
<string>Dependency</string>
</array>
</dict>
<key>Managers/Request/RequestManager.swift</key>
<dict>
<key>Path</key>
<string>Managers/Request/RequestManager.swift</string>
<key>Group</key>
<array>
<string>Managers</string>
<string>Request</string>
</array>
</dict>
<key>Managers/Request/RequestManagerType.swift</key>
<dict>
<key>Path</key>
<string>Managers/Request/RequestManagerType.swift</string>
<key>Group</key>
<array>
<string>Managers</string>
<string>Request</string>
</array>
</dict>
<key>Managers/Request/Endpoint.swift</key>
<dict>
<key>Path</key>
<string>Managers/Request/Endpoint.swift</string>
<key>Group</key>
<array>
<string>Managers</string>
<string>Request</string>
</array>
</dict>
<key>Coordinators/Coordinator.swift</key>
<dict>
<key>Path</key>
<string>Coordinators/Coordinator.swift</string>
<key>Group</key>
<string>Coordinators</string>
</dict>
<key>Coordinators/AppCoordinator.swift</key>
<dict>
<key>Path</key>
<string>Coordinators/AppCoordinator.swift</string>
<key>Group</key>
<string>Coordinators</string>
</dict>
<key>Screens/SampleController/SampleViewController.swift</key>
<dict>
<key>Path</key>
<string>Screens/SampleController/SampleViewController.swift</string>
<key>Group</key>
<array>
<string>Screens</string>
<string>SampleController</string>
</array>
</dict>
<key>Views/SampleView/SampleView.swift</key>
<dict>
<key>Path</key>
<string>Views/SampleView/SampleView.swift</string>
<key>Group</key>
<array>
<string>Views</string>
<string>SampleView</string>
</array>
</dict>
<key>Resources/Assets.xcassets</key>
<dict>
<key>Path</key>
<string>Resources/Assets.xcassets</string>
<key>Group</key>
<array>
<string>Resources</string>
</array>
</dict>
<key>Resources/Colors.xcassets</key>
<dict>
<key>Path</key>
<string>Resources/Colors.xcassets</string>
<key>Group</key>
<array>
<string>Resources</string>
</array>
</dict>
</dict>
<key>Nodes</key>
<array>
<string>Application/AppDelegate.swift</string>
<string>Models/Response/SampleResponse.swift</string>
<string>Models/Request/SampleRequest.swift</string>
<string>Managers/Dependency/DependencyContainer.swift</string>
<string>Managers/Request/RequestManager.swift</string>
<string>Managers/Request/RequestManagerType.swift</string>
<string>Managers/Request/Endpoint.swift</string>
<string>Coordinators/Coordinator.swift</string>
<string>Coordinators/AppCoordinator.swift</string>
<string>Screens/SampleController/SampleViewController.swift</string>
<string>Views/SampleView/SampleView.swift</string>
<string>Resources/Colors.xcassets</string>
<string>Resources/Assets.xcassets</string>
<string>Info.plist:UIMainStoryboardFile</string>
<string>Info.plist:UIApplicationSceneManifest:UISceneStoryboardFile</string>
</array>
</dict>
Everything up to definitions you can copy/paste, since it’s static for our simple template. Regardless I’ll give you a quick sum-up anyway:
Kind: states that it’s a project template opposite to a file template which is the only other option.
Identifier: This is the identifier of the template that should be unique and can be referred to from other templates to import it
Concrete: States if this template should be visible. You can hide it if you only use it as a part of other templates.
Ancestors: lists the ids of other templates from which this template inherits.
Definitions: States files that you’re going to refer to later on below in the nodes. You need to put all the files that you want to see in your projects in the definitions. The Path in the definition <dict> states where the desired file is located relative to your template directory. The Group in the definition <dict> states how the folder hierarchy will be after you create a new project using the template.
Nodes: States which files will the template create. If not stated otherwise, the order in which you write them will be the order in which your file hierarchy will be.
Hit save and try to create a folder using this template. You should see your custom templates at the very bottom of the project creation options in a separate section (The naming reflects your folder structure after the Templates folder)