A Rust library for controlling Android Emulators via gRPC.
- Discover Emulator AVDs: List available Android Virtual Devices
- Spawn Emulators: Configure and start emulator instances programmatically
- Find Running Emulators: Locate existing emulator instances via ADB protocol
- gRPC Control: Full bindings to the Android Emulator gRPC controller API
- Authentication Support: No auth, Basic Auth, and JWT authentication for gRPC
- Export Limited JWT Tokens: Export JWT tokens that can temporarily grant other tools / clients limited access to the emulator.
#[tokio::main]
async fn main() {
let avds = android_emulator::list_avds().await.expect("Failed to list AVDs");
println!("Available AVDs: {:?}", avds);
}use android_emulator::{EmulatorConfig, list_avds};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Get the first available AVD
let avds = list_avds().await?;
let avd_name = avds.first().ok_or("No AVDs found")?;
let config = EmulatorConfig::new(avd_name)
.with_window(false)
.with_snapshot_load(false)
.with_snapshot_save(false)
.with_boot_animation(false);
let instance = config.spawn().await?;
// Connect to the emulator
let mut client = instance.connect(Some(Duration::from_secs(120)), true).await?;
// Wait until the emulator is fully booted
let elapsed = client.wait_until_booted(Duration::from_secs(200), None).await?;
println!("Emulator ready at: {}", instance.grpc_endpoint());
println!("Booted in {:.1} seconds", elapsed.as_secs_f64());
Ok(())
}Find an existing emulator instance that's running a particular AVD and connect to it:
use android_emulator::{list_avds, list_emulators};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Get the first available AVD
let avds = list_avds().await?;
let avd_id = avds.first().ok_or("No AVDs found")?;
// Find a running emulator with that AVD
let emulators = list_emulators().await?;
let instance = emulators
.into_iter()
.find(|e| e.avd_id().unwrap_or_default() == avd_id)
.ok_or("No running emulator found")?;
println!("Found emulator: {}", instance.serial());
println!("gRPC endpoint: {}", instance.grpc_endpoint());
// Connect to the emulator
let mut client = instance.connect(Some(Duration::from_secs(30)), true).await?;
// Use the client...
Ok(())
}use android_emulator::{EmulatorConfig, list_avds};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Get the first available AVD
let avds = list_avds().await?;
let avd_name = avds.first().ok_or("No AVDs found")?;
// Start the emulator
let instance = EmulatorConfig::new(avd_name)
.with_window(false)
.spawn()
.await?;
let mut client = instance.connect(Some(Duration::from_secs(120)), true).await?;
// Get emulator status
let status = client.protocol_mut().get_status(()).await?.into_inner();
println!("Emulator status: {:?}", status);
// Set GPS coordinates
let gps_state = android_emulator::proto::GpsState {
latitude: 37.7749,
longitude: -122.4194,
..Default::default()
};
client.protocol_mut().set_gps(gps_state).await?;
Ok(())
}use android_emulator::{EmulatorConfig, list_avds};
use android_emulator::proto::{Touch, TouchEvent};
use std::time::Duration;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Get the first available AVD
let avds = list_avds().await?;
let avd_name = avds.first().ok_or("No AVDs found")?;
// Start the emulator
let instance = EmulatorConfig::new(avd_name)
.with_window(false)
.spawn()
.await?;
let mut client = instance.connect(Some(Duration::from_secs(120)), true).await?;
let touch = Touch {
x: 500,
y: 1000,
identifier: 1,
pressure: 100,
..Default::default()
};
let touch_event = TouchEvent {
touches: vec![touch],
display: 0,
};
client.protocol_mut().send_touch(touch_event).await?;
Ok(())
}The library depends on finding an Android SDK installation in order to be able to spawn new emulators and will look for the Android SDK as follows:
ANDROID_HOMEenvironment variableANDROID_SDK_ROOTenvironment variable (deprecated)- Platform-specific default locations:
- Linux:
$HOME/Android/sdkor$HOME/Android/Sdk - macOS:
$HOME/Library/Android/sdk - Windows:
%LOCALAPPDATA%/Android/Sdk
- Linux:
Emulator AVDs: At least one Android Virtual Device must be created
The library provides complete bindings to the Android Emulator Controller gRPC API, including:
- Sensor control (accelerometer, GPS, etc.)
- Physical model control (rotation, position, etc.)
- Battery state management
- Screenshot and screen streaming
- Audio streaming
- Touch, mouse, and keyboard input
- Phone calls and SMS
- VM state management
- Display configuration
- And more...
This crate includes pre-generated protobuf bindings, so consumers don't need protoc installed.
If you modify the .proto files, regenerate the bindings by running:
cargo xtask codegenThis will update android-emulator/src/generated/android.emulation.control.rs.
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or https://opensource.org/license/mit)
at your option.