> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omi.me/llms.txt
> Use this file to discover all available pages before exploring further.

# App Setup

> Set up the Omi Flutter app for development. Build automatically against the local backend harness, or manually with your own.

## Overview

There are two ways to set up the Omi app for development:

<CardGroup cols={2}>
  <Card title="Automatic Setup" icon="wand-magic-sparkles" href="#build-the-app-automatically">
    **Recommended for most developers**

    One command setup against the local backend harness
  </Card>

  <Card title="Manual Setup" icon="wrench" href="#build-the-app-manually">
    **For custom backends**

    Full control over configuration and backend
  </Card>
</CardGroup>

<Info>
  Don't want to build from source? Download the official app from the [App Store](https://apps.apple.com/us/app/friend-ai-wearable/id6502156163) or [Google Play](https://play.google.com/store/apps/details?id=com.friend.ios).
</Info>

***

## Prerequisites

Before starting, make sure you have the following installed:

<CardGroup cols={2}>
  <Card title="Flutter SDK" icon="flutter" href="https://docs.flutter.dev/get-started/install">
    Includes Dart - the core framework
  </Card>

  <Card title="Xcode" icon="apple" href="https://developer.apple.com/xcode/">
    Required for iOS development
  </Card>

  <Card title="Android Studio" icon="android" href="https://developer.android.com/studio">
    Required for Android development
  </Card>

  <Card title="CocoaPods" icon="gem" href="https://cocoapods.org/">
    iOS dependency manager
  </Card>
</CardGroup>

<Note>
  You'll also need [NDK](https://developer.android.com/ndk/downloads) to build Opus for ARM devices.
</Note>

<Note>
  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.
</Note>

***

