A production-ready reference app demonstrating the RunAnywhere Kotlin SDK capabilities for on-device AI. This app showcases how to build privacy-first, offline-capable AI features with LLM chat, speech-to-text, text-to-speech, and a complete voice assistant pipelineβall running locally on your device.
Important: This sample app consumes the RunAnywhere Kotlin SDK as a local Gradle included build. Before opening this project, you must first build the SDKβs native libraries.
# 1. Navigate to the Kotlin SDK directory
cd runanywhere-sdks/sdk/runanywhere-kotlin
# 2. Run the setup script (~10-15 minutes on first run)
# This builds the native C++ JNI libraries and sets testLocal=true
./scripts/build-kotlin.sh --setup
# 3. Open this sample app in Android Studio
# File > Open > examples/android/RunAnywhereAI
# 4. Wait for Gradle sync to complete
# 5. Connect an Android device (ARM64 recommended) or use an emulator
# 6. Click Run
This sample app uses settings.gradle.kts with includeBuild() to reference the local Kotlin SDK:
This Sample App β Local Kotlin SDK (sdk/runanywhere-kotlin/)
β
Local JNI Libraries (sdk/runanywhere-kotlin/src/androidMain/jniLibs/)
β
Built by: ./scripts/build-kotlin.sh --setup
The build-kotlin.sh --setup script:
runanywhere-commons.so files to sdk/runanywhere-kotlin/src/androidMain/jniLibs/runanywhere.testLocal=true in gradle.properties./gradlew assembleDebugrunanywhere-commons):
cd sdk/runanywhere-kotlin
./scripts/build-kotlin.sh --local --rebuild-commons
Download the app from Google Play Store to try it out.
This sample app demonstrates the full power of the RunAnywhere SDK:
| Feature | Description | SDK Integration |
|---|---|---|
| AI Chat | Interactive LLM conversations with streaming responses | RunAnywhere.generateStream() |
| Thinking Mode | Support for models with <think>...</think> reasoning |
Thinking tag parsing |
| Real-time Analytics | Token speed, generation time, inference metrics | MessageAnalytics |
| Speech-to-Text | Voice transcription with batch & live modes | RunAnywhere.transcribe() |
| Text-to-Speech | Neural voice synthesis with Piper TTS | RunAnywhere.synthesize() |
| Voice Assistant | Full STT -> LLM -> TTS pipeline with auto-detection | RunAnywhere.processVoice() |
| Model Management | Download, load, and manage multiple AI models | RunAnywhere.downloadModel() |
| Storage Management | View storage usage and delete models | RunAnywhere.storageInfo() |
| Offline Support | All features work without internet | On-device inference |
The app follows modern Android architecture patterns:
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Jetpack Compose UI β
β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββ β
β β Chat β β STT β β TTS β β Voice β βSettingsβ β
β β Screen β β Screen β β Screen β β Screen β β Screen β β
β ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ βββββ¬βββββ β
βββββββββΌβββββββββββββΌβββββββββββββΌβββββββββββββΌββββββββββββΌβββββββ€
β βΌ βΌ βΌ βΌ βΌ β
β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββ β
β β Chat β β STT β β TTS β β Voice β βSettingsβ β
β βViewModel β βViewModel β βViewModel β βViewModel β βViewModelβ
β ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ βββββ¬βββββ β
βββββββββ΄βββββββββββββ΄βββββββββββββ΄βββββββββββββ΄ββββββββββββ΄βββββββ€
β β
β RunAnywhere Kotlin SDK β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Extension Functions (generate, transcribe, synthesize) β β
β β EventBus (LLMEvent, STTEvent, TTSEvent, ModelEvent) β β
β β Model Management (download, load, unload, delete) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββ΄βββββββββββββββββββ β
β βΌ βΌ β
β βββββββββββββββββββ βββββββββββββββββββ β
β β LlamaCpp β β ONNX Runtime β β
β β (LLM/GGUF) β β (STT/TTS) β β
β βββββββββββββββββββ βββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
StateFlow, Compose observes changesEventBus.eventsConversationStore persists chat historyRunAnywhereAI/
βββ app/
β βββ src/main/
β β βββ java/com/runanywhere/runanywhereai/
β β β βββ RunAnywhereApplication.kt # SDK initialization, model registration
β β β βββ MainActivity.kt # Entry point, initialization state handling
β β β β
β β β βββ data/
β β β β βββ ConversationStore.kt # Chat history persistence
β β β β
β β β βββ domain/
β β β β βββ models/
β β β β β βββ ChatMessage.kt # Message data model with analytics
β β β β β βββ SessionState.kt # Voice session states
β β β β βββ services/
β β β β βββ AudioCaptureService.kt # Microphone audio capture
β β β β
β β β βββ presentation/
β β β β βββ chat/
β β β β β βββ ChatScreen.kt # LLM chat UI with streaming
β β β β β βββ ChatViewModel.kt # Chat logic, thinking mode
β β β β β βββ components/
β β β β β βββ MessageInput.kt # Chat input component
β β β β β
β β β β βββ stt/
β β β β β βββ SpeechToTextScreen.kt # STT UI with waveform
β β β β β βββ SpeechToTextViewModel.kt # Batch & live transcription
β β β β β
β β β β βββ tts/
β β β β β βββ TextToSpeechScreen.kt # TTS UI with playback
β β β β β βββ TextToSpeechViewModel.kt # Synthesis & audio playback
β β β β β
β β β β βββ voice/
β β β β β βββ VoiceAssistantScreen.kt # Full voice pipeline UI
β β β β β βββ VoiceAssistantViewModel.kt # STTβLLMβTTS orchestration
β β β β β
β β β β βββ settings/
β β β β β βββ SettingsScreen.kt # Storage & model management
β β β β β βββ SettingsViewModel.kt # Storage info, cache clearing
β β β β β
β β β β βββ models/
β β β β β βββ ModelSelectionBottomSheet.kt # Model picker UI
β β β β β βββ ModelSelectionViewModel.kt # Download & load logic
β β β β β
β β β β βββ navigation/
β β β β β βββ AppNavigation.kt # Bottom nav, routing
β β β β β
β β β β βββ common/
β β β β βββ InitializationViews.kt # Loading/error states
β β β β
β β β βββ ui/theme/
β β β βββ Theme.kt # Material 3 theming
β β β βββ AppColors.kt # Color palette
β β β βββ Type.kt # Typography
β β β βββ Dimensions.kt # Spacing constants
β β β
β β βββ res/ # Resources (icons, strings)
β β βββ AndroidManifest.xml # Permissions, app config
β β
β βββ src/test/ # Unit tests
β βββ src/androidTest/ # Instrumentation tests
β
βββ build.gradle.kts # Project build config
βββ settings.gradle.kts # Module settings
βββ README.md # This file
# Clone the repository
git clone https://github.com/RunanywhereAI/runanywhere-sdks.git
cd runanywhere-sdks/examples/android/RunAnywhereAI
# Build debug APK
./gradlew assembleDebug
# Install on connected device
./gradlew installDebug
Shift + F10# Install and launch
./gradlew installDebug
adb shell am start -n com.runanywhere.runanywhereai.debug/.MainActivity
The SDK is initialized in RunAnywhereApplication.kt:
// Initialize SDK with development environment
RunAnywhere.initialize(environment = SDKEnvironment.DEVELOPMENT)
// Complete services initialization (device registration)
RunAnywhere.completeServicesInitialization()
// Register AI backends
LlamaCPP.register(priority = 100) // LLM backend (GGUF models)
ONNX.register(priority = 100) // STT/TTS backend
// Register models
RunAnywhere.registerModel(
id = "smollm2-360m-q8_0",
name = "SmolLM2 360M Q8_0",
url = "https://huggingface.co/prithivMLmods/SmolLM2-360M-GGUF/...",
framework = InferenceFramework.LLAMA_CPP,
memoryRequirement = 500_000_000,
)
// Download with progress tracking
RunAnywhere.downloadModel("smollm2-360m-q8_0").collect { progress ->
println("Download: ${(progress.progress * 100).toInt()}%")
}
// Load into memory
RunAnywhere.loadLLMModel("smollm2-360m-q8_0")
// Generate with streaming
RunAnywhere.generateStream(prompt).collect { token ->
// Display token in real-time
displayToken(token)
}
// Or non-streaming
val result = RunAnywhere.generate(prompt)
println("Response: ${result.text}")
// Load STT model
RunAnywhere.loadSTTModel("sherpa-onnx-whisper-tiny.en")
// Transcribe audio bytes
val transcription = RunAnywhere.transcribe(audioBytes)
println("Transcription: $transcription")
// Load TTS voice
RunAnywhere.loadTTSVoice("vits-piper-en_US-lessac-medium")
// Synthesize speech
val result = RunAnywhere.synthesize(text, TTSOptions(
rate = 1.0f,
pitch = 1.0f,
))
// result.audioData contains WAV audio bytes
// Process voice through full pipeline
val result = RunAnywhere.processVoice(audioData)
if (result.speechDetected) {
println("User said: ${result.transcription}")
println("AI response: ${result.response}")
// result.synthesizedAudio contains TTS audio
}
ChatScreen.kt)What it demonstrates:
<think>...</think> tags)Key SDK APIs:
RunAnywhere.generateStream() β Streaming generationRunAnywhere.generate() β Non-streaming generationRunAnywhere.cancelGeneration() β Stop generationEventBus.events.filterIsInstance<LLMEvent>() β Listen for LLM eventsSpeechToTextScreen.kt)What it demonstrates:
Key SDK APIs:
RunAnywhere.loadSTTModel() β Load Whisper modelRunAnywhere.transcribe() β Batch transcriptionRunAnywhere.transcribeStream() β Streaming transcriptionTextToSpeechScreen.kt)What it demonstrates:
Key SDK APIs:
RunAnywhere.loadTTSVoice() β Load TTS modelRunAnywhere.synthesize() β Generate speech audioRunAnywhere.stopSynthesis() β Cancel synthesisVoiceAssistantScreen.kt)What it demonstrates:
Key SDK APIs:
RunAnywhere.startVoiceSession() β Start voice sessionRunAnywhere.processVoice() β Process audio through pipelineRunAnywhere.voiceAgentComponentStates() β Check component statusSettingsScreen.kt)What it demonstrates:
Key SDK APIs:
RunAnywhere.storageInfo() β Get storage detailsRunAnywhere.deleteModel() β Remove downloaded modelRunAnywhere.clearCache() β Clear temporary files./gradlew test
./gradlew connectedAndroidTest
# Detekt static analysis
./gradlew detekt
# ktlint formatting check
./gradlew ktlintCheck
# Android lint
./gradlew lint
Filter logcat for RunAnywhere SDK logs:
adb logcat -s "RunAnywhere:D" "RunAnywhereApp:D" "ChatViewModel:D"
| Tag | Description |
|---|---|
RunAnywhereApp |
SDK initialization, model registration |
ChatViewModel |
LLM generation, streaming |
STTViewModel |
Speech transcription |
TTSViewModel |
Speech synthesis |
VoiceAssistantVM |
Voice pipeline |
ModelSelectionVM |
Model downloads, loading |
| Variant | Description |
|---|---|
debug |
Development build with debugging enabled |
release |
Optimized build with R8/ProGuard |
benchmark |
Release-like build for performance testing |
export KEYSTORE_PATH=/path/to/keystore.jks
export KEYSTORE_PASSWORD=your_password
export KEY_ALIAS=your_alias
export KEY_PASSWORD=your_key_password
| Model | Size | Memory | Description |
|---|---|---|---|
| SmolLM2 360M Q8_0 | ~400MB | 500MB | Fast, lightweight chat |
| Qwen 2.5 0.5B Q6_K | ~500MB | 600MB | Multilingual, efficient |
| LFM2 350M Q4_K_M | ~200MB | 250MB | LiquidAI, ultra-compact |
| Llama 2 7B Chat Q4_K_M | ~4GB | 4GB | Powerful, larger model |
| Mistral 7B Instruct Q4_K_M | ~4GB | 4GB | High quality responses |
| Model | Size | Description |
|---|---|---|
| Sherpa Whisper Tiny (EN) | ~75MB | English transcription |
| Model | Size | Description |
|---|---|---|
| Piper US English (Medium) | ~65MB | Natural American voice |
| Piper British English (Medium) | ~65MB | British accent |
arm64-v8a only (x86 emulators not supported)See CONTRIBUTING.md for guidelines.
# Fork and clone
git clone https://github.com/YOUR_USERNAME/runanywhere-sdks.git
cd runanywhere-sdks/examples/android/RunAnywhereAI
# Create feature branch
git checkout -b feature/your-feature
# Make changes and test
./gradlew assembleDebug
./gradlew test
./gradlew detekt ktlintCheck
# Commit and push
git commit -m "feat: your feature description"
git push origin feature/your-feature
# Open Pull Request
This project is licensed under the Apache License 2.0 - see LICENSE for details.