Record and manage rides, runs and hikes on an offline map, with no internet permission at all. Tracks are standard GPX files, and maps are optional Mapsforge files you import yourself.
- Record tracks in the background with pausing, waypoints and live charts
- Recordings survive most crashes
- Speed and elevation charts by distance or time, with zoom
- Import and export
.gpxtracks compatible with other apps - Trim, search, sort and categorize tracks
- Show, hide, export or delete many tracks at once
- Maps are optional; without one, tracks draw on a blank background
- All maps share one canvas and don't need to be adjacent
- Anything requiring internet access
- External device integration
- Map routing or searching
Is internet-based data collection possible?
Not through the app itself, which lacks theINTERNET permission and fails to build with it. Android's cloud backup is disabled and only device-to-device transfers are allowed, though some backup apps, such as Seedvault, can use the device-to-device path and store your data wherever they're set to. However, recording needs system location on, so there is no guarantee that Android itself or other apps don't collect that data.
Was AI used?
Yes, a large portion of this codebase was written by Claude. However, a significant amount of time and human effort was put into polishing the user interface and ensuring the app stays lightweight with as few permissions as possible.Needs the Android SDK (sdk.dir in local.properties, or ANDROID_HOME) and any JDK 17+
to start Gradle, which then builds with an installed JDK 21 or fetches one. Runs on Android 12 or later.
./gradlew :app:assembleDebug # app/build/outputs/apk/debug/app-debug.apk
./gradlew :app:assembleRelease # app/build/outputs/apk/release/app-release-unsigned.apkThe release build is minified but unsigned; sign it with your own key. F-Droid rebuilds each release with Debian's OpenJDK 21 and ships it only if it matches the signed APK on GitHub, so build that one clean and with the same JDK: an incremental build can carry a stale baseline profile.
./gradlew clean :app:assembleRelease --no-build-cache
apksigner sign --ks release.jks --alignment-preserved --v1-signing-enabled false --out offline-gpx-<version>.apk app/build/outputs/apk/release/app-release-unsigned.apkThe build fails if any dependency adds a network permission to the merged manifest
(CheckNoNetworkPermissions in app/build.gradle.kts).
Dependencies are checked against gradle/verification-metadata.xml. After changing one, refresh it
with a device or emulator connected:
./gradlew --write-verification-metadata sha256 check :app:assembleRelease :app:connectedDebugAndroidTest./gradlew test # JVM unit tests for :core and :app, no device needed
./gradlew coverageVerification # coverage report in app/build/reports/coverage, with per-file minimums
./gradlew ktlintCheck # style per .editorconfig; ktlintFormat fixes most of it
./gradlew check # all of the above, plus Android lintInstrumented tests in app/src/androidTest need a connected device or emulator:
./gradlew :app:connectedDebugAndroidTestcore/ JVM Gradle module, so no Android: model (Track, TrackPoints columns,
TrackPoint for single points), analysis (FixFilter, SpeedWindow,
TrackAnalyzer -> TrackProfile).
app/ data/ gpx (streaming parser/writer/relabeller), db (Room), map (MapStore, .map headers, VTM
tile source), record (LocationSource, RecordingWal, RecordingService/
Controller/Recovery), settings, track (TrackRepository, TrackCache).
app/ ui/ map (MapScreen, VTM canvas, layers, generated render theme), track (sheet),
chart (hand-rolled Canvas charts), library, record, settings, format, theme, nav.
app/ di/ AppContainer: manual wiring, no Hilt.
docs/ README icon.
fastlane/ F-Droid listing and screenshots.
Offline GPX is licensed under the GPLv3 or any later version. See LICENSE for details.
Bundled libraries are credited within the app at Settings > Libraries.
The test fixture app/src/test/resources/andorra-fragment.map, which is not part of
the app, contains map data © OpenStreetMap contributors,
available under the Open Database License.
It is cut from a mapsforge extract.