## Build the App Automatically

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`.

<Warning>
  `setup.sh` does **not** start the backend or the emulator — start the harness
  first (step 1 below), or the app builds and launches but every request fails to
  connect.

  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](https://github.com/BasedHardware/omi/blob/main/app/README.md#mobile-beta--dogfood)).
</Warning>

### Video Walkthrough

<iframe width="560" height="315" src="https://www.youtube.com/embed/U6L8S1SaUls?si=etmPgly-7dhyXmG_" title="Omi App Setup Video Guide" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />

### Setup Steps

<Steps>
  <Step title="Start the local backend harness" icon="server">
    From the **root of the repository**, one-time setup then start the services:

    ```bash theme={null}
    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 theme={null}
    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/docs/runbooks/local-emulator-manual-qa.md).
  </Step>

  <Step title="Navigate to the app directory" icon="folder">
    ```bash theme={null}
    cd app
    ```
  </Step>

  <Step title="Run setup for your platform" icon="terminal">
    <Tabs>
      <Tab title="iOS">
        ```bash theme={null}
        bash setup.sh ios
        ```
      </Tab>

      <Tab title="Android">
        ```bash theme={null}
        bash setup.sh android
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Run in simulator" icon="play">
    Open the app in your IDE and hit run:

    * **Xcode**: Open `app/ios` folder
    * **Android Studio**: Open `app/android` folder

    Or run from terminal:

    ```bash theme={null}
    flutter run --flavor dev
    ```
  </Step>
</Steps>

<Tip>
  The automatic setup runs entirely on your machine — local API, local emulators,
  no production data — making it the fastest way to start building apps and making
  changes. On a physical iPhone, set `OMI_DEV_HOST` to your Mac's LAN or Tailscale
  address before running both `setup.sh ios` and `make dev-up` (in the same shell,
  or exported so both commands see it) — this now makes the harness itself listen
  there too, not just the app you build. Only a private address works (LAN, e.g.
  `192.168.x.x`, or Tailscale/CGNAT, e.g. `100.x.x.x`); a public address is
  rejected. Use `OMI_DEV_BIND_HOST` instead if you want the harness to bind a
  different address than the one the app is compiled to reach.
</Tip>

***

## Build the App Manually

Manual setup gives you full control, allowing you to use your own backend.

<Steps>
  <Step title="Verify Flutter Installation" icon="check">
    Ensure Flutter is installed by following the official [Flutter Installation Guide](https://docs.flutter.dev/get-started/install).

    Verify your setup:

    ```bash theme={null}
    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 theme={null}
        flutter config --jdk-dir /Library/Java/JavaVirtualMachines/jdk-21.jdk/Contents/Home
        ```
      </Accordion>
    </AccordionGroup>
  </Step>

  <Step title="Get Flutter Dependencies" icon="download">
    From the `app` directory, install packages:

    ```bash theme={null}
    cd app
    flutter pub get
    ```
  </Step>

  <Step title="Install iOS Pods" icon="apple">
    Navigate to iOS directory and install CocoaPods dependencies:

    ```bash theme={null}
    cd ios
    pod install
    pod repo update
    ```
  </Step>

  <Step title="Configure Environment" icon="gear">
    Create your environment file from the template:

    ```bash theme={null}
    cd ..
    cat .env.template > .dev.env
    ```
  </Step>

  <Step title="Add API Keys" icon="key">
    Edit `.dev.env` and add your API keys:

    | 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>
  </Step>

  <Step title="Run Build Runner" icon="hammer">
    Generate necessary files:

    ```bash theme={null}
    dart pub run build_runner clean
    dart pub run build_runner build
    ```
  </Step>

  <Step title="Setup Firebase" icon="fire">
    Firebase is **mandatory** for the app to run.

    <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>
  </Step>

  <Step title="Run the App" icon="play">
    Select your target device and run:

    ```bash theme={null}
    flutter run -v --flavor dev
    ```

    To build an APK:

    ```bash theme={null}
    flutter build apk --flavor dev
    ```
  </Step>
</Steps>

***

## Code Formatting

We use `dart format` with a line length of 120 characters.

To automatically format code on commit, install the pre-commit hook:

```bash theme={null}
# From the root of the repository
ln -s -f ../../scripts/pre-commit .git/hooks/pre-commit
```

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="Flutter doctor shows issues" icon="stethoscope">
    * Run `flutter doctor -v` for detailed output
    * Follow the suggestions to fix each issue
    * Make sure all required SDKs are installed
  </Accordion>

  <Accordion title="iOS build fails" icon="apple">
    * Ensure CocoaPods is installed: `sudo gem install cocoapods`
    * Run `pod install` in the `ios` directory
    * Try `pod repo update` if dependencies fail
  </Accordion>

  <Accordion title="Android build fails" icon="android">
    * Check NDK is installed via Android Studio SDK Manager
    * Verify JDK version matches requirements (JDK 21)
    * Accept all Android licenses: `flutter doctor --android-licenses`
  </Accordion>

  <Accordion title="Firebase auth not working" icon="fire">
    * Enable Google/Apple sign-in in Firebase Console
    * Verify SHA1/SHA256 keys are added to Firebase
    * Check bundle IDs match your Firebase configuration
  </Accordion>

  <Accordion title="App can't reach the backend (connection refused / timeouts)" icon="plug">
    `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.
  </Accordion>

  <Accordion title="Sign-in works but every request returns 401" icon="triangle-exclamation">
    The app and the backend are on **different Firebase projects**. Firebase ID
    tokens are project-scoped: a token minted for one project cannot be verified
    by a backend initialized for another, so authentication succeeds locally and
    every authenticated API call is rejected.

    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.
  </Accordion>

  <Accordion title="iOS: Unable to flip between RX and RW memory protection" icon="apple">
    **Error Message:**

    ```
    error: Unable to flip between RX and RW memory protection on pages
    ```

    **Cause:**
    This error occurs because iOS security restrictions prevent the Dart VM from changing memory protection during JIT compilation in Debug mode on physical devices.

    **Solutions:**

    1. **Use iOS Simulator (Recommended for Development):**
       * In Xcode, select an iOS Simulator (e.g., "iPhone 16 Pro") instead of your physical device
       * The simulator doesn't have this restriction, so Debug mode works normally
       * Or run: `flutter run --flavor dev` (it will use a simulator if available)

    2. **Use Release/Profile Mode for Physical Devices:**
       * If you need to test on a physical device, build in Release or Profile mode:
         ```bash theme={null}
         flutter run --release --flavor dev
         ```
       * Or in Xcode, select "Release" or "Profile" scheme instead of "Debug"

    **Note:** This is a known Flutter/iOS limitation. Debug mode with JIT compilation requires memory protection changes that iOS blocks on physical devices for security reasons.
  </Accordion>
</AccordionGroup>

***

## Need Help?

<CardGroup cols={2}>
  <Card title="Discord Community" icon="discord" href="http://discord.omi.me">
    Search the help channel or ask questions
  </Card>

  <Card title="GitHub Issues" icon="github" href="https://github.com/BasedHardware/omi/issues">
    Report bugs or browse existing issues
  </Card>
</CardGroup>

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Backend Setup" icon="server" href="/doc/developer/backend/Backend_Setup">
    Set up your own Omi backend
  </Card>

  <Card title="Build Apps" icon="puzzle-piece" href="/doc/developer/apps/Introduction">
    Create Omi apps and integrations
  </Card>

  <Card title="Firmware Setup" icon="microchip" href="/doc/get_started/Flash_device">
    Flash and update device firmware
  </Card>

  <Card title="Contribution Guide" icon="code-branch" href="/doc/developer/Contribution">
    How to contribute to Omi
  </Card>
</CardGroup>
