Creating Custom Xcode Project Templates
2019 - 07 - 11
Posted by kharrison
I recently wanted to play with some projects that did not use a main Storyboard. Starting from the single view app template it soon gets tiring to clean things up and add the boilerplate to the app delegate to create the window. This seems like a good time to learn how to create my own custom Xcode project template. Here are my notes for future reference.
Where Are The Xcode Templates
The built-in file and project templates are in the Xcode application bundle. Right-click on the Xcode app in the
/Applications folder and show package contents. The iOS templates are in sub-folders here:
Contents/Developer/Platforms/iPhoneOS.platform/ Developer/Library/Xcode/Templates/Project Templates/iOS
They make use of a number of shared base templates stored here:
You add your own templates by placing them in the folder:
I followed Apple’s direction and created sub-folders for the file and project templates:
$ mkdir -p ~/Library/Developer/Xcode/Templates/File\ Templates $ mkdir -p ~/Library/Developer/Xcode/Templates/Project\ Templates
How Do They Work
I cannot find any official Apple guides on how the templates work (some useful links at the end of this post). The easiest way seems to be to start from one of the built-in templates. I am going to use the single view application iOS template which is in a folder named
Single View App.xctemplate. It has just four files:
Main.storyboard- the storyboard with the initial view controller.
TemplateIcon.png- 48x48 icon
TemplateIcon@2x.png- 96x96 icon
TemplateInfo.plist- the configuration file for the template.
The interesting file is the
TemplateInfo.plist file. Here is how it looks at the top level:
Xcode.Xcode3.ProjectTemplateUnitKind for project templates.
A unique identifier for this template. Used when other templates inherit from this template.
The template system allows you to inherit from and override other templates. The
Ancestors field is an array of identifiers for templates that this template inherits from. The single view application template has two entries:
com.apple.dt.unit.storyboardApplication- adds the
UIMainStoryboardFilekey to the
com.apple.dt.unit.coreDataCocoaTouchApplication- adds the Core Data boilerplate to the app delegate if you select the checkbox
The storyboard and core data templates these identifiers reference both inherit from a Cocoa Touch Application Base template:
com.apple.dt.unit.cocoaTouchApplicationBase- adds unit test options, the application delegate boilerplate code and some
This template inherits from a number of others including an iOS App Base template to build a complex setup that takes some unpicking.
YES for Xcode to show the template. If missing Xcode treats the template as an abstract base template that other templates will inherit from.
A text description that Xcode used to display when browsing the templates. Xcode 9 does not seem to show it.
Set to override the default alphabetical sort order in the template browser.
An array of items to create in the new project. These can be code snippets, project and build settings or whole files. The value of each item is often an identifier to a definition stored in the
Definitions section of this template or an inherited template.
A dictionary of definitions for the items in
Nodes. You can override a defintion from a previous template. You can include an external file using a path dictionary. This is how the template adds the main storyboard file:
Options allow for user input to customize the template. The language choice between Swift and Objective-C is a menu with two choices listed in a
The language choice determines which set of
Nodes Xcode adds to the project. In this case it builds the Swift or Objective-C versions of the
ViewController class. The
Unit dictionary can also contain
Definitions. You can use any of the Xcode placeholder strings (
___FILEBASENAME___) in the values. Xcode replaces them when creating the project.
Creating A New Project Template
My aim is to create a new version of the single view application template that manually creates the window and root view hierarchies without using a main Storyboard.
To get started create a folder under “Project Templates” to store the template. The folder name shows up as the section name in the Xcode template browser.
$ mkdir -p ~/Library/Developer/Xcode/Templates/Project\ Templates/Personal
Then copy the single view app template to have a starting point:
$ APP_TEMPLATES='/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates/Project Templates/iOS/Application' $ cd ~/Library/Developer/Xcode/Templates/Project\ Templates/Personal/ $ cp -r "$APP_TEMPLATES/Single View App.xctemplate" "Manual Single View App.xctemplate"
To make changes to the template we need to edit the
TemplateInfo.plist file. Double-click to open it in Xcode or your favourite plist editor.
Change The Identifier
The first thing to do is change the identifier to something unique. I used
com.useyourloaf.dt.unit.manual.singleViewApplication. I also updated the description.
Remove The Storyboard
I do not want this template to inherit from the storyboard template so I replaced it in the ancestors array with the Cocoa Touch Application Base template that it inherits from. I left the Core Data template:
<key>Ancestors</key> <array> <string>com.apple.dt.unit.cocoaTouchApplicationBase</string> <string>com.apple.dt.unit.coreDataCocoaTouchApplication</string> </array>
I also removed the storyboard definition entry and the
The Root View Controller
I added an item to the
Options to allow the user to choose the name of the root view controller when creating the project:
It defaults to
RootViewController. We can use the value elsewhere in the template with the variable placeholder
To create the root view controller class I modified the nodes for both language choices. This was mostly just replacing the hardcoded
ViewController with our new
Note that for the Objective-C version of the project I also include the view controller header file in the app delegate as we will need it shortly:
Change the App Delegate
The app delegate needs code to create the main window and root view controller. For some extra polish I decided to also add a user option to embed the view controller in a navigation controller. Note the
checkbox and defaults to
false (a string not a boolean):
Units dictionary for a checkbox has entries for
false. If you only wanted to add items for the
true case you can omit
false. In my case I am going to generare a different app delegate in both cases. I also need to make the result dependent on the language choice. The
false case looks like this with an item for Objective-C and an item for Swift:
Note how each item has the
RequiredOptions key set to the relevant language choice. To add the code snippet to the app delegate we override the definition from the Cocoa Touch App Base template for the body for the
The Xcode plist editor is clumsy when handling multi-line values. I found it easier to cut and paste the code into the field. The swift version is as follows:
window = UIWindow(frame: UIScreen.main.bounds) window?.backgroundColor = .white window?.rootViewController = ___VARIABLE_rootClassName___() window?.makeKeyAndVisible()
Note that we use the variable placeholder for the name of the root view controller class. The
true version embeds the view controller in a navigation controller:
window = UIWindow(frame: UIScreen.main.bounds) window?.backgroundColor = .white let rootViewController = ___VARIABLE_rootClassName___() let navigationController = UINavigationController(rootViewController: rootViewController) window?.rootViewController = navigationController window?.makeKeyAndVisible()
Using The Template
There is nothing more to do to activate the template. When creating a new Xcode project the template should appear in the browser:
The project settings includes our user options to change the class name for the root view controller and the checkbox to embed it in a navigation controller:
These options are persistent so they remember the last value used (set the
NotPersisted boolean key to
YES for the item to change that).
Getting The Template
The template is available in an Xcode Templates repository on GitHub here:
To install it just copy the
Personal folder into the
~/Library/Developer/Xcode/Templates/Project Templates folder.