# GPS2Audio — First Signed Release (Handoff) ## Build result - **Status**: BUILD SUCCESSFUL (`gradle :app:assembleRelease`). - **Signed APK**: `/home/user/workspace/GPS2Audio_first_release_signed.apk` (~14.4 MB). - **applicationId**: `de.waypointaudio` - **versionCode**: `27` - **versionName**: `1.6.2-osm-layout` - **minSdk / targetSdk / compileSdk**: 26 / 35 / 35 - **Baseline**: bit-exact source from `GPS2Audio_first_release_source.zip`. No app code was changed; only `app/build.gradle.kts` was extended with a release-signing config and a lint-relax block (`abortOnError = false`, `checkReleaseBuilds = false`) so the existing pre-release lint warnings do not block the release packaging task. App functionality is unchanged. ## Signature verification (apksigner) ``` Verifies Verified using v2 scheme (APK Signature Scheme v2): true Number of signers: 1 Signer #1 certificate DN: CN=GPS2Audio, OU=NesoHub, O=GPS2Audio, L=Germany, C=DE Signer #1 certificate SHA-256 digest: 7b0ea4d5528605173d299d7b268e7ab8768dd504ec15b66a52d47b4257b3bb46 Signer #1 certificate SHA-1 digest: eb922a833909ed6b2dcb6252f0cf425f26df25ad Signer #1 key algorithm: RSA Signer #1 key size (bits): 4096 ``` `aapt2 dump badging`: ``` package: name='de.waypointaudio' versionCode='27' versionName='1.6.2-osm-layout' platformBuildVersionName='15' platformBuildVersionCode='35' minSdkVersion:'26' targetSdkVersion:'35' ``` ## Artifacts | Path | Purpose | | --- | --- | | `/home/user/workspace/GPS2Audio_first_release_signed.apk` | Signed release APK to distribute. | | `/home/user/workspace/GPS2Audio_release_keystore.jks` | The release signing keystore. **Keep forever.** | | `/home/user/workspace/GPS2Audio_release_keystore_credentials.txt` | Alias + passwords + fingerprints. **Sensitive.** Permissions set to `600`. | | `/home/user/workspace/GPS2Audio_first_release_signed_source.zip` | Source tree with signing config + `keystore.properties.example` + `.gitignore`. **Excludes** the real `.jks` and the real `keystore.properties`. | | `/home/user/workspace/GPS2Audio_first_release_signed_handoff.md` | This document. | ## Keystore / signing identity - **File**: `GPS2Audio_release_keystore.jks` (PKCS12) - **Alias**: `gps2audio_release` - **Algorithm**: RSA 4096, SHA384withRSA - **DN**: `CN=GPS2Audio, OU=NesoHub, O=GPS2Audio, L=Germany, C=DE` - **Validity**: 30 years (10 950 days) from 2026-05-08, until 2056-04-30 - **SHA-256 fingerprint**: `7B:0E:A4:D5:52:86:05:17:3D:29:9D:7B:26:8E:7A:B8:76:8D:D5:04:EC:15:B6:6A:52:D4:7B:42:57:B3:BB:46` - **SHA-1 fingerprint**: `EB:92:2A:83:39:09:ED:6B:2D:CB:62:52:F0:CF:42:5F:26:DF:25:AD` This keystore IS the release signing identity of GPS2Audio. It signs all future update-capable releases. **Losing it means losing the ability to update users in place** — they would have to uninstall and reinstall, and local app data would be lost. ### Protecting the keystore 1. Move `GPS2Audio_release_keystore.jks` and `GPS2Audio_release_keystore_credentials.txt` off the build host into: - an encrypted password manager (passwords + fingerprints), AND - an encrypted offline backup (the `.jks` file itself), preferably in two physical locations. 2. Never commit the `.jks` or the `keystore.properties` file. The included `.gitignore` already excludes both. 3. Treat `GPS2Audio_release_keystore_credentials.txt` like the keystore itself; permissions on this file are `600`. ## How future update-capable builds work The release build is wired to read the signing config from either: - a project-root `keystore.properties` file: ``` storeFile=/absolute/path/to/GPS2Audio_release_keystore.jks storePassword= keyAlias=gps2audio_release keyPassword= ``` - or environment variables: - `GPS2AUDIO_RELEASE_STORE_FILE` - `GPS2AUDIO_RELEASE_STORE_PASSWORD` - `GPS2AUDIO_RELEASE_KEY_ALIAS` - `GPS2AUDIO_RELEASE_KEY_PASSWORD` Then run: ``` gradle :app:assembleRelease ``` The output is `app/build/outputs/apk/release/app-release.apk`, signed with the same keystore as v1.6.2 (versionCode 27). As long as the `applicationId` remains `de.waypointaudio` AND the same keystore is used, every future build with a higher `versionCode` will install as a normal in-place update on top of this release for any user who installed it. Debug builds (`gradle :app:assembleDebug`) continue to use the standard Android debug keystore and are unchanged. ## Install notes for users currently running a debug build The release APK is signed with a different certificate than the debug builds that were used during development. Android refuses to "update" across signatures. So users who have a previous **debug** install must: 1. Uninstall the existing debug build of `de.waypointaudio` once. 2. Install `GPS2Audio_first_release_signed.apk`. After that, every future signed release built from this same keystore will install as a normal update without uninstalling. ## Build environment used - Gradle 8.9 - Android Gradle Plugin: per the project's `libs.versions.toml` - Android SDK build-tools 35.0.0 - JDK 17 (jdk-11 keytool was used for keystore generation; the build itself uses JDK 17 via Gradle) - `apksigner` from build-tools 35.0.0 was used to verify the resulting APK.