Flutter
More ▾
The Flutter plugin renders Essence 2 and Expression 2 on Android phones, inside a Flutter app.
One Flutter dependency gives your app an avatar widget. On Android the plugin runs the same engines as the Android SDK, so the avatar renders on the phone: 16 kHz mono speech goes in, and a lip-synced picture comes out as a Flutter Texture.
| Platform | What the plugin does |
|---|---|
| Android (arm64-v8a, a physical device) | renders Essence 2 and Expression 2 on the phone; the engines resolve from Maven Central, and the example app builds from a clone |
| iOS (16 or newer) | builds from the published tag after the plugin’s bootstrap step. For an iPhone or iPad app that renders on the device, use the Swift package |
| macOS (13 or newer, Apple silicon) | builds from the published tag after the bootstrap step and two Homebrew libraries. For a Mac app, the Swift package is the documented path |
Before you start
| You need | Notes |
|---|---|
| Flutter 3 with the Android toolchain | JDK 17 and the Android SDK |
| A physical Android phone, arm64 | emulators cannot load the engines; Essence 2 needs Android 10 (API 29) or newer |
| An API secret | the Creator plan or higher |
Install
The plugin is published as a tag in the homebrew-bithuman repository. Pin it in pubspec.yaml:
dependencies:
bithuman:
git:
url: https://github.com/bithuman-product/homebrew-bithuman.git
path: packages/flutter-plugin
ref: flutter-plugin-v2.6.21
Then run flutter pub get. On Android, Gradle resolves ai.bithuman:essence2-android and ai.bithuman:expression2-android from Maven Central; nothing else to fetch.
For an iOS or macOS build, three more steps:
- Run the plugin’s
scripts/bootstrap.shonce. It downloads the published engines and checks their sha256. For a git dependency, the plugin’s folder ispackages/flutter-pluginunder~/.pub-cache/git/homebrew-bithuman-…. - Raise the deployment targets:
platform :ios, '16.0'inios/Podfile,platform :osx, '13.0'inmacos/Podfile, and the Runner targets to match. - On macOS only:
brew install llama.cpp onnxruntime. The plugin links both.
Authenticate
The engines check your API secret when an avatar loads: pass it to BithumanAvatar.load(…, apiSecret:). The example app asks for it on first launch and keeps it in the Android Keystore, or you can pass --dart-define=BITHUMAN_API_SECRET=… when you build. A shipped app holds the secret on the device, so give each app its own secret that you can rotate or revoke (API secrets).
Credits pay for active session time, talking or idle, billed to the second (pricing).
First frame
Build the example app for your phone, with the wise-pup sample avatar:
git clone https://github.com/bithuman-product/bithuman-examples.git
cd bithuman-examples/app/avatar_chat
flutter pub get
flutter run --release --dart-define=AGENT_CODE=A23WJF0199
Expected result
The app installs on the connected phone, asks for your API secret once, downloads the avatar (about 160 MB, first run only) and shows it idling full screen. Speak, or type a line, and it answers with its lips in sync.
Complete example
The avatar_chat app is a complete voice conversation with idle motion and interruption, in one layout for every platform. From plugin 2.6.20 its voice session connects through bitHuman’s realtime relay with your API secret; no token is minted.
Integrate into your app
The avatar is a Texture in your widget tree. On Android the first argument to load is the agent code:
// excerpt: app/avatar_chat/lib/main.dart (bithuman-examples)
import 'package:bithuman/bithuman.dart';
await BithumanAvatar.setExpression2AgentDir('A23WJF0199');
final avatar = await BithumanAvatar.load('A23WJF0199', engine: 'expression2', apiSecret: secret);
Texture(textureId: avatar.textureId); // the avatar in your layout
avatar.pushAudio(pcm); // Int16List, 16 kHz mono speech
avatar.interrupt(); // cut the current reply
await avatar.dispose(); // release the engine
| Job | Call |
|---|---|
| Show the avatar | Texture(textureId: avatar.textureId); frameWidth and frameHeight give its size |
| Stream speech | pushAudio(Int16List), 16 kHz mono |
| Know it is ready | isReady; audio pushed before it is dropped |
| Interrupt the reply | interrupt() |
| Stop | dispose() |
| Pick the model | engine: 'expression2' or engine: 'essence2' |
Platform notes
- Two models in one app:
essence2-androidneedsminSdk 29; raise the app to 29. - Your own voice pipeline: any speech your stack produces works, as 16 kHz mono PCM through
pushAudio. - Versions: each plugin tag fixes the Android SDK versions it uses. The current tag and its line are on Downloads & versions.
Performance
The plugin runs the Android SDK’s own engines (the same native libraries), so the Android rows apply:
| Configuration | Essence 2 | Expression 2 |
|---|---|---|
| Samsung Galaxy S25+ Android | 2.0× real timeSamsung Galaxy S25+ · essence2-android 0.7.0 · measured 2026-09-25 | 2.4× real timeSamsung Galaxy S25+ · expression2-android 0.4.10 · measured 2026-09-23 |
| Samsung Galaxy S25+ Android held 10 min | 1.4× real timeSamsung Galaxy S25+ · essence2-android 0.8.1 · held 10 min · measured 2026-09-27 | 2.2× real timeSamsung Galaxy S25+ · expression2-android 0.5.2 · held 10 min · measured 2026-09-27 |
Times real time: seconds of avatar video rendered per second. At 1.0× or more, an avatar holds a live conversation. Select a figure for its release and date. All configurations and how we measure.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
UnsatisfiedLinkError on an emulator | the engines are arm64-v8a only | run on a physical arm64 phone |
| The app shows a refusal and asks for a secret | no API secret, or a rejected one | enter a valid secret, or build with --dart-define=BITHUMAN_API_SECRET=… |
Manifest merge fails on minSdk | Essence 2 needs minSdk 29 | raise the app to 29 |
pod install fails on iOS or macOS | the deployment target is below iOS 16 or macOS 13 | raise the Podfile platform and the Runner targets |
| The iOS or macOS build cannot find the engines | the bootstrap step was skipped | run scripts/bootstrap.sh in the plugin’s folder, then build again |
A macOS link error names llama or onnxruntime | the Homebrew libraries are missing | brew install llama.cpp onnxruntime |
Reference
- Android: the engines under the plugin, their API and their settings.
avatar_chatexample and the plugin source.- Changelog and Downloads & versions.