Skip to content

Latest commit

 

History

History

README.md

Flatgym — Android wrapper

A thin native shell around the canonical single-file HTML app. The whole web app lives at the repo root; this directory only contains the Android project (Gradle, Kotlin, Manifest, resources) and bundles the HTML + manifest + service worker + icons into the APK at build time.

Why this exists

  • F-Droid listing. F-Droid only builds from a real source repo with a Gradle setup, and it strongly prefers wrapped HTML apps over raw web links. This wrapper produces an APK that F-Droid can build, sign, and push to its repo, with auto-update on every git tag.
  • Sideload-friendly APK. Anyone who'd rather have a .apk than open the HTML in their browser can grab the release artefact and install. No Play Store account, no F-Droid client needed.
  • Future Play Store via TWA. A separate Bubblewrap project will reuse the published PWA — different artefact, same web codebase.

Layout

android/
├── build.gradle.kts          ← top-level (plugin pinning only)
├── settings.gradle.kts
├── gradle.properties
├── gradle/wrapper/           ← gradle-wrapper.properties is checked in;
│                                gradle-wrapper.jar must be generated once
│                                (see "First-time setup" below)
└── app/
    ├── build.gradle.kts      ← module config + bundleWebApp Copy task
    ├── proguard-rules.pro
    └── src/main/
        ├── AndroidManifest.xml
        ├── java/io/github/zerotonin/flatgym/MainActivity.kt
        ├── res/
        │   ├── values/        (strings, colors, themes)
        │   ├── xml/           (backup, data-extraction, network-security)
        │   ├── mipmap-*/      (legacy + adaptive launcher icons)
        │   └── mipmap-anydpi-v26/  (adaptive-icon XML)
        └── assets/            ← gitignored, populated by `bundleWebApp`

First-time setup

Requires JDK 17+ and Gradle 8.7+ on PATH (any Linux package manager will do — apt install openjdk-17-jdk gradle on Debian/Ubuntu).

cd android
gradle wrapper --gradle-version 8.7   # one-time, creates gradle-wrapper.jar

After that, all build commands use ./gradlew — no system Gradle needed.

Build

cd android
./gradlew assembleDebug      # debug APK at app/build/outputs/apk/debug/
./gradlew assembleRelease    # release APK (debug-signed; F-Droid resigns)

The first build downloads Gradle 8.7 + the Android Gradle Plugin + the Android SDK packages it needs (~500 MB of caches under ~/.gradle/). The Android SDK itself must already be installed and ANDROID_HOME set; the easiest path is to install Android Studio once.

bundleWebApp runs automatically before every build and stages the web assets from the repo root into app/src/main/assets/. If you change gym-tracker.html and rebuild, the new HTML lands in the APK without any manual sync.

Install on device

adb install -r app/build/outputs/apk/debug/app-debug.apk

Or on a Syncthing-synced phone, just drop the APK into the synced folder and tap it.

What's in / what's out

Bundled in the APK:

  • The full Flatgym HTML app at assets/index.html
  • manifest.webmanifest, sw.js, icons/

Loaded over the network at runtime (requires INTERNET permission):

  • The lazy-fetched exercise-details JSON from raw.githubusercontent.com/yuhonas/free-exercise-db on first ? click.
  • External reference pages — but those are routed to the system browser via Intent.ACTION_VIEW, never rendered in-WebView.

A future v0.16.x will inline the exercise dataset and drop the INTERNET permission entirely. That's what F-Droid's NetworkAccess anti-feature flag tracks; for v0.15.x we declare it honestly.

Origin trick: WebViewAssetLoader

The WebView serves the bundled assets through WebViewAssetLoader.AssetsHandler, which surfaces them at https://appassets.androidplatform.net/assets/.... Three reasons:

  1. Real originlocalStorage is partitioned per-origin; a file:// URL would give weaker isolation and trip various WebView quirks.
  2. Service-worker eligibility — SWs require HTTPS or localhost; the asset-loader URL satisfies the WebView's HTTPS check.
  3. No file:// exposure — the manifest disables allowFileAccess, so a stray file: link can't pivot to the device's file system.

Versioning

versionName and versionCode are pinned in app/build.gradle.kts:

val flatgymVersionName = "0.15.0"
val flatgymVersionCode = 15000     // major*10000 + minor*100 + patch

Bump these in the same commit as the corresponding package.json and gym-tracker.html VERSION constant.

F-Droid submission (after the APK builds locally)

  1. Push a v0.15.0 git tag from the repo root.
  2. Open a PR against f-droid/fdroiddata with a metadata YAML describing the build. Template lives at metadata/io.github.zerotonin.flatgym.yml once we cut the first submission.
  3. F-Droid's build farm checks out the tag, runs ./gradlew assembleRelease in android/, signs with the F-Droid key, and publishes.