Skip to main content
Follow these best practices to build high-quality AI-powered Flutter apps.
Reference Implementation: The Flutter Starter Example demonstrates all these best practices in a production-ready app.

Model Selection

Choose the right model size for your use case:
Start small — Use the smallest model that meets your quality needs. You can always upgrade later.

Memory Management

Unload Unused Models

Check Available Memory

Clean Up Old Models

Streaming for Better UX

Always prefer streaming for chat interfaces:

Preload Models

Load models during idle time, not when user needs them:

Error Handling

Always handle errors gracefully:

Test on Physical Devices

Always test on real devices — Emulators are significantly slower for AI inference. Performance you see in emulators is not representative of real-world usage.
  • iOS Simulator: 5-10x slower than device
  • Android Emulator: 3-5x slower than device

Download Management

Show Progress

Download on WiFi

Voice Assistant Tips

Optimize Latency

Handle Background/Foreground

Performance Monitoring

Track performance metrics:

Flutter Platform Gotchas

iOS: Static Linkage is Critical

The Podfile must use use_frameworks! :linkage => :static. Without it, RACommons symbols from vendored xcframeworks won’t link properly and you’ll get runtime crashes.

iOS: Permission Preprocessor Macros

The permission_handler_apple pod requires preprocessor definitions to enable permissions. Without PERMISSION_MICROPHONE=1 and PERMISSION_SPEECH_RECOGNIZER=1, permission requests will silently fail at runtime:

TTS: WAV File Construction Required

RunAnywhere.synthesize() returns raw Float32List samples, not a playable audio file. You must manually construct a WAV header and convert Float32 to Int16 PCM, then save to a temp file for playback:
iOS AVPlayer requires a proper file extension (.wav) and WAV header — it cannot play raw PCM bytes.

Audio Format for STT

The record package must be configured with AudioEncoder.pcm16bits, sampleRate: 16000, numChannels: 1. RunAnywhere.transcribe() expects raw PCM16 Uint8List data at 16kHz mono. Minimum data threshold: ~1600 bytes (~0.1s).

Tool Calling Uses RunAnywhereTools

Tool registration and generation with tools uses the RunAnywhereTools class, not RunAnywhere:

Model Downloaded Check

To check if a model is already downloaded, query RunAnywhere.availableModels() and check if the matching model’s localPath is non-null. There is no direct isDownloaded(id) API.

Gradle JVM Memory

Android builds may require higher JVM memory allocation (-Xmx8G) due to native SDK compilation requirements.

Summary Checklist

  • Test on physical devices (iOS and Android)
  • Handle all error cases with user-friendly messages
  • Implement download progress UI
  • Add WiFi check for large downloads
  • Test with slow network conditions
  • Use smallest adequate model size - [ ] Preload models during idle time - [ ] Use streaming for chat interfaces - [ ] Unload unused models - [ ] Monitor memory usage
  • Show loading states clearly
  • Provide cancel option for long operations
  • Handle background/foreground transitions
  • Save conversation history locally
  • Allow model selection for power users

See Also

Configuration

SDK configuration

Error Handling

Handle errors gracefully