Kotlin / Android — Hello, avatar
Render an on-device AI avatar on Android in ~20 lines of Kotlin — Maven Central AAR, arm64-v8a, fully private lip-sync.
Prerequisites
- A bitHuman API secret — get one at Developer → API Keys; see Authentication. Read it from env or your app config at startup; never hardcode it.
- Android Studio with NDK 28.0.13004108 and compile SDK 35. Add the dependency:
implementation("ai.bithuman:sdk:1.17.1") // Maven Central
- Device floor: an
arm64-v8adevice (physical phone or arm64 emulator image), Android 10+ (API 29+). Inference is fully on-device — no cloud round-trip. - A
.imxmodel file pushed to the device (the snippet reads fromgetExternalFilesDir(null)).
Note The Android / Kotlin SDK is in Beta. The API surface below is stable enough to build on, but expect minor changes ahead of GA. There is no standalone Android project under
Examples/yet — this snippet is the canonical starting point; track the Android SDK page for updates.
Run it
- In
app/build.gradle.kts, restrict toarm64-v8aand add the dependency.
android {
defaultConfig {
ndk { abiFilters += setOf("arm64-v8a") }
minSdk = 29
}
}
dependencies {
implementation("ai.bithuman:sdk:1.17.1") // Maven Central
}
- Push your model and audio onto the device’s app-private external dir (or adapt the paths in the code).
adb push sample-avatar.imx /sdcard/Android/data/com.example.bithumanhello/files/
adb push speech.wav /sdcard/Android/data/com.example.bithumanhello/files/
- Drop the Full code into
MainActivity.kt, then Build and Run on the device.
What you’ll see
A full-screen ImageView shows the avatar lip-syncing to speech.wav — 16 kHz mono PCM in, lip-synced Bitmaps out at 25 fps, rendered entirely on the phone with no network inference.
Full code
// MainActivity.kt — load model, compose frames, display them
package com.example.bithumanhello
import android.app.Activity
import android.os.Bundle
import android.widget.ImageView
import ai.bithuman.sdk.Avatar
import java.io.File
class MainActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val imageView = ImageView(this).also { setContentView(it) }
// Read .imx + WAV from app-private external files dir.
val dir = getExternalFilesDir(null)!!
val model = File(dir, "sample-avatar.imx").absolutePath
val audio = File(dir, "speech.wav").absolutePath
// Compose runs off the main thread; each Bitmap is a 25 fps frame.
Thread {
Avatar.load(model).use { avatar ->
avatar.composeFromFile(audio).forEach { frame ->
runOnUiThread { imageView.setImageBitmap(frame.toBitmap()) }
}
}
}.start()
}
}
Full source: Android SDK reference — no standalone Examples/ project yet; the SDK page carries the canonical streaming snippets.
Next steps
- Android SDK — full walkthrough: API surface, streaming,
Fixture+Runtime. - Audio streaming — the streaming contract that backs
composeFromFile. - Models — Essence vs Expression, which to ship.