Skip to main content
The Template API provides interfaces for creating custom project templates and file templates in Android Code Studio.

Core Interfaces

ITemplateProvider

The main interface for managing templates. Source: utilities/templates-api/src/main/java/com/tom/rv2ide/templates/ITemplateProvider.kt:27
package com.tom.rv2ide.templates

interface ITemplateProvider {
  
  // Template access
  fun getTemplates(): List<Template<*>>
  fun getTemplate(templateId: String): Template<*>?
  
  // Lifecycle
  fun reload()
  fun release()
  
  companion object {
    fun getInstance(reload: Boolean = false): ITemplateProvider
    fun isLoaded(): Boolean
  }
}

RecipeExecutor

Interface for executing template recipes and file operations. Source: utilities/templates-api/src/main/java/com/tom/rv2ide/templates/RecipeExecutor.kt:28
package com.tom.rv2ide.templates

import java.io.File
import java.io.InputStream

interface RecipeExecutor {
  
  // Project data access
  fun projectData(): ProjectTemplateData?
  fun requireProjectData(): ProjectTemplateData
  
  // File operations
  fun copy(source: File, dest: File)
  fun save(source: String, dest: File)
  
  // Asset operations
  fun openAsset(path: String): InputStream
  fun copyAsset(path: String, dest: File)
  fun copyAssetsRecursively(path: String, destDir: File)
}

Getting Templates

Get Template Provider

Access the template provider:
import com.tom.rv2ide.templates.ITemplateProvider

val templateProvider = ITemplateProvider.getInstance()
println("Template provider loaded")

List Available Templates

Retrieve all available templates:
val templates = templateProvider.getTemplates()

println("Available templates:")
templates.forEach { template ->
  println("  - ${template.name} (${template.id})")
  println("    ${template.description}")
}
getTemplates()
List<Template<*>>
Returns all registered templates in the provider

Get Specific Template

Retrieve a template by ID:
val templateId = "EmptyActivity"
val template = templateProvider.getTemplate(templateId)

if (template != null) {
  println("Found template: ${template.name}")
  println("Category: ${template.category}")
} else {
  println("Template not found: $templateId")
}
templateId
String
required
The unique identifier for the template

Template Types

Project Templates

Templates for creating entire projects:
interface ProjectTemplate : Template<ProjectTemplateData> {
  val minSdk: Int
  val targetSdk: Int
  val widgets: List<Widget>
  
  suspend fun create(data: ProjectTemplateData, executor: RecipeExecutor)
}

Module Templates

Templates for adding modules to existing projects:
interface ModuleTemplate : Template<ModuleTemplateData> {
  val isLibrary: Boolean
  val androidModule: Boolean
  
  suspend fun create(data: ModuleTemplateData, executor: RecipeExecutor)
}

File Templates

Templates for creating individual files:
interface FileTemplate : Template<FileTemplateData> {
  val fileExtension: String
  
  suspend fun create(data: FileTemplateData, executor: RecipeExecutor)
}

Creating Templates

Define a Project Template

Create a custom project template:
import com.tom.rv2ide.templates.*
import com.tom.rv2ide.templates.base.ProjectTemplateBuilder

class MyProjectTemplate : ProjectTemplate {
  
  override val id = "MyProject"
  override val name = "My Custom Project"
  override val description = "A custom project template"
  override val category = "Custom"
  override val minSdk = 21
  override val targetSdk = 34
  override val widgets = emptyList<Widget>()
  
  override suspend fun create(
    data: ProjectTemplateData,
    executor: RecipeExecutor
  ) {
    // Create project structure
    createProjectStructure(data, executor)
    
    // Copy template files
    copyTemplateFiles(executor)
    
    // Generate build files
    generateBuildFiles(data, executor)
  }
  
  private fun createProjectStructure(
    data: ProjectTemplateData,
    executor: RecipeExecutor
  ) {
    val projectDir = File(data.projectDir)
    
    // Create directories
    File(projectDir, "app/src/main/java").mkdirs()
    File(projectDir, "app/src/main/res").mkdirs()
    File(projectDir, "app/src/main/assets").mkdirs()
  }
  
