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

View File

@@ -0,0 +1,78 @@
# T26 — iOS release readiness
What App Review will look at, and what is already in place. Background-location apps get
more scrutiny than most, and the research in `docs/PORT_RESEARCH.md` names unclear
privacy disclosure as the leading rejection cause.
**Status: configured, not submitted.** Nothing here has been through review.
---
## Guideline 5.1.1 — data privacy and transparency
**Rejection cause:** generic usage strings like *"This app needs location"*.
Already in `ios/Runner/Info.plist`, written specifically:
| Key | Says |
|---|---|
| `NSLocationWhenInUseUsageDescription` | Records the GPS track of your ride so you can see route, speed and distance afterwards. **Nothing is recorded until you press Start.** |
| `NSLocationAlwaysAndWhenInUseUsageDescription` | Keeps recording while the phone is in your pocket or the screen is off, so a ride you started is captured beginning to end. **Recording stops the moment you press Stop.** |
Both name what is collected, why, and when it stops. That last clause matters — it is the
difference between "an app that wants your location" and "a recorder you control".
## App Privacy nutrition labels
Declare, and make sure it stays true:
- **Location → Precise Location**, linked to the user? **No.** Used for **App
Functionality** only.
- **No data collected for tracking**, no advertising identifiers, no analytics SDKs.
- **Data is not transmitted off-device by default.** The uploader exists but has no UI and
no endpoint configured; it is inert unless someone sets one deliberately.
> If a server ever ships (the v3 group-ride idea), these labels must change **before** it
> does. Undisclosed background transmission is a straightforward rejection.
## Guideline 2.1 — completeness and background stability
The exposure is crashing on background resume. Mitigations in place:
- Recording state lives in the database, so resuming after suspension reads real state
rather than guessing.
- `restoreAfterProcessDeath` runs at startup and is covered by four tests, including the
crash-gap guard.
- Every upload failure path is swallowed; the network cannot stop a recording.
- Database write failures are caught per batch — losing points beats losing the app.
**Still unproven:** what iOS actually does when the app is suspended while stationary.
That is item **I3** in [REAL-RIDE-CHECKLIST.md](REAL-RIDE-CHECKLIST.md) and it must be
answered before submission.
## Guideline 4.2 — minimum functionality
Not a realistic risk: native Flutter UI, real hardware integration, offline-first storage,
no web view anywhere.
---
## Before submitting
- [ ] **Switch the bundle id** from `com.rippr.port` to `com.rippr` (T27). The `.port`
suffix exists only so the native app can be installed alongside during the port.
- [ ] `CFBundleName` is still the generated lowercase `rippr`; `CFBundleDisplayName` is
already `Rippr`. Make them consistent.
- [ ] App icon and launch screen — still Flutter defaults. The native app's adaptive icon
artwork lives in `~/dojo/rippr/design/` and needs re-exporting at iOS sizes.
- [ ] Run [REAL-RIDE-CHECKLIST.md](REAL-RIDE-CHECKLIST.md) on a real iPhone, especially I3.
- [ ] Record a demo video of a real ride for the review notes. Background-location apps
are frequently asked to justify the entitlement; a video pre-empts a rejection round.
- [ ] `flutter build ipa --release` and confirm the release build works — everything so
far has been debug.
## Known parity gap to disclose internally
The notification cannot carry actions, so the native app's Pause/Resume buttons in the
shade are absent on both platforms. Not an App Review issue; it is a feature difference
the T27 audit must record.