Every experienced developer has a set of tools that he is used to and that he is comfortable working with. This can be the simplest setting of the environment, utilities for intermediate operations (for example, the API Postman testing assistant), libraries and snippets that have been tested by time and personally by the developer.
Also, many developers may have their own approach to the implementation of the chosen architecture. Therefore, it is very useful to have an application blank in your arsenal – a general skeleton (framework), to which you only remain to add new modules, screens and features. In this article, I will show you how to create your own application template in Xcode.
Where is the heart of the template
How often do you create applications and write the same code over and over again, creating the base of a future product? You declare base classes, make helpers, embed the architecture, create wrappers… At such moments, you want to have a tool that will allow you to instantly get a working application with a well-developed architecture and a written base for further development.
Such a tool exists, and we all use it all the time when we create a ‘Single View App’ in Xcode.
My search for instructions from Apple on how to create your own templates was fruitless. However, Xcode allows you to add the generation of your own files with already prepared code, and it’s a tea party.
For an easy start, let’s take the well-known Single View App. Go to Finder, press the key combination Cmd + Shift + G (jump to folder) and specify the path:
We find “Single View App.xctemplate” there and copy it, for example, to the desktop.
As you can see, the template consists of only 4 files:
- Main.storyboard. Storyboard containing the main view controller
- TemplateIcon.png. Icon with 48×48 definition
- TemplateIcon@2x.png. Icon with 96×96 definition
- TemplateInfo.plist. Configuration file for the template
Only the last file, TemplateInfo.plist, plays a significant role here, because it contains all the settings. Main.storyboard is just one of the possible files that will be added to every application created from this template. In the absence of the second and third files from this list, your template will have a default icon. Therefore, the heart of the template is TemplateInfo.plist.
Main properties of the configuration file
Nominally, TemplateInfo properties can be divided into several categories:
1. Template markup
Assigning a template a unique ID and additional fields for display in the Xcode environment.
Unique identificator. Two templates with the same ID cannot exist at the same time. Also used for inheritance in other templates.
Template type. Xcode.Xcode3.ProjectTemplateUnitKind are always used for projects
A field that indicates whether the template will appear in the list when a new application is created. It makes sense to put NO when it is called from another template and is not independent itself. Otherwise, always set YES.
Specifies what platforms the template is used for. Only useful for preventing inheritance in templates for other platforms (for example, when trying to import an iOS template into a WatchOS one).
The display name for the template. The default directory name is *.xctemplate.
Serial number. If there is no such field, it is considered as the last one.
Description of the template. It is not displayed in the latest Xcode versions.
Templates in Xcode have a very useful property: they can include properties and files from other templates. It is very useful if there is a need to extend a template with additional features from another one without copying the files again and without editing the configuration file. A direct analogy is inheritance in OOP.
List of Identifier-templates which properties and files will be included in the project.
4. Content generation
You can fill a new application with both ready-made files, and by setting their generation in the settings.
P.S. Since projects can be created using both Objective-C and Swift, it must be taken into account that file generation must be written for different languages separately.
To do this, the Options field is created, which is an array. As the first element, we create a Dictionary and create two keys. The first is an Identifier of type String with the value “languageChoice”. The second is Units, which is a Dictionary. In Units, we create two more Dictionaries with the names “Objective-C” and “Swift”, respectively. All the Definitions and Nodes created in the future are placed inside these directories. If there is no language binding (for example, we want to add xib, storyboard or register content for a file), then Definitions and Nodes can be declared at the same level as the rest of the parameters.
Code generation is declared here and the paths to the files that will be added to the application are written.
Definitions is an associative array and contains a list of files or variables. Each file, in turn, is also an associative array that contains the path to the file. It can consist of two properties – Path and Group.
Path is the direct path to the file located in the .xctemplate directory.
Group is an array, and each its element is a directory included in the specified path. The file itself is not specified.
For example, the file path is:
Then the Definition for it will look like this:
Accordingly, if the file has no embedding and lies directly in .xctemplate/, then the Group array is not created.
After we have specified the file paths, we need to create links. With their help we will point either to the created file or to the content. Nodes is a regular array, and its elements are keys from Definitions. For the above mentioned example, Nodes would look like this:
Code generation inside TemplateInfo.plist
You can add code to a file created in TemplateInfo.plist by writing it in Definitions and referencing it in Nodes. This is done by using the “:” operator after specifying the file, and the code is written afterwards. For example, in the default “Page-Based App” template, you can see that the Definitions describe a lot of code generation:
The order of the code in the file depends on the order of the links in the Nodes array. It will be created in case the specified file does not exist.
The following constants work in pre-created files and inside TemplateInfo.plist:
___COPYRIGHT___ Copyright line
___DATE___ Project (file) creation date
___DIRECTORY___ Full path to the file
___FILEBASENAME___ File name without extension
___FILEEXTENSION___ File extention
___FILENAME___ Full file name
___FULLUSERNAME___ Username authorized in the system
___ORGANIZATIONNAME___ The name of the organization specified when the project was created
___PACKAGENAME___ / ___PROJECTNAME___ The product name specified when the project was created
___TIME___ The time the project (file) was created
___USERNAME___ Authorized user account name
Editing the application settings window
When creating a template, you can also edit the application settings window which will later appear when this template is called.
For example, for the “Single View App”, Apple offers us several text fields for entering the developer name and the name of the organization, several checkboxes for including unit tests or CoreData in the project, as well as a drop-down list for choosing a programming language. All this is regulated by the Options field – an array from the Dictionary. For each option, the following list of options is available:
An identifier which allows to change or use the value stored in the option field.
The value that will be used by default for this field.
The sequence number by which this option will be displayed in the window.
The title for the option.
The type of the originating field. There are the following fields types:
- Static. Static, non-editable text. In terms of meaning, it is nothing more than a Label.
- Checkbox. Regular checkbox. Since it is inherently a Bool-field, you also need to define Units for it, which will contain the appropriate set of actions for true and false values. An example of usage can be found in the “Core Data Cocoa Touch App.xctemplate” base template, which will be mentioned in the template creation section.
- Text. Text input field.
- Popup. Provides a selection from a drop-down list which must be defined in the Values array.
Creating an application template
Before we start, we need to prepare the files with the written code that we want to see in the application created according to our template.
For starters, let’s create a directory where the templates we created will be stored. To do this, in the console, execute the command:
$ mkdir -p ~/Library/Developer/Xcode/Templates/Project\ Templates/Private
This is the path Xcode will look for application templates. You can name the Private folder as you wish, as long as it is located along this path. There may be several such directories, but the templates embedded in them must have a different Identifier. Otherwise, the existence of the template in all but one directory will be ignored.
Rename the “Single View App.xctemplate” copied earlier to “MVVM Application.xctemplate” and copy it to the Private folder. If you now launch Xcode and go to the menu for creating a new application, you can already see at the very bottom a new Private section, where there will be one single “MVVM Application” template. Since we have not changed anything yet, when using it, we will get the same Single View App (which, by the way, disappeared from the list of basic ones, because it has the same Identifier).
The next step is to transfer the Presentation folder and two icon files – TemplateIcon.png and TemplateIcon@2x.png. Now we need to change the Identifier so that Xcode sees our template as a brand new one. For example, let’s set the Identifier to “MVVMTemplate”. Now, when creating a new application in Xcode, we will see that the “Single View App” has returned to its proper place, and in the Private section, “MVVM Application” flaunts with our icon.
Next, let’s see what templates “Single View App” inherits from. Opening TemplateInfo.plist and go to Ancestors, we see:
Templates with these identifiers are located in the same place as the “Single View App”. Let’s sort it out in order.
The first template “Storyboard App.xctemplate” contains only the configuration file, in which you can see the Definitions and Nodes fields. They state that Main.storyboard will be used as the main storyboard, and the path to it is indicated. We don’t need it, because we already have a MainScreen.storyboard file that we want to use as the main one. Therefore, we are removing the “Storyboard App.xctemplate” template from Ancestors.
Next comes the “Core Data Cocoa Touch App.xctemplate” template. A checkbox field is added to its options for the possibility of using CoreData, and all the necessary code generation and import of the ___PACKAGENAMEASIDENTIFIER___.xcdatamodeld file are registered in the Units field. Let’s say that we don’t need CoreData either, and also delete this parent.
But here’s the problem: if we now try to create an application according to our template, then it will not be visible in the list. The fact is that the parents we deleted, in turn, also had the Ancestors list, which contained the necessary base template “Cocoa Touch App Base” with the com.apple.dt.unit.cocoaTouchApplicationBase identifier. By adding it to the list of Ancestors of our template, we will return it to the list of available ones again. By carefully studying this basic template, you will understand why it is so necessary, and we move on.
Now let’s register all the paths and links for the copied files. Since the code is written for Swift, I will do this only for it.
Go to Options -> languageChoice (Item 0) -> Units -> Swift and create a Dictionary here called Definitions. Now let’s write out all the paths to the files that we have:
Presentation/Main Screen/View Controller/MainViewController.swift
Presentation/Main Screen/View Model/MainViewModel.swift
We get the following list:
Now we fill in the Nodes links, it will look like this:
It remains to add the final touch – to put MainScreen.storyboard as the main one. Create Definitions and Nodes for the entire file and add the following fields to them:
We get the following:
In the example I attached, there is a ready-made version of the TemplateInfo.plist file.
This article does not cover all the features for creating templates and files. It is simply not possible to include a description of each parameter here. Therefore, in the repository where the example is located, I have enclosed the documentation (unofficial) which describes all the possibilities and spells out all the existing parameters (at the time of Xcode 4 existence). Most of the functions can be understood by digging into the basic templates from Apple, at the same time seeing their implementation. I just described the necessary minimum for the simple creation of plain templates.
If you want to leave a feedback, you can always email us to firstname.lastname@example.org. Thank you!