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