The Tooling API provides interfaces for interacting with Gradle builds, executing tasks, and querying project models in Android Code Studio.
Core Interfaces
The main interface for Gradle Tooling API operations.
Source : tooling/api/src/main/java/com/tom/rv2ide/tooling/api/IToolingApiServer.kt:36
package com.tom.rv2ide.tooling.api
import com.tom.rv2ide.tooling.api.messages. *
import com.tom.rv2ide.tooling.api.messages.result. *
import com.tom.rv2ide.tooling.api.models.ToolingServerMetadata
import java.util.concurrent.CompletableFuture
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest
interface IToolingApiServer {
// Server information
@JsonRequest
fun metadata (): CompletableFuture < ToolingServerMetadata >
// Initialization
@JsonRequest
fun initialize (params: InitializeProjectParams ): CompletableFuture < InitializeResult >
@JsonRequest
fun isServerInitialized (): CompletableFuture < Boolean >
// Project access
@JsonRequest
fun getRootProject (): CompletableFuture < IProject >
// Build operations
@JsonRequest
fun executeTasks (message: TaskExecutionMessage ): CompletableFuture < TaskExecutionResult >
@JsonRequest
fun cancelCurrentBuild (): CompletableFuture < BuildCancellationRequestResult >
// Lifecycle
@JsonRequest
fun shutdown (): CompletableFuture < Void >
}
IProject
Interface for querying Gradle project information.
Source : tooling/model/src/main/java/com/tom/rv2ide/tooling/api/IProject.kt:34
package com.tom.rv2ide.tooling.api
import com.tom.rv2ide.builder.model.DefaultProjectSyncIssues
import com.tom.rv2ide.tooling.api.models.BasicProjectMetadata
import java.util.concurrent.CompletableFuture
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest
interface IProject : IProjectQueries {
@JsonRequest
fun getProjects (): CompletableFuture < List < BasicProjectMetadata >>
@JsonRequest
fun getProjectSyncIssues (): CompletableFuture < DefaultProjectSyncIssues >
companion object {
const val PROJECT_UNKNOWN = "Unknown"
}
}
Server Initialization
Retrieve information about the tooling server:
import com.tom.rv2ide.tooling.api.IToolingApiServer
val toolingServer: IToolingApiServer = getToolingServer ()
toolingServer. metadata (). thenAccept { metadata ->
println ( "Tooling Server Version: ${ metadata.version } " )
println ( "API Version: ${ metadata.apiVersion } " )
}
The version of the tooling server
The API version supported
Initialize Project
Initialize the server with a project:
import com.tom.rv2ide.tooling.api.messages.InitializeProjectParams
import com.tom.rv2ide.tooling.api.messages.GradleDistributionParams
import java.io.File
val projectDir = File ( "/storage/emulated/0/MyApp" )
val params = InitializeProjectParams (). apply {
projectDir = projectDir.absolutePath
gradleDistribution = GradleDistributionParams (). apply {
version = "8.2.1"
// Or use local installation
// gradleHome = "/path/to/gradle"
}
}
toolingServer. initialize (params). thenAccept { result ->
if (result.isSuccessful) {
println ( "Project initialized successfully" )
} else {
println ( "Initialization failed: ${ result.error } " )
}
}
The absolute path to the Gradle project root directory
Configuration for which Gradle distribution to use
Check Initialization Status
toolingServer. isServerInitialized (). thenAccept { initialized ->
if (initialized) {
println ( "Server is ready" )
} else {
println ( "Server not initialized yet" )
}
}
Project Queries
Get Root Project
Retrieve the root project proxy:
toolingServer. getRootProject (). thenAccept { project ->
println ( "Root project obtained" )
// Query project information
project. getProjects (). thenAccept { projects ->
projects. forEach { metadata ->
println ( "Project: ${ metadata.name } " )
println ( " Path: ${ metadata.path } " )
println ( " Dir: ${ metadata.projectDir } " )
}
}
}
A proxy for querying Gradle project model information
Retrieve information about all projects:
val project: IProject = toolingServer. getRootProject (). get ()
project. getProjects (). thenAccept { projects ->
projects. forEach { metadata ->
println ( """
Project: ${ metadata.name }
Path: ${ metadata.path }
Description: ${ metadata.description ?: "None" }
Build File: ${ metadata.buildFile }
""" . trimIndent ())
}
}
The Gradle project path (e.g., “:app”)
The build.gradle or build.gradle.kts file
Optional project description
Get Sync Issues
Retrieve synchronization issues:
project. getProjectSyncIssues (). thenAccept { issues ->
if (issues.syncIssues. isEmpty ()) {
println ( "No sync issues" )
} else {
issues.syncIssues. forEach { issue ->
println ( "[ ${ issue.severity } ] ${ issue.message } " )
println ( " Type: ${ issue.type } " )
println ( " Data: ${ issue. data } " )
}
}
}
Task Execution
Execute Gradle Tasks
Run Gradle tasks:
import com.tom.rv2ide.tooling.api.messages.TaskExecutionMessage
val message = TaskExecutionMessage (). apply {
tasks = listOf ( "clean" , "assembleDebug" )
projectPath = ":app"
}
toolingServer. executeTasks (message). thenAccept { result ->
if (result.isSuccessful) {
println ( "Tasks completed successfully" )
println ( "Output: ${ result.output } " )
} else {
println ( "Task execution failed" )
println ( "Error: ${ result.error } " )
}
}
List of task names to execute (e.g., “clean”, “build”, “test”)
The Gradle project path (defaults to root project)
Execute with Arguments
Pass additional arguments to Gradle:
val message = TaskExecutionMessage (). apply {
tasks = listOf ( "build" )
args = listOf (
"--stacktrace" ,
"--info" ,
"-Pandroid.injected.build.api=30"
)
}
toolingServer. executeTasks (message). thenAccept { result ->
// Handle result
}
Additional command-line arguments for Gradle
Monitor Build Output
Listen for build output and progress:
import com.tom.rv2ide.tooling.api.IToolingApiClient
class BuildMonitor : IToolingApiClient {
override fun onOutput (message: LogMessageParams ) {
when (message.level) {
LogLevel.ERROR -> println ( "[ERROR] ${ message.message } " )
LogLevel.WARN -> println ( "[WARN] ${ message.message } " )
LogLevel.INFO -> println ( "[INFO] ${ message.message } " )
else -> println (message.message)
}
}
override fun onProgress (message: String ) {
println ( "Progress: $message " )
}
}
// Register client before executing tasks
val client = BuildMonitor ()
toolingServer. setClient (client)
Build Cancellation
Cancel Current Build
Stop a running build:
toolingServer. cancelCurrentBuild (). thenAccept { result ->
if (result.isSuccessful) {
println ( "Build cancelled successfully" )
} else {
println ( "Failed to cancel build: ${ result.message } " )
}
}
Build cancellation is asynchronous and may take time to complete. The build may finish before cancellation takes effect.
Task Execution Results
Handle Results
Process task execution results:
toolingServer. executeTasks (message). thenAccept { result ->
println ( "Success: ${ result.isSuccessful } " )
println ( "Duration: ${ result.executionTimeMs } ms" )
if (result.isSuccessful) {
println ( "Build output:" )
println (result.output)
} else {
println ( "Build failed:" )
println (result.error)
result.failureReasons?. forEach { reason ->
println ( " - $reason " )
}
}
}
Whether the tasks completed successfully
Standard output from the build
Error output if the build failed
Duration of task execution in milliseconds
List of failure reasons if applicable
Common Tasks
Build Project
fun buildProject (variant: String = "Debug" ) {
val message = TaskExecutionMessage (). apply {
tasks = listOf ( "assemble $variant " )
}
toolingServer. executeTasks (message). thenAccept { result ->
if (result.isSuccessful) {
println ( "Build successful" )
}
}
}
Clean Project
fun cleanProject () {
val message = TaskExecutionMessage (). apply {
tasks = listOf ( "clean" )
}
toolingServer. executeTasks (message). thenAccept { result ->
println ( "Clean completed" )
}
}
Run Tests
fun runTests () {
val message = TaskExecutionMessage (). apply {
tasks = listOf ( "test" )
args = listOf ( "--info" )
}
toolingServer. executeTasks (message). thenAccept { result ->
if (result.isSuccessful) {
println ( "All tests passed" )
} else {
println ( "Tests failed: ${ result.error } " )
}
}
}
Install APK
fun installDebugApk () {
val message = TaskExecutionMessage (). apply {
tasks = listOf ( "installDebug" )
projectPath = ":app"
}
toolingServer. executeTasks (message). thenAccept { result ->
if (result.isSuccessful) {
println ( "APK installed successfully" )
}
}
}
Lifecycle Management
Shutdown Server
Cleanly shutdown the tooling server:
toolingServer. shutdown (). thenAccept {
println ( "Tooling server shut down" )
}
Always call shutdown() when closing a project to release Gradle daemon connections and resources.
Complete Example
Here’s a complete example demonstrating tooling API usage:
import com.tom.rv2ide.tooling.api. *
import com.tom.rv2ide.tooling.api.messages. *
import java.io.File
class GradleBuildManager ( private val toolingServer: IToolingApiServer ) {
suspend fun initializeAndBuild (projectPath: String ) {
// 1. Initialize project
val initParams = InitializeProjectParams (). apply {
projectDir = projectPath
gradleDistribution = GradleDistributionParams (). apply {
version = "8.2.1"
}
}
val initResult = toolingServer. initialize (initParams). get ()
if ( ! initResult.isSuccessful) {
println ( "Failed to initialize: ${ initResult.error } " )
return
}
println ( "Project initialized" )
// 2. Get project information
val project = toolingServer. getRootProject (). get ()
val projects = project. getProjects (). get ()
println ( "Projects in workspace:" )
projects. forEach { metadata ->
println ( " - ${ metadata.name } ( ${ metadata.path } )" )
}
// 3. Check for sync issues
val syncIssues = project. getProjectSyncIssues (). get ()
if (syncIssues.syncIssues. isNotEmpty ()) {
println ( "Warning: Found sync issues:" )
syncIssues.syncIssues. forEach { issue ->
println ( " [ ${ issue.severity } ] ${ issue.message } " )
}
}
// 4. Build the project
println ( "Starting build..." )
val buildMessage = TaskExecutionMessage (). apply {
tasks = listOf ( "assembleDebug" )
args = listOf ( "--stacktrace" )
}
val buildResult = toolingServer. executeTasks (buildMessage). get ()
if (buildResult.isSuccessful) {
println ( "Build completed in ${ buildResult.executionTimeMs } ms" )
} else {
println ( "Build failed:" )
println (buildResult.error)
}
}
fun cleanup () {
toolingServer. shutdown ()
}
}
Error Handling
Handle Async Errors
toolingServer. executeTasks (message)
. exceptionally { throwable ->
println ( "Task execution error: ${ throwable.message } " )
throwable. printStackTrace ()
null
}
. thenAccept { result ->
if (result != null ) {
// Process result
}
}
Timeout Handling
import java.util.concurrent.TimeUnit
try {
val result = toolingServer. executeTasks (message)
. get ( 5 , TimeUnit.MINUTES)
// Process result
} catch (e: TimeoutException ) {
println ( "Build timed out after 5 minutes" )
toolingServer. cancelCurrentBuild ()
}
Project API Access project and workspace information
Action System Create build action menu items