Add the Rippr Flutter port: source, history bundle, and installable APK

The port runs on Android and iOS and is feature-complete; the native Android app
is superseded but kept, since it is still the only version that has recorded real
rides.

rippr-flutter-1.0-debug.apk is package com.rippr.port, deliberately different
from the native com.rippr so both install side by side. Recording the same ride
on both at once is the strongest available check that the port is faithful.

Added INSTALL.md covering both platforms. Android is a one-line adb install; iOS
has no APK equivalent and must be built and signed through Xcode with a free
Apple ID, which gives a 7-day profile.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-15 22:37:45 -05:00
parent 64f5dff30b
commit 0bc42b2e5a
98 changed files with 8417 additions and 24 deletions

141
INSTALL.md Normal file
View File

@@ -0,0 +1,141 @@
# Installing Rippr
Two platforms, two very different stories. Android takes a minute; iOS needs a Mac and
about ten.
---
## Android — install the APK
`rippr-flutter-1.0-debug.apk` · package `com.rippr.port` · label **Rippr** · Android 8.0+
It is **debug-signed**, so it installs directly and coexists with the native app
(`com.rippr`).
### Over USB
```bash
adb install -r rippr-flutter-1.0-debug.apk
```
If you already have it installed and signatures clash:
```bash
adb uninstall com.rippr.port && adb install rippr-flutter-1.0-debug.apk
```
### Without a cable
Copy the APK to the phone (Drive, email to yourself, `adb push`, whatever), open it in
Files, and allow the installing app to install unknown apps when prompted.
### First launch
1. Grant **location** — "While using the app" is enough; the foreground service covers
the rest. Rippr never asks for "Allow all the time".
2. Grant **notifications** on Android 13+. Not optional in practice: the ongoing
notification is what keeps the recording service alive.
3. On Samsung/Xiaomi/OnePlus, exempt Rippr from battery optimisation, or the OS may kill
it mid-ride. Settings → Apps → Rippr → Battery → Unrestricted.
### Running both apps at once
This is worth doing deliberately. The two use different application ids so they can
record the **same ride simultaneously**, which is the strongest check that the port is
faithful:
```bash
adb install -r rippr-2.0.1-debug.apk # native, com.rippr
adb install -r rippr-flutter-1.0-debug.apk # port, com.rippr.port
```
Start both, ride, stop both, compare distance / max speed / moving time. See
`rippr-flutter-src/docs/port/REAL-RIDE-CHECKLIST.md`.
> The debug APK is ~172 MB because it carries every ABI and no code shrinking. A release
> build would be a fraction of that, but needs a signing key — see below.
---
## iOS — you have to build and sign it yourself
**There is no APK equivalent.** iOS will not run an app that is not signed by a
certificate the device trusts, so an unsigned `.app` or `.ipa` cannot simply be copied
over. The only routes are the App Store, TestFlight, an Apple Developer account with
ad-hoc provisioning, or **free personal signing through Xcode** — which is what follows.
### What you need
- A Mac with Xcode (already installed)
- Flutter (already installed)
- Your iPhone and a Lightning/USB-C cable
- A free Apple ID — **no paid Developer account required**
### Steps
```bash
git clone rippr-flutter-history.bundle rippr-flutter
cd rippr-flutter
flutter pub get
dart run build_runner build # Drift codegen
open ios/Runner.xcworkspace # the workspace, NOT the .xcodeproj
```
In Xcode:
1. Select the **Runner** target → **Signing & Capabilities**
2. Tick **Automatically manage signing**
3. **Team** → Add an Account… → sign in with your Apple ID → select it as the team
4. **Change the Bundle Identifier** to something globally unique, e.g.
`com.dylan.rippr.port`. A free personal team cannot claim an identifier someone else
has registered, and `com.rippr.port` may collide.
5. Plug in the iPhone and pick it as the run destination
6. Press **Run** (⌘R)
On the phone, first launch will refuse with *"Untrusted Developer"*. Go to
**Settings → General → VPN & Device Management → your Apple ID → Trust**, then launch
again.
Or from the terminal once signing is configured in Xcode:
```bash
flutter devices # find your phone's id
flutter run --release -d <device-id>
```
### The catch with free signing
A free Apple ID gives a **7-day** provisioning profile. After a week the app refuses to
launch and you re-run it from Xcode to refresh. You are also limited to three apps
sideloaded at a time.
A paid Developer account ($99/yr) raises that to a year and unlocks TestFlight, which is
the sane route if you want the app on a phone for a whole riding season.
### First launch on iOS
1. Grant **location**. Choose **"Allow While Using App"** first; iOS will later ask to
upgrade to Always once it sees background usage — accept it, or recording stops when
the screen locks.
2. A **blue pill** appears in the status bar while recording in the background. That is
correct and intentional.
3. iOS gives no equivalent of Android's battery-optimisation exemption. Low Power Mode
*will* affect GPS behaviour — worth testing with it off first.
---
## Known limitations of both builds
- **Neither has ever recorded a real ride.** Everything is verified by 175 automated tests
and a simulator, and no simulator produces velocity.
- **No notification actions.** The native app had Pause/Resume buttons in the shade; the
Flutter port does not. Tapping the notification opens the app.
- **The app icon is still the Flutter default.**
- **Debug builds.** Slower than release and much larger. For Android, a release build
needs a keystore:
```bash
keytool -genkey -v -keystore ~/rippr.jks -keyalg RSA -keysize 2048 \
-validity 10000 -alias rippr
# then configure signingConfigs in android/app/build.gradle.kts
flutter build apk --release
```