
In the process of creating new applications, it is often necessary to write the same type of code and reproduce the time-tested class structures. IDE (in particular, Android Studio) facilitates in many respects the tasks associated with the creation of new components for the application. The list of template tivity is growing with each new version of the SDK Tools. But what if you need to create your own template? For a single file, this is easy, but what if you need to create a template with multiple files? Knowing the capabilities of the IDE, it is quite realizable, because the Activity is created with the markup file, and you can add a fragment to it. However, the description of such functionality was not found, so I had to find a solution for this possibility on my own.
Under the cut I want to tell you about how this feature is implemented in Android Studio.
My first thought was to ask colleagues who use JetBrains products how they solve this problem. The answer was quite simple. To create the class structure, a separate script was written that performed all the necessary actions.
')
Indeed, this was the first decision that came to mind. And it has its advantages, namely, independence from the IDE. However, this is inconvenient, and the issue of compatibility with the IDE remained relevant.
In the source code of the SDK there is a description of the way to solve the problem.
Android IDE Template Format .
Having received such a tool, I immediately decided to try it out and I hasten to share this experience.
To create templates using
FreeMarker . This is very similar to using PHP and Django templates.
The bottom line is that we have a specific template and form for entering parameters. After entering, the parameters are transferred to the template, and the required class is collected based on this data.
A list of all used templates is located at the following address
android-studio-folder \ plugins \ android \ lib \ templates \To create your template, add a new directory to the directory activities (or other) with the following list of files

