by Wero Lasota

File Group Templates in Android Studio — Unofficial Guide

Jakub Komorowski
codequest
Published in
7 min readAug 13, 2019

--

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
/Applications/Android Studio.app/Contents/plugins/android/lib/templates
  • on other OSes:
{ANDROID_STUDIO_LOCATION}/plugins/android/lib/templates/other/

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:

…/templates/{GROUP_FOLDER_NAME}/{TEMPLATE_NAME}/

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:

Typical structure of the group template 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.

Template file

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:

template

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;

category

  • value — category in which the template would show in, it creates a new category in the file picker if there was no such category;

parameter

  • 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 :
“activity_${featureName}”
  • 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.

globals

  • file — relative path to globals.xml.ftl file;

execute

  • 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.

Globals file

This file defines the variables accessible in all of the template files. It is commonly is named globals.xml.ftl

#assign

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.

global

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.

#include

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 file

Recipe files contain instructions for the processor pertaining to file creation and modification. In existing templates it is called recipe.xml.ftl.

include

Directive for including external recipes, useful when we want to re-use the same recipe in multiple templates.

merge

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.

instantiate

This element is used to create a new file based on the file template.

open

Using this element you can define which files will be opened after the template has been executed.

Template files

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.

Freemarker methods

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:

myVariable?capitalize

The full reference for built-ins can be found here.

Conversion methods

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:

${activityToLayout(myVariable)}

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:

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 “&lt;&quot;&apos;>&amp;”.

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:

/Users/{UserName}/{ProjectDirectory}/app/src/main

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:

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!

--

--