Geminio Android Studio Plugin
repository·master·Indexed 41 days ago
https://github.com/hhru/android-multimodule-pluginAn Android Studio plugin that restores and extends the ability to use custom FreeMarker templates for code generation. It allows developers to create, add, and update code and module templates via recipe.yaml files without needing to rebuild the IDE plugin, bypassing limitations introduced in Android Studio 4.1.
What's inside Geminio
- Geminio is an Android Studio plugin designed to restore and extend the ability to generate code from custom FreeMarker templates. It allows developers to add and update code generation templates independently of the plugin itself, bypassing the limitations introduced in Android Studio 4.1 where custom FreeMarker template support was restricted to IDEA plugins.
What is Geminio and why use it?
masterSince Android Studio 4.1, support for custom FreeMarker templates (previously added via local folders) has been deprecated. Custom templates can now only be added via IDEA plugins.
Geminio solves this by providing a plugin mechanism that allows you to create, add, and update your own code templates based on the FreeMarker engine without needing to rebuild or redistribute a full IDEA plugin every time a template changes.
Structure of a `recipe.yaml` file
masterA
recipe.yamlfile is a set of instructions and prerequisites used to execute a template in Geminio. Every recipe file must be named exactlyrecipe.yaml. It combines the functionality of previous template formats (like FreeMarker'stemplate.xmlandrecipe.xml) into a single configuration file.A complete recipe is composed of six main sections:
requiredParams: Defines parameters that must be provided for the template to run.optionalParams: Defines parameters that are not strictly required.predefinedFeatures: A set of predefined Geminio features that can add new widgets or supplement functionality. This section is required only for modules templates.widgets: Defines the user-facing template parameters (e.g.,stringParameter,booleanParameter,suggestParameter).globals: Defines invisible parameters (global variables) used within the template logic.recipe: The core set of execution instructions (commands) to be performed by the template engine.
requiredParams: name: HeadHunter BaseFragment description: Creates HeadHunter BaseFragment optionalParams: revision: 1 # ... predefinedFeatures: - enableModuleCreationParams: defaultPackageNamePrefix: ru.hh.test widgets: - stringParameter: id: className name: Fragment Name # ... globals: - stringParameter: id: reducerClassName value: ${moduleName}Reducer recipe: - mkDirs: - ${srcOut}: - api - instantiate: from: root/src/app_package/BlankFragment.kt.ftl to: ${srcOut}/${className}.ktHow the android-multimodule-plugin works
masterThe plugin automates the creation of templates and module templates by scanning specified folders for "recipes".
- Scanning: Upon opening a project in Android Studio, the plugin scans designated folders for recipe definitions.
- Action Creation: For every discovered template, the plugin automatically generates a new IDE Action (menu item).
- Menu Integration: These actions are integrated into two locations:
- The
Generatemenu (accessible viaCmd + Nwhile inside a code editor). - A dedicated group within the
Newmenu (accessible viaCmd + Nwithin the Project View).
- The
- Execution: When a user selects a template from the menu, the plugin parses the associated
recipe.yamlfile and executes the defined steps to generate the template or module.
Define templates using recipe.yaml
masterTemplates and module templates are defined by arecipe.yamlfile located within the template's folder. The plugin uses this file to determine how to prepare the template or module. While the UI of the wizard may differ between module templates and regular templates, both types support the same core features defined in the recipe.How module templates work in Geminio
masterModule templates are specialized templates designed to create new modules with specific folder structures, dependencies, and content. Unlike regular templates, module templates can be executed from any folder, not just from within existing Android modules.
When a module template is used, Geminio performs the following automated tasks:
- Executes the commands defined in the template recipe.
- Appends a description of the new module to the
settings.gradlefile. - Automatically adds a dependency on the newly created module to the selected application modules.
Use expressions in template parameters
masterTemplate parameters can use "expressions" to dynamically evaluate values during template generation. Expressions consist of a fixed part and a dynamic part enclosed in
${}.Rules for expressions:
- The dynamic part
${}is calculated based on the context. - You can only use parameters that have been declared ABOVE the current expression within the same
widgetsorglobalssection. - Expressions can evaluate to either strings or booleans.
suggest: fragment_${className.classToResource().underscoreToCamelCase()} visibility: ${includeModule} availability: true- The dynamic part
Define template parameters using the `widgets` section
masterThe
widgetssection in your recipe configuration defines the user interface parameters (inputs) that will be presented to a user when running a template. You can define three types of parameters:stringParameter,booleanParameter, andsuggestParameter. All parameters support expression evaluation for dynamic behavior.widgets: - stringParameter: id: className name: Class Name - booleanParameter: id: generateConstructor name: Generate ConstructorUse the `recipe` section to automate post-template actions
masterThe
recipesection in your configuration allows you to define a sequence of commands that are automatically executed by anActionafter a user has provided all required parameters for a template. This is used to automate tasks like dependency management, directory creation, or opening projects immediately after generation.# Example conceptual structure recipe: - command: addDependencies args: ... - command: instantiate args: ...Release process for Geminio when API is unchanged
masterIf the Android Studio update does not break any internal APIs, follow these steps to release the new version:
- Create a new branch in the repository.
- Update the build version: Update the
androidStudio(...)value in the rootbuild.gradle.kts. - Update the plugin version: In
gradle.properties, increment the minor version ofhh-geminio(the second digit). Example: change1.0.0to1.1.0. - Update CHANGELOG.md: Document the support for the new Android Studio version.
- Run verification tasks:
./gradlew test ./gradlew buildPlugin verifyPluginStructure verifyPlugin - Submit a PR to the
masterbranch.
./gradlew test ./gradlew buildPlugin verifyPluginStructure verifyPluginEnable module creation parameters in Geminio
masterTo enable built-in features for module creation, add the
enableModuleCreationParamsvalue to thepredefinedFeaturessection in your configuration.This feature adds two text fields for the new module's name and its main package name. Once enabled, you can use the following special parameters within
widgetsexpressions,globalsexpressions, and FTL templates:__moduleName: The module Gradle path without a leading:, e.g.,applicant:core. During file generation, path segments are treated as nested directories.__packageName: ThepackageNameof the module added toAndroidManifest.xml. If derived from__moduleName,:characters are replaced with..__formattedModuleName: A formatted module name used as a prefix for classes within the new module.
predefinedFeatures: - enableModuleCreationParamsUse the `mkDirs` command to create folder structures
masterThe
mkDirscommand is used to automatically create a hierarchical folder structure within your module.To use it, define a list of folder paths in your configuration. Each item in the list represents a root directory, and nested items represent subdirectories. You can use expressions (such as
${srcOut}or${resOut}) to define paths dynamically based on the project configuration.mkDirs: - ${srcOut}: - api - di: - modules - outer - ui: - presenters - ${resOut}: - layout - drawables - values