| title | App Setup |
|---|---|
| icon | mobile |
| description | Set up the Omi Flutter app for development. Build automatically against the local backend harness, or manually with your own. |
There are two ways to set up the Omi app for development:
**Recommended for most developers**One command setup against the local backend harness
Full control over configuration and backend
Before starting, make sure you have the following installed:
Includes Dart - the core framework Required for iOS development Required for Android development iOS dependency manager You'll also need [NDK](https://developer.android.com/ndk/downloads) to build Opus for ARM devices. The local backend harness additionally needs **Python 3.11** (not 3.12+ — the backend pins 3.11), a **Java runtime** for the Firestore emulator, and **firebase-tools** (or `npx`). `make dev-up` names any of these that are missing.This is the recommended way to get started. setup.sh builds the dev flavor
against the local backend harness — the Python API on port 8000 and the
Firebase Auth emulator on port 9099, using the demo-omi-local Firebase
project. iOS builds address them as 127.0.0.1; Android builds default to the
emulator's host alias 10.0.2.2.
Do not point this build at https://api.omiapi.com/. That API verifies Firebase
ID tokens against Omi's production Firebase project, and Firebase tokens are
project-scoped, so a demo-omi-local token is rejected with 401 Unauthorized
on every call — sign-in appears to succeed and nothing else works. Production
data requires the explicit beta profile (see Mobile beta).
```bash
make dev-init # once: creates backend/.venv and copies the env template
make dev-up # starts the Firestore + Auth emulators and the Python API
```
`make dev-init` builds `backend/.venv` from whatever `python3` resolves to,
and the backend requires **Python 3.11** — make sure that's what you get, or
the harness fails later with import errors.
No provider API keys? Use fake providers instead:
```bash
PROVIDER_MODE=offline make dev-up
```
Check what came up with `make dev-status`, and stop it later with
`make dev-down`. Ports, seeded local users, and troubleshooting live in the
[local emulator runbook](https://github.com/BasedHardware/omi/blob/main/backend/docs/runbooks/local-emulator-manual-qa.md).
Or run from terminal:
```bash
flutter run --flavor dev
```
Manual setup gives you full control, allowing you to use your own backend.
Ensure Flutter is installed by following the official [Flutter Installation Guide](https://docs.flutter.dev/get-started/install).Verify your setup:
```bash
flutter doctor -v
```
<AccordionGroup>
<Accordion title="Example output" icon="terminal">
```
[✓] Flutter (Channel stable, 3.44.5, on macOS 15.4.1)
[✓] Android toolchain - develop for Android devices (Android SDK version 36.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 16.4)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2025.1)
[✓] VS Code (version 1.101.0)
[✓] Connected device (4 available)
[✓] Network resources
```
</Accordion>
<Accordion title="Recommended versions" icon="info-circle">
This project is tested with specific tool versions. See [`app/setup.sh`](https://github.com/BasedHardware/omi/blob/main/app/setup.sh) for recommended versions:
- Flutter 3.44.5
- Xcode 16.4
- Android SDK Platform 35
- NDK 28.2.13676358
- JDK 21
To set a specific JDK on macOS:
```bash
flutter config --jdk-dir /Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home
```
</Accordion>
</AccordionGroup>
| Key | Description |
|-----|-------------|
| `API_BASE_URL` | Your backend URL — `http://127.0.0.1:8000/` for the local harness, or [set up your own](/doc/developer/backend/Backend_Setup) |
| `GOOGLE_MAPS_API_KEY` | Optional - for location features |
<Warning>
Be sure to include the trailing `/` in `API_BASE_URL` or you'll get malformed URLs. If you change this later, delete the builds folder and recreate the runner.
</Warning>
<Warning>
Whatever backend you point at must verify Firebase ID tokens against the
**same Firebase project** the app signs into. Tokens are project-scoped, so a
mismatch returns **401 Unauthorized** on every authenticated call while
sign-in still appears to succeed. Omi's shared `https://api.omiapi.com/`
verifies against the production project and will reject tokens from the
`demo-omi-local` emulator or from your own Firebase project.
</Warning>
<Warning>
`setup.sh` installs **local emulator Firebase configs** (the `demo-omi-local`
project) for the `dev` flavor. If you're using the local backend harness (the
common case), they're already in place — skip to the next step. These configs
only work against the Firebase Auth emulator; they are not credentials for
any hosted Firebase project.
**Never run `flutterfire configure`** against Omi's bundle IDs — it overwrites the prebuilt prod credentials in `app/ios/Config/Prod/`, `app/lib/firebase_options_prod.dart`, and `app/android/app/src/prod/`.
</Warning>
If you need your **own** Firebase project (custom backend):
1. Follow the official [Firebase Flutter Setup](https://firebase.google.com/docs/flutter/setup) through Step 1
2. For Apple login, [create an identifier](https://developer.apple.com/account/resources/identifiers/list) first
3. Configure `flutterfire config` using **your own** bundle IDs and **your own** project — not Omi's
4. Generate SHA1/SHA256 keys for your keystore and add them to Firebase ([StackOverflow guide](https://stackoverflow.com/a/56091158) | [Official Docs](https://support.google.com/firebase/answer/9137403?hl=en))
<Tip>
If you're facing auth issues, enable Google/Apple sign-in in the Firebase Console under **Authentication → Sign-in method**.
</Tip>
To build an APK:
```bash
flutter build apk --flavor dev
```
We use dart format with a line length of 120 characters.
To automatically format code on commit, install the pre-commit hook:
# From the root of the repository
ln -s -f ../../scripts/pre-commit .git/hooks/pre-commit- Run `flutter doctor -v` for detailed output - Follow the suggestions to fix each issue - Make sure all required SDKs are installed - Ensure CocoaPods is installed: `sudo gem install cocoapods` - Run `pod install` in the `ios` directory - Try `pod repo update` if dependencies fail - Check NDK is installed via Android Studio SDK Manager - Verify JDK version matches requirements (JDK 21) - Accept all Android licenses: `flutter doctor --android-licenses` - Enable Google/Apple sign-in in Firebase Console - Verify SHA1/SHA256 keys are added to Firebase - Check bundle IDs match your Firebase configuration `setup.sh` builds against `http://127.0.0.1:8000` but does not start anything. Run `make dev-up` from the repo root first, and confirm with `make dev-status`.
On a physical device, `127.0.0.1` is the phone — set `OMI_DEV_HOST` to your
Mac's LAN or Tailscale address before running **both** `setup.sh` (so the
build points at your machine) and `make dev-up` (so the harness actually
listens there — it defaults to loopback-only otherwise, which is why a
device build alone used to reach nothing). Export it in the same shell so
both commands see it. The Android emulator uses `10.0.2.2` by default.
This shows up on the manual path, where you choose both sides: your own
Firebase project signs the user in while `API_BASE_URL` points at a backend
initialized for a different project. Point `API_BASE_URL` at a backend that
verifies against *your* project.
Omi's shared `https://api.omiapi.com/` is never a valid target for a
self-configured build — it verifies against Omi's own Firebase project, and
the `demo-omi-local` configs `setup.sh` installs are emulator-only fakes that
no hosted backend can verify. Production data requires the explicit `beta`
profile.
**Cause:**
Debug builds run the Dart VM in JIT mode, and iOS only lets Flutter tooling
start a JIT VM on a physical device. Without it, `FlutterEngine` init returns
nil, the app's `FlutterViewController` has no engine, and plugin registration
has nothing to register against. The app now shows a notice explaining this
instead of crashing, but it still cannot run.
**Solutions:**
1. **Install an AOT build for untethered use (physical devices):**
```bash
OMI_MOBILE_BUILD_MODE=profile bash setup.sh ios
```
Profile (or `release`) builds open from the Home Screen on their own. You
lose hot reload; press `d` in `flutter run` to detach and keep the app running.
`setup.sh ios` warns whenever a debug build is about to land on a physical iPhone.
2. **Use the iOS Simulator for debug-mode development:**
- The simulator has no JIT restriction, so `flutter run --flavor dev` works
from the Home Screen too.
Search the help channel or ask questions Report bugs or browse existing issues
Set up your own Omi backend Create Omi apps and integrations Flash and update device firmware How to contribute to Omi