  private fun copyTemplateFiles(executor: RecipeExecutor) {
    // Copy assets from template
    executor.copyAssetsRecursively(
      "templates/MyProject",
      File(executor.requireProjectData().projectDir)
    )
  }
  
  private fun generateBuildFiles(
    data: ProjectTemplateData,
    executor: RecipeExecutor
  ) {
    // Generate build.gradle
    val buildGradle = """
      plugins {
          id 'com.android.application'
          id 'org.jetbrains.kotlin.android'
      }
      
      android {
          namespace '${data.packageName}'
          compileSdk ${data.compileSdk}
          
          defaultConfig {
              applicationId "${data.packageName}"
              minSdk ${data.minSdk}
              targetSdk ${data.targetSdk}
              versionCode 1
              versionName "1.0"
          }
      }
    """.trimIndent()
    
    executor.save(
      buildGradle,
      File(data.projectDir, "app/build.gradle")
    )
  }
}

Define a File Template

Create a template for generating files:
class KotlinClassTemplate : FileTemplate {
  
  override val id = "KotlinClass"
  override val name = "Kotlin Class"
  override val description = "Creates a new Kotlin class"
  override val category = "Kotlin"
  override val fileExtension = ".kt"
  
  override suspend fun create(
    data: FileTemplateData,
    executor: RecipeExecutor
  ) {
    val className = data.fileName
    val packageName = data.packageName
    
    val content = """
      package $packageName
      
      /**
       * $className
       * 
       * @author ${data.author}
       */
      class $className {
          
          // TODO: Implement class
          
      }
    """.trimIndent()
    
    val targetFile = File(data.targetDirectory, "$className.kt")
    executor.save(content, targetFile)
    
    println("Created: ${targetFile.absolutePath}")
  }
}

Recipe Execution

File Operations

Perform file operations during template execution:
class TemplateRecipe(private val executor: RecipeExecutor) {
  
  fun execute(data: ProjectTemplateData) {
    val projectDir = File(data.projectDir)
    
    // Copy single file
    val sourceFile = File("/templates/MainActivity.kt")
    val destFile = File(projectDir, "app/src/main/java/MainActivity.kt")
    executor.copy(sourceFile, destFile)
    
    // Save string content to file
    val manifest = """
      <?xml version="1.0" encoding="utf-8"?>
      <manifest xmlns:android="http://schemas.android.com/apk/res/android">
          <application
              android:label="${data.appName}">
          </application>
      </manifest>
    """.trimIndent()
    
    executor.save(manifest, File(projectDir, "app/src/main/AndroidManifest.xml"))
  }
}

Asset Operations

Work with template assets:
fun copyTemplateAssets(executor: RecipeExecutor) {
  // Open asset stream
  val stream = executor.openAsset("templates/icon.png")
  stream.use { input ->
    // Process asset
  }
  
  // Copy single asset
  executor.copyAsset(
    "templates/icon.png",
    File("app/src/main/res/drawable/icon.png")
  )
  
  // Copy entire asset directory
  executor.copyAssetsRecursively(
    "templates/layouts",
    File("app/src/main/res/layout")
  )
}
path
String
required
The path to the asset relative to the assets directory
dest
File
required
The destination file or directory

Template Data

ProjectTemplateData

Data passed when creating projects:
data class ProjectTemplateData(
  val projectName: String,
  val projectDir: String,
  val packageName: String,
  val appName: String,
  val language: Language,
  val minSdk: Int,
  val targetSdk: Int,
  val compileSdk: Int,
  val useAndroidX: Boolean = true,
  val useKotlin: Boolean = true
)

ModuleTemplateData

Data for creating modules:
data class ModuleTemplateData(
  val moduleName: String,
  val packageName: String,
  val parentProjectDir: String,
  val isLibrary: Boolean = false,
  val language: Language
)

FileTemplateData

Data for creating files:
data class FileTemplateData(
  val fileName: String,
  val packageName: String,
  val targetDirectory: File,
  val author: String = "Unknown",
  val extraData: Map<String, Any> = emptyMap()
)