Only the template.xml and recipe.xml files are required.
template.xml
This XML file contains metadata about the template, including the name, description, category, and options that are visible to the user and are available as options in the IDE.
Sample template.xml <template format="4" revision="2" minApi="7" minBuildApi="16" name="Blank Activity" description="Creates a new blank activity, with navigation."> <parameter id="activityClass" name="Activity Name" type="string" constraints="class|unique|nonempty" suggest="${layoutToActivity(layoutName)}" default="MainActivity" help="The name of the activity class to create." /> <parameter id="layoutName" name="Layout Name" type="string" constraints="layout|unique|nonempty" suggest="${activityToLayout(activityClass)}" default="activity_main" help="The name of the layout to create for the activity" /> <parameter id="navType" name="Navigation Type" type="enum" default="none" help="The type of navigation to use for the activity"> <option id="none">None</option> <option id="tabs" minApi="11">Tabs</option> <option id="pager" minApi="11">Swipe Views</option> <option id="dropdown" minApi="11">Dropdown</option> </parameter> <parameter id="fragmentName" name="Fragment Name" type="string" constraints="class|unique|nonempty" default="MainFragment" visibility="navType != 'none'" help="The name of the fragment class to create" /> <thumbs> <thumb>template_default.png</thumb> <thumb navType="tabs">template_tabs.png</thumb> <thumb navType="dropdown">template_dropdown.png</thumb> </thumbs> <globals file="globals.xml.ftl" /> <execute file="recipe.xml.ftl" /> </template>
Template element
format - the version of the template that this template follows. Must be 4. (well, so here)
revision is an optional parameter. The version of this template (which can be increased by updating the template)
name - the display name of the template.
description - description of the template.
minApi is an optional parameter. The minimum API level is checked for this template. IDE before creating a template will check that minSdkVersion is not lower than this value.
Element
parameterDefines a customizable template parameter.
id - identifier for the variable. Available in a global variable file. If the identifier is Foo, then the parameter value will be available in FreeMarker files as $ {Foo}.
name - the display name of the parameter.
type - the type of the parameter. Available values are string, boolean, enum, and separator.
constraints is optional. Parameter restrictions. Constraints can be combined with |.
Types of restrictions- nonempty - the value should not be empty
- apilevel - indicates API level
- package - value must be a valid Java package name
- app_package - the value must be a valid Android app package name
- module - the value must be a valid module name
- class - the value must be a valid Java class
- activity - the value must be the full name of the class Activity
- layout - the value must be a valid resource layout name
- drawable - the value must be a valid drawable resource name
- string - the value must be a valid string name of the resource
- id - the value must be a valid id name
- unique - the value must be unique
- exists - value must exist
suggest - optional. Automatically updated expressions depending on the value of other parameters.
default is optional. The default value for this parameter.
visibility is optional. FreeMarker expression defining component visibility.
help is optional. Hint for this parameter.
Option element
For parameters of type enum, represents the elements to select.
id - the parameter value is set if this option is selected.
minApi is optional. A minimum API level is required.
[text] - The text displayed when this option is selected.
Thumb element
Shows the thumbnail for the template. Items must be inside the item. The text contained in this element is the path to the thumbnail. If this element has attributes, they will be treated as a selector.
Example:
<thumbs> <thumb>template.png</thumb> <thumb navType="tabs">template_tabs.png</thumb> </thumbs>
Template_tabs.png will be shown as a thumbnail if tabs is selected in navType.
globals.xml.ftl
The XML file contains global variables for use in FreeMarker working layouts.
Example globals.xml.ftl:
<globals> <global id="srcOut" value="src/${slashedPackageName(packageName)}" /> <global id="activityNameLower" value="${activityName?lower_case}" /> <global id="activityClass" value="${activityName}Activity" /> </globals>
recipe.xml.ftl
This XML file contains separate instructions that must be executed when generating code for this template.
For example, you can copy some files or directories (copy instruction), you can create files via FreeMarker (instantiate instruction), and you can ask the IDE to open the file (open instruction).
Note: The name of the instruction file is defined in template.xml. However, by convention, it is better to call it recipe.xml.ftl.
Note: Globals.xml.ftl global variables are available for use in recipe.xml.ftl.
Recipe.xml.ftl example <recipe> <#if appCompat?has_content> <dependency mavenUrl="com.android.support:appcompat-v7:+"/> </#if> <merge from="AndroidManifest.xml.ftl" to="${escapeXmlAttribute(manifestDir)}/AndroidManifest.xml" /> <copy from="res/drawable-mdpi" to="${escapeXmlAttribute(resDir)}/res/drawable-mdpi" /> <copy from="res/drawable-hdpi" to="${escapeXmlAttribute(resDir)}/res/drawable-hdpi" /> <copy from="res/drawable-xhdpi" to="${escapeXmlAttribute(resDir)}/res/drawable-xhdpi" /> <copy from="res/drawable-xxhdpi" to="${escapeXmlAttribute(resDir)}/res/drawable-xxhdpi" /> <copy from="res/menu/main.xml" to="${escapeXmlAttribute(resDir)}/res/menu/${activityNameLower}.xml" /> <merge from="res/values/dimens.xml" to="${escapeXmlAttribute(resDir)}/res/values/dimens.xml" /> <merge from="res/values-large/dimens.xml" to="${escapeXmlAttribute(resDir)}/res/values-large/dimens.xml" /> <merge from="res/values/styles.xml" to="${escapeXmlAttribute(resDir)}/res/values/styles.xml" /> <merge from="res/values/strings.xml.ftl" to="${escapeXmlAttribute(resDir)}/res/values/strings.xml" /> <#if navType?contains("pager")> <instantiate from="${escapeXmlAttribute(resDir)}/res/layout/activity_pager.xml.ftl" to="${escapeXmlAttribute(resDir)}/res/layout/activity_${activityNameLower}.xml" /> <#elseif navType == "tabs" || navType == "dropdown"> <copy from="${escapeXmlAttribute(resDir)}/res/layout/activity_fragment_container.xml" to="${escapeXmlAttribute(resDir)}/res/layout/activity_${activityNameLower}.xml" /> <#else> <copy from="${escapeXmlAttribute(resDir)}/res/layout/activity_simple.xml" to="${escapeXmlAttribute(resDir)}/res/layout/activity_${activityNameLower}.xml" /> </#if> <#if navType == "none"> <instantiate from="src/app_package/SimpleActivity.java.ftl" to="${escapeXmlAttribute(srcOut)}/${activityClass}.java" /> <#elseif navType == "pager"> <instantiate from="src/app_package/PagerActivity.java.ftl" to="${escapeXmlAttribute(srcOut)}/${activityClass}.java" /> <#elseif navType == "tabs"> <instantiate from="src/app_package/TabsActivity.java.ftl" to="${escapeXmlAttribute(srcOut)}/${activityClass}.java" /> <#elseif navType == "dropdown"> <instantiate from="src/app_package/DropdownActivity.java.ftl" to="${escapeXmlAttribute(srcOut)}/${activityClass}.java" /> </#if> <open file="${escapeXmlAttribute(resDir)}/res/layout/${activityNameLower}.xml" /> <open file="${escapeXmlAttribute(srcOut)}/${activityClass}.java" /> </recipe>
The instructions support the following methods:
dependencyIndicates that the template needs a library. If not, the IDE will add a dependency to the project.
MavenUrl attribute
Specifying the maven library package. For example, com.android.support:appcompat-v7:+
copyThe only required parameter is the path to the source files to be copied relative to the root / directory. All necessary subdirectories are created automatically, if necessary.
The creation directory defaults to the location of the template relative to the / root folder. There is an optional parameter to specify the path to create the file. Please note that the .ftl extension is automatically removed. For example, the entry /> is correct. This will create a file named strings.xml, not strings.xml.ftl.
instantiateSame as copy, but for the source file FreeMarker will be launched first.
mergeThis instruction will launch FreeMarker for the source file, and then merge the content with an existing file in the project or create a new file. The most common example of using this instruction is adding components to the AndroidManifest.xml file or combining resources such as strings.xml.
openOpens the file specified in the arguments after the code generation is complete.
mkdirChecks the existence of the directory specified in the arguments
root /
All template files (resources, Java sources, Android Manifest) should be located in the root / directory
However, instead of placing the source files in src / com / google / ... you can simply use src / app_package /.
Built-in Template Functions
There are several functions that are not included in the FreeMarker functions that can be used.
Here are some of them:
string activityToLayout (string)Converts the class name of the Activity to a string suitable for use as a resource name. For example, FooActivity will be converted to activity_foo.
string camelCaseToUnderscore (string)Converts a camel-case string to an underscore string. For example, FooBar will be converted to foo_bar.
string classToResource (string)Converts the Android class name, for example, FooActivity or FooFragment, to the corresponding resource with the addition of the suffix 'Activity' or 'Fragment'.
Currently recognized:
- Activity
- Fragment
- Provider
- Service
string layoutToActivity (string)Converts a suffixed resource to a class string. For example, activity_foo will be translated to the Java class FooActivity.
string slashedPackageName (string)Converts the full name of the Java package to the corresponding directory path. For example, if the argument is com.example.foo, then the return value will be com / example / foo.
string underscoreToCamelCase (string)Converts the underscore string to the corresponding camel case line. For example, foo_bar to FooBar.
Built-in Template Parameters
Some options available for FreeMarker expressions and files.
packageNameProject package name, for example, com.example.foo
isNewProjectA Boolean value indicating whether the template is a new project template.
manifestDirDirectory with AndroidManifest.xml.
srcDirThe Java source directory for the project.
resDirThe directory of the root directory of resources (res /) for the project.
For a complete list of functions and parameters, refer to the
documentation .
In general, creating your own template is not difficult. Having spent some time on its creation, you can get rid of the routine for creating components and structures in the project.
Use and automate everything that can be automated.
useful links
DocumentationArticle on creating your own Google Analytics ActivityWork with FreeMarker