feat: serve bincio wheel locally for mobile dev testing
- Add GET /api/wheel/download to serve/server.py and edit/server.py: serves dist/bincio-*.whl via FileResponse; in production nginx takes the request before FastAPI, so this is a no-op there but works locally - wheel_version response now includes api_url: "/api/wheel/download" alongside the nginx-served url field - Bundle mobile/assets/bincio.whl (built from dist/) as an offline fallback for Pyodide testing before the first instance sync - docs/mobile-app.md: document dev setup — bundled asset, local server endpoint, and how to refresh the bundle with uv build + cp
This commit is contained in:
+181
-20
@@ -51,20 +51,53 @@ server uses. Any tool in any language can read them.
|
||||
|
||||
---
|
||||
|
||||
## Setup
|
||||
## Development setup
|
||||
|
||||
### Two build modes: Expo Go vs Development Build
|
||||
|
||||
This is the most important thing to understand before starting.
|
||||
|
||||
**Expo Go** is the Expo app available on the Play Store / App Store. It runs any
|
||||
Expo project by scanning a QR code — no compilation step. However, it only supports
|
||||
Expo's own built-in modules. It does **not** support third-party native modules.
|
||||
|
||||
**Development Build** is a custom version of the Expo Go app compiled specifically
|
||||
for this project. It includes all third-party native modules (react-native-webview,
|
||||
maplibre). It is installed once on the device; after that, code changes still update
|
||||
instantly via Metro (the JS bundler) — no rebuild needed.
|
||||
|
||||
| | Expo Go | Development Build |
|
||||
|---|---|---|
|
||||
| Setup | Scan QR, instant | Build APK once (local or EAS cloud) |
|
||||
| expo-sqlite | ✅ | ✅ |
|
||||
| expo-document-picker | ✅ | ✅ |
|
||||
| react-native-webview (Pyodide) | ✗ | ✅ |
|
||||
| @maplibre/maplibre-react-native | ✗ | ✅ |
|
||||
| Code changes | instant (Metro) | instant (Metro) |
|
||||
| Native changes | need new Expo Go release | rebuild APK |
|
||||
|
||||
**Phase 0** only uses built-in Expo modules — Expo Go works. **Phase 1** (Pyodide)
|
||||
requires a Development Build because `react-native-webview` is a native module.
|
||||
|
||||
The recommended setup from the start is a Development Build so you never hit a wall
|
||||
mid-phase.
|
||||
|
||||
---
|
||||
|
||||
### Prerequisites
|
||||
|
||||
| Tool | Minimum version | Notes |
|
||||
| Tool | Required for | Install |
|
||||
|---|---|---|
|
||||
| Node.js | 18 | 20 LTS recommended — install via [nodejs.org](https://nodejs.org) or `nvm` |
|
||||
| npm | ships with Node | |
|
||||
| Expo Go app | latest | Install on your phone — scan the QR code to run the app instantly during development |
|
||||
| Xcode | 15+ | **macOS only, iOS builds.** Install from the App Store, then `xcode-select --install` |
|
||||
| Android Studio | latest | **Android builds / emulator.** Includes the SDK and `adb` |
|
||||
| Node.js 20 LTS | everything | [nodejs.org](https://nodejs.org) or `nvm install 20` |
|
||||
| npm | everything | ships with Node |
|
||||
| Android Studio | Android dev build / emulator | [developer.android.com/studio](https://developer.android.com/studio) |
|
||||
| Xcode 15+ | iOS only, macOS only | App Store → `xcode-select --install` |
|
||||
| EAS CLI | cloud builds (optional) | `npm install -g eas-cli` |
|
||||
|
||||
You do **not** need Xcode or Android Studio to start. Expo Go lets you run the app
|
||||
on your physical device by scanning a QR code — no native build required.
|
||||
You do **not** need a physical Android device to start. The Android emulator
|
||||
(AVD Manager inside Android Studio) works fine for development.
|
||||
|
||||
---
|
||||
|
||||
### First-time setup
|
||||
|
||||
@@ -73,25 +106,153 @@ on your physical device by scanning a QR code — no native build required.
|
||||
bash mobile/setup.sh
|
||||
```
|
||||
|
||||
The script checks prerequisites, installs npm dependencies, and generates the
|
||||
required Expo type declarations. It prints next steps when done.
|
||||
The script checks Node, Android SDK, and Xcode availability; installs npm
|
||||
dependencies; and generates the required Expo type declarations.
|
||||
|
||||
### Running the app
|
||||
---
|
||||
|
||||
### Phase 0 — Expo Go (quickest start)
|
||||
|
||||
Since Phase 0 uses only built-in Expo modules, you can start with Expo Go:
|
||||
|
||||
```bash
|
||||
cd mobile
|
||||
|
||||
# Development server — scan QR with Expo Go on your phone
|
||||
npx expo start
|
||||
```
|
||||
|
||||
# Run on a connected Android device or emulator
|
||||
npx expo run:android
|
||||
1. Install **Expo Go** on your Android phone from the Play Store.
|
||||
2. Scan the QR code printed in the terminal.
|
||||
3. The app loads instantly. Code changes in your editor appear on the phone
|
||||
within a second or two.
|
||||
|
||||
# Run on iOS simulator (macOS only)
|
||||
npx expo run:ios
|
||||
> **Limitation**: once you add the Pyodide WebView in Phase 1, you must switch to
|
||||
> a Development Build. Expo Go will show an error for `react-native-webview`.
|
||||
|
||||
# Build a standalone APK for Karoo sideloading
|
||||
npx eas build -p android --profile preview
|
||||
---
|
||||
|
||||
### Phase 1+ — Development Build
|
||||
|
||||
#### Option A: local build (Android Studio required)
|
||||
|
||||
Plug in an Android device via USB (or start an emulator in Android Studio), then:
|
||||
|
||||
```bash
|
||||
cd mobile
|
||||
npx expo run:android # builds APK, installs it, starts Metro
|
||||
```
|
||||
|
||||
This compiles the full native project once (~3–5 min). After that, JS changes
|
||||
reflect instantly without rebuilding.
|
||||
|
||||
For the emulator, create an AVD in Android Studio with API 33+ and start it before
|
||||
running the command.
|
||||
|
||||
#### Option B: EAS Build (cloud, no Android Studio required)
|
||||
|
||||
EAS (Expo Application Services) builds the APK in the cloud. You get a download
|
||||
link; install it on your device once.
|
||||
|
||||
```bash
|
||||
npm install -g eas-cli
|
||||
eas login # Expo account needed
|
||||
eas build -p android --profile development
|
||||
```
|
||||
|
||||
After install, start Metro locally:
|
||||
|
||||
```bash
|
||||
cd mobile
|
||||
npx expo start --dev-client
|
||||
```
|
||||
|
||||
Shake the device to open the dev menu and enter the Metro URL if needed.
|
||||
|
||||
---
|
||||
|
||||
### iOS development (macOS only)
|
||||
|
||||
```bash
|
||||
cd mobile
|
||||
npx expo run:ios # opens iOS simulator, builds, and runs
|
||||
```
|
||||
|
||||
Requires Xcode 15+ and an active iOS simulator. Cloud builds via EAS:
|
||||
|
||||
```bash
|
||||
eas build -p ios --profile development # requires Apple Developer account ($99/yr)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Where Pyodide comes from
|
||||
|
||||
The hidden WebView loads Pyodide from the **jsDelivr CDN** — the same source
|
||||
as the `/convert/` page on the web:
|
||||
|
||||
```
|
||||
https://cdn.jsdelivr.net/pyodide/v0.26.4/full/pyodide.js (~30 MB)
|
||||
```
|
||||
|
||||
On first extraction after install, the WebView downloads and caches this
|
||||
runtime in `expo-file-system`'s document directory. Subsequent extractions use
|
||||
the cached copy — no internet required.
|
||||
|
||||
The **bincio wheel** (~50 KB) is fetched from:
|
||||
|
||||
```
|
||||
GET {instance_url}/api/wheel/version → { version, url, api_url }
|
||||
GET {instance_url}/bincio-{version}-py3-none-any.whl (nginx, prod)
|
||||
GET {instance_url}/api/wheel/download (FastAPI, local dev)
|
||||
```
|
||||
|
||||
If no instance is configured, it falls back to `https://bincio.org`. The wheel
|
||||
is also cached locally and re-downloaded only when the version changes.
|
||||
|
||||
**Local development** (before bincio is published to PyPI): the wheel is not on
|
||||
PyPI, so there is a bundled fallback at `mobile/assets/bincio.whl`. The
|
||||
extraction code loads it from the app bundle when no cached wheel exists yet.
|
||||
This bundled copy is updated manually by running:
|
||||
|
||||
```bash
|
||||
uv build --wheel # builds dist/bincio-*.whl
|
||||
cp dist/bincio-*.whl mobile/assets/bincio.whl
|
||||
```
|
||||
|
||||
The server-side `GET /api/wheel/download` endpoint also serves the wheel
|
||||
directly from `dist/` — useful when running a local `bincio serve` instance on
|
||||
the same WiFi network as the test device and wanting to exercise the update flow.
|
||||
|
||||
The **common packages** (`fitdecode`, `gpxpy`, `lxml`, `pyyaml`) are fetched from
|
||||
the Pyodide CDN via micropip on first use and cached by the WebView's internal
|
||||
storage.
|
||||
|
||||
**Summary of what touches the network:**
|
||||
|
||||
| Asset | Size | When | Cached |
|
||||
|---|---|---|---|
|
||||
| Pyodide runtime | ~30 MB | once (first extraction ever) | ✅ permanently |
|
||||
| Common packages | ~5 MB | once | ✅ permanently |
|
||||
| bincio wheel | ~50 KB | on version bump (bundled fallback in assets/) | ✅ until next update |
|
||||
| Map tiles | per-tile | on pan/zoom | ✅ by MapLibre |
|
||||
|
||||
Everything else — the activity files, the extracted BAS JSON — stays on device.
|
||||
|
||||
---
|
||||
|
||||
### Distributing the app
|
||||
|
||||
| Target | Method |
|
||||
|---|---|
|
||||
| Your own Android phone | `npx expo run:android` via USB, or EAS development build |
|
||||
| Karoo 2 | EAS production build → download APK → sideload via `adb install bincio.apk` or Karoo's app sideloader |
|
||||
| Other Android users | EAS build → share APK download link (no Play Store needed) |
|
||||
| Play Store | EAS production build → upload `.aab` to Play Console |
|
||||
| iOS users | EAS build → TestFlight (beta) or App Store |
|
||||
|
||||
For Karoo sideloading:
|
||||
```bash
|
||||
eas build -p android --profile preview # produces a standalone APK
|
||||
adb install /path/to/bincio.apk # with Karoo connected via USB
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user