Using Template Builders

AndroidModuleTemplateBuilder

Use the builder for Android modules:
import com.tom.rv2ide.templates.base.AndroidModuleTemplateBuilder

val builder = AndroidModuleTemplateBuilder()
  .setModuleName("mymodule")
  .setPackageName("com.example.mymodule")
  .setMinSdk(21)
  .setTargetSdk(34)
  .setIsLibrary(false)
  
builder.build().execute(executor)

FileTemplateBuilder

Build file templates:
import com.tom.rv2ide.templates.base.FileTemplateBuilder

val fileBuilder = FileTemplateBuilder()
  .setFileName("MyClass")
  .setPackageName("com.example")
  .setFileExtension(".kt")
  .setTemplate { data ->
    """
      package ${data.packageName}
      
      class ${data.fileName} {
          // Implementation
      }
    """.trimIndent()
  }
  
fileBuilder.create(executor)

Template Registration

Register Custom Template

Add your template to the provider:
import com.tom.rv2ide.templates.ITemplateProvider

class MyTemplateProvider : ITemplateProvider {
  
  private val templates = mutableListOf<Template<*>>()
  
  init {
    // Register templates
    templates.add(MyProjectTemplate())
    templates.add(KotlinClassTemplate())
    // Add more templates...
  }
  
  override fun getTemplates() = templates.toList()
  
  override fun getTemplate(templateId: String) =
    templates.find { it.id == templateId }
  
  override fun reload() {
    templates.clear()
    // Reload templates
  }
  
  override fun release() {
    templates.clear()
  }
}

Complete Example

Here’s a complete example creating and using a template:
import com.tom.rv2ide.templates.*
import java.io.File

class ComposeActivityTemplate : FileTemplate {
  
  override val id = "ComposeActivity"
  override val name = "Jetpack Compose Activity"
  override val description = "Creates a new Compose Activity"
  override val category = "Compose"
  override val fileExtension = ".kt"
  
  override suspend fun create(
    data: FileTemplateData,
    executor: RecipeExecutor
  ) {
    val activityName = data.fileName
    val packageName = data.packageName
    
    // Generate activity file
    val activityContent = """
      package $packageName
      
      import android.os.Bundle
      import androidx.activity.ComponentActivity
      import androidx.activity.compose.setContent
      import androidx.compose.material3.*
      import androidx.compose.runtime.*
      
      class $activityName : ComponentActivity() {
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContent {
                  ${activityName}Content()
              }
          }
      }
      
      @Composable
      fun ${activityName}Content() {
          Surface {
              Text("Hello from $activityName!")
          }
      }
    """.trimIndent()
    
    val targetFile = File(data.targetDirectory, "$activityName.kt")
    executor.save(activityContent, targetFile)
    
    println("Created Compose Activity: ${targetFile.absolutePath}")
  }
}

// Usage
fun useTemplate() {
  val provider = ITemplateProvider.getInstance()
  val template = ComposeActivityTemplate()
  
  // Create template data
  val data = FileTemplateData(
    fileName = "MainActivity",
    packageName = "com.example.myapp",
    targetDirectory = File("/path/to/src"),
    author = "Developer"
  )
  
  // Execute template (needs RecipeExecutor implementation)
  // template.create(data, executor)
}

Template Widgets

Define UI widgets for template configuration:
import com.tom.rv2ide.templates.Widget

val widgets = listOf(
  Widget.TextField(
    id = "appName",
    label = "Application Name",
    default = "My Application"
  ),
  Widget.TextField(
    id = "packageName",
    label = "Package Name",
    default = "com.example.myapp"
  ),
  Widget.Spinner(
    id = "language",
    label = "Language",
    options = listOf("Kotlin", "Java"),
    default = "Kotlin"
  ),
  Widget.CheckBox(
    id = "useCompose",
    label = "Use Jetpack Compose",
    default = true
  )
)

Project API

Work with project structure

Tooling API

Initialize created projects

Build docs developers (and LLMs) love