Android Studio (and other JetBrains IDEs) offer two easily accessible options for creating code snippets and whole files from templates — live templates and file templates. You can add, delete, and edit them in IDE preferences. But what if you want to create multiple files at once? That’s where group templates come in. Android Studio comes with bundled file group templates — you have probably already used them when creating ActivitiesY’all or Fragments. You cannot modify those templates from the IDE itself, but they can be found in the Android Studio directory. You can add your own templates there, or edit the existing ones.
Group File Templates Location
Group file templates can be found in the following locations:
- on MacOS
- on other OSes:
Bundled file templates are grouped in the following folders in the aforementioned directory — activities, gradle, gradle-projects, other. You can add new templates into those folders, or create separate folders for your templates.
Every new group file template must be contained in its own folder, and this folder has to be placed in one of the group folders. New templates have to be placed in the following directory:
GROUP_FOLDER_NAME — can be an existing folder’s name (such as activities), or a new folder — for example my_activities.
File Group Template Structure
Group template typically contains the following files:
There are two type of files used for creating file group templates — XML, and Freemarker (with .ftl extension). According to the project’s website:
Freemarker is a template engine: a Java library to generate text output (HTML web pages, e-mails, configuration files, source code, etc.) based on templates and changing data.
Full documentation of Freemarker can be found here.
The name of this file has to be template.xml. Otherwise IDE won’t recognize it as such, and the file template defined in this file won’t show up in new files picker. It is technically the only file needed for the template to appear in Android Studio. It defines the template’s name, description, and parameters that can be inputted by the user. It has the following structure:
Element defining the file group template.
- name — name of the template, visible to the user in the new file list;
- description — template description, visible at the top of the new file group dialog;
- value — category in which the template would show in, it creates a new category in the file picker if there was no such category;
- id — parameter name that can be used to reference parameter’s value in template files;
- name — parameter name visible to the user;
- type — typ of the parameter, e.g. ‘string’;
- constraints — constraints of the input, can take following values: layout, unique, nonempty, package;
- default — default value of the parameter, can reference other parameters, e.g. we could use this feature to generate an activity’s layout name based on a feature name :
- help — optional parameter that defines a hint that appears at the bottom of the new component dialog when the user is editing a particular parameter’s value.
- file — relative path to globals.xml.ftl file;
- file — relative path to recipe.xml.ftl file;
- thumbs — optional element containing image file paths to the preview picture visible in new the file group dialog.
This file defines the variables accessible in all of the template files. It is commonly is named globals.xml.ftl
With this directive you can create new variable, or replace an existing variable. Variables in this element would be visible only within this element. Full documentation for this directive can be found here.
Element defining globally visible variable
- id — name of the variable that can be referenced in template files;
- value — value of the variable. Can be either string literal, or a method call.
Directive for including external files containing global variables definition. Useful when we want to re-use the same variables for multiple templates. The included file has the same structure as the main globals file.
Recipe files contain instructions for the processor pertaining to file creation and modification. In existing templates it is called recipe.xml.ftl.
Directive for including external recipes, useful when we want to re-use the same recipe in multiple templates.
This element is used to merge xml elements into existing xml files. It is most commonly used for merging activity elements into AndroidManifest.xml. It can’t be used with other file types, such as Kotlin or Java files.
This element is used to create a new file based on the file template.
Using this element you can define which files will be opened after the template has been executed.
Those are the files which will serve as a base for files created during the template processing. They have .ftl extension, usually preceded by the result file extension, for example MyActivity.kt.ftl for Activity written in Kotlin. The template file can look something like this:
You can reference variables defined in globals.xml.ftl file in your templates. You can also use methods here.
There are various built-in methods available in Freemarker that you can call on your defined variables. For example, if you defined a string variable named myVariable, you can call a method on it like so:
The full reference for built-ins can be found here.
Beside standard Freemarker built-in methods you can also use conversion methods added by JetBrains. There’s no official reference for those, but all of them can be seen in the source code of their FreemarkerUtil::createParameterMap method:
Those methods can be called like Java methods, and take zero or more variables as an argument, for example:
Those methods are not really documented anywhere, but if you want to figure out what exactly they do, you can check the tests for them, which can be found here:
Android Plugin for IntelliJ IDEA. Contribute to JetBrains/android development by creating an account on GitHub.
activityToLayout — takes one string argument, and returns a string with activity name converted to layout name, for example “FooActivity” would be converted to “activity_foo”;
camelCaseToUnderscore — takes one string argument, as the name implies, converts camel case strings to underscored ones, e.g. “FooBar” would be converted to “foo_bar”;
classToResource — takes one string argument, converts Android components names to resource names, e.g. calling this method for both “FooActivity”, or “FooFragment” would produce “foo”;
compareVersions — two string arguments, both describing a Gradle version — usually three numbers separated by dots, with an optional suffix. For example “1.0.0”, “10.5.1”, or “2.2.0-dev”. Then it parses the arguments GradleVersion objects and compares them using GradleVersion::compareTo method. It can return three integer values — either 1 if the first argument is greater than the second, 0 if the arguments are identical, or -1 if the second argument is greater than the first.
compareVersionsIgnoringQualifiers — the same as compareVersions, but uses GradleVersion::compareIgnoringQualifiers method for comparison.
escapePropertyValue — takes one string argument, and returns a string with removed escaping backslashes — for example calling the method with “\\ foo “ argument will produce “ foo “.
escapeXmlAttribute — takes one string argument and returns a string with escaped xml characters. E.g. for “<\”’>&” the method will produce “<"'>&”.
escapeXmlString — takes one string argument and returns a string with xml characters escaped. E.g. calling this method with “Hello\nWorld” argument, would return “Hello\\nWorld”.
escapeXmlText — takes one string argument and returns string converted to Xml-attribute-safe value. Seems to yield the same results as escapeXmlString, but uses different method for conversion internally.
extractLetters — takes one string argument and returns string containing only letter characters from that string, e.g. calling the method with “<\’>&foo “ argument would produce “foo”.
getAppManifestDir — returns the path to the directory in which app manifest is stored, e.g. for MacOS that would be:
getApplicationTheme — returns map containing application theme name (e.g. “AppTheme”), boolean denoting whether application theme inherits from AppCompat theme, and whether the application has an application theme at all. You can access those arguments by calling “getApplicationTheme().name”, “getApplicationTheme().isAppCompat”, and “getApplicationTheme().exists”.
isAndroidxEnabled — returns boolean if the project uses AndroidX libraries.
getConfigurationName — returns currently used configuration name, such as “implementation”.
getMaterialComponentName — takes two arguments, first of them being a name of an Android view class, and the second — a boolean denoting whether a new class name should be used. Calling this method with “android.support.design.widget.FloatingActionButton” and true arguments it returns “com.google.android.material.floatingactionbutton.FloatingActionButton” which is the name of the new FloatingActionButton class.
hasDependency — takes two string arguments, first of them being a library name, and second — a configuration name, and returns a boolean denoting whether specified configuration depends on specified library.
isGradleComponentPluginUsed — returns boolean denoting whether the Gradle component plugin (AKA experimental plugin) is used for a given module.
layoutToActivity — takes one string argument and returns string with layout name converted to activity name, for e.g. for “activity_foo” this method will return “FooActivity”.
slashedPackageName — takes one string argument in format of a Java package name and returns string containing relative path to this package. E.g. calling this method with “com.example.foo” argument will return “com/example/foo”.
truncate — takes two arguments, a string and an int, and returns the argument string truncated to first n characters, where n is the second argument.
underscoreToCamelCase — takes one string argument and returns argument string converted to camel case.
escapeKotlinIdentifiers — takes one string argument and returns string with all of the Kotlin keywords escaped with `` characters. For example, for “foo.in.bar.is” the method will return “foo.`in`.bar.`is`”.
Example of custom file group template
To accelerate Android applications development here at Codequest we created file group templates for MVI Activities and Fragments that take care of creating all of the classes and files required by this architecture. It can be found here:
Contribute to kubak89/MVI-Android-Templates development by creating an account on GitHub.
If you have any further questions on the topic, or think I omitted some aspect of creating file group templates in Android Studio, please let me know! I would like to make this guide as comprehensive as possible, so I will try update it according to your comments.
Thank you for reading and happy coding!