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