Geminio Android Studio Plugin

repository·master·Indexed 41 days ago

https://github.com/hhru/android-multimodule-plugin

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

Tokens
10.9K
Snippets
30
Records
57
Agent score
45%

What's inside Geminio

  1. Overview of Geminio

    master
    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.
  2. What is Geminio and why use it?

    master

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

  3. Structure of a `recipe.yaml` file

    master

    A recipe.yaml file is a set of instructions and prerequisites used to execute a template in Geminio. Every recipe file must be named exactly recipe.yaml. It combines the functionality of previous template formats (like FreeMarker's template.xml and recipe.xml) into a single configuration file.

    A complete recipe is composed of six main sections:

    1. requiredParams: Defines parameters that must be provided for the template to run.
    2. optionalParams: Defines parameters that are not strictly required.
    3. predefinedFeatures: A set of predefined Geminio features that can add new widgets or supplement functionality. This section is required only for modules templates.
    4. widgets: Defines the user-facing template parameters (e.g., stringParameter, booleanParameter, suggestParameter).
    5. globals: Defines invisible parameters (global variables) used within the template logic.
    6. 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}.kt
  4. How the android-multimodule-plugin works

    master

    The plugin automates the creation of templates and module templates by scanning specified folders for "recipes".

    1. Scanning: Upon opening a project in Android Studio, the plugin scans designated folders for recipe definitions.
    2. Action Creation: For every discovered template, the plugin automatically generates a new IDE Action (menu item).
    3. Menu Integration: These actions are integrated into two locations:
      • The Generate menu (accessible via Cmd + N while inside a code editor).
      • A dedicated group within the New menu (accessible via Cmd + N within the Project View).
    4. Execution: When a user selects a template from the menu, the plugin parses the associated recipe.yaml file and executes the defined steps to generate the template or module.
  5. Define templates using recipe.yaml

    master
    Templates and module templates are defined by a recipe.yaml file 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.
  6. How module templates work in Geminio

    master

    Module 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:

    1. Executes the commands defined in the template recipe.
    2. Appends a description of the new module to the settings.gradle file.
    3. Automatically adds a dependency on the newly created module to the selected application modules.
  7. Use expressions in template parameters

    master

    Template 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 widgets or globals section.
    • Expressions can evaluate to either strings or booleans.
    suggest: fragment_${className.classToResource().underscoreToCamelCase()}
    visibility: ${includeModule}
    availability: true
  8. Define template parameters using the `widgets` section

    master

    The widgets section 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, and suggestParameter. All parameters support expression evaluation for dynamic behavior.

    widgets:
      - stringParameter:
          id: className
          name: Class Name
      - booleanParameter:
          id: generateConstructor
          name: Generate Constructor
  9. Use the `recipe` section to automate post-template actions

    master

    The recipe section in your configuration allows you to define a sequence of commands that are automatically executed by an Action after 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: ...
  10. Release process for Geminio when API is unchanged

    master

    If the Android Studio update does not break any internal APIs, follow these steps to release the new version:

    1. Create a new branch in the repository.
    2. Update the build version: Update the androidStudio(...) value in the root build.gradle.kts.
    3. Update the plugin version: In gradle.properties, increment the minor version of hh-geminio (the second digit). Example: change 1.0.0 to 1.1.0.
    4. Update CHANGELOG.md: Document the support for the new Android Studio version.
    5. Run verification tasks:
      ./gradlew test
      ./gradlew buildPlugin verifyPluginStructure verifyPlugin
    6. Submit a PR to the master branch.
    ./gradlew test
    ./gradlew buildPlugin verifyPluginStructure verifyPlugin
  11. Enable module creation parameters in Geminio

    master

    To enable built-in features for module creation, add the enableModuleCreationParams value to the predefinedFeatures section 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 widgets expressions, globals expressions, 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: The packageName of the module added to AndroidManifest.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:
      - enableModuleCreationParams
  12. Use the `mkDirs` command to create folder structures

    master

    The mkDirs command 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