App Signing & Keystore
Every APK or app bundle Android installs carries a digital signature, and that signature backs a specific promise the platform makes to every user: an update to an app already sitting on their phone must come from the exact same developer as the original install. This lesson covers what that signature actually is, how to generate and wire one into TrailLog's release builds, and — genuinely the single most consequential warning anywhere in this track — how not to lose access to it.
Why Every Android App Must Be Signed
Android refuses to install any APK that isn't signed, and it checks that signature again on every single update. When TrailLog version 2.0 tries to install over version 1.0 already on a user's device, Android compares the two signatures first. If they match, the update proceeds and the user keeps their existing data. If they don't, Android rejects the update outright — it has no way to know whether "TrailLog 2.0" from a different signature is a genuine update from you or a same-named app from someone else entirely, so it refuses to guess. The signature is what makes "same developer" a fact Android can actually verify, rather than something it just has to trust.
The Debug Keystore: Automatic, and Wrong for a Release
You've been shipping signed builds this entire track without ever thinking about it. Android
Studio generates a debug keystore automatically the first time it needs one
(typically at ~/.android/debug.keystore) and signs every debug build with it behind
the scenes, using a well-known, publicly documented password. That's fine — it exists purely so a
debug build installs at all on an emulator or test device.
- The debug keystore's password is the same fixed, public value on every machine — it provides no real security, by design, since it was never meant to protect anything.
- Every machine's debug keystore is different. Reinstall Android Studio, or set up a new development machine, and you get a brand-new debug keystore with a different signature.
- Play Console will not accept an upload signed with a debug keystore at all — a release build needs its own, dedicated keystore, generated once and reused for every future update.
Generating a Release Keystore
A release keystore is generated once, using the JDK's keytool command bundled with
Android Studio, and then reused for every release build TrailLog ever ships:
keytool -genkeypair -v -keystore traillog-release-key.jks -alias traillog-key -keyalg RSA -keysize 2048 -validity 10000
keytool then prompts interactively for a keystore password, a key password, and some
identifying details (name, organization, and so on) that get embedded in the certificate. The same
result is available through a graphical wizard if you'd rather not use the command line: Android
Studio's Build → Generate Signed Bundle / APK menu includes a "Create new..."
option on its keystore step that runs keytool for you and walks through the same
prompts as form fields.
Protect Your Release Keystore Like Your Business Depends On It
This is worth stating in the plainest possible terms: if you lose TrailLog's release keystore file, or forget its password, you can never again publish an update to that app under its original Play Store listing. Android's signature check described above doesn't make an exception for "the original developer lost their key" — from Android's point of view, a build signed with any other key simply isn't the same app. The only way forward at that point is publishing an entirely new listing, starting over with zero installs, zero reviews, and zero rating history. This has genuinely ended real apps' ability to update, and it's a mistake worth taking seriously well before your first release, not after.
- Back up the keystore file itself in at least two independent, durable locations — not just a single laptop's disk.
- Store the keystore password and key password in a password manager, separate from the keystore file itself.
- Never commit the keystore file, or its passwords, to a Git repository — including a private one.
Signing Configs in build.gradle.kts
With a keystore generated and safely backed up, the next step is telling Gradle how to use it for
release builds — without ever typing the actual path or passwords directly into a file that gets
committed. A common pattern is a small, git-ignored keystore.properties file at the
project root:
# keystore.properties — listed in .gitignore, never committed
storeFile=../traillog-release-key.jks
storePassword=REPLACE_WITH_THE_REAL_PASSWORD
keyAlias=traillog-key
keyPassword=REPLACE_WITH_THE_REAL_PASSWORD
app/build.gradle.kts then loads that file at configuration time and feeds its values
into a signingConfigs block:
// Loaded once, at the top of app/build.gradle.kts
val keystoreProperties = Properties()
val keystorePropertiesFile = rootProject.file("keystore.properties")
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}
android {
signingConfigs {
create("release") {
storeFile = file(keystoreProperties["storeFile"] as String)
storePassword = keystoreProperties["storePassword"] as String
keyAlias = keystoreProperties["keyAlias"] as String
keyPassword = keystoreProperties["keyPassword"] as String
}
}
buildTypes {
release {
signingConfig = signingConfigs.getByName("release")
isMinifyEnabled = true
}
}
}
An equally common alternative skips the properties file entirely and reads
System.getenv("TRAILLOG_KEYSTORE_PASSWORD") and similar environment variables instead —
especially convenient on a CI server, where secrets are usually injected as environment variables
rather than files. Either way, the principle is identical: real secrets stay out of any file Git
tracks. Security Best Practices covers this same
"never hardcode a secret" habit as it applies more broadly, beyond just signing.
Play App Signing: Google's Managed Alternative
Modern Play Console apps default to Play App Signing, where Google generates and securely stores the actual signing key used to distribute your app to users, and you keep a smaller upload key instead — used only to sign the bundle you upload to Play Console, which Google then verifies and re-signs with the real app signing key before it reaches any device. This shifts where the "genuinely can't lose this" secret lives: Google's infrastructure protects the app signing key on your behalf, and if your upload key is ever lost or compromised, Google Play Console has a supported process to reset it — something that was never possible under the old model, where the release keystore was the app signing key with no fallback at all. You still need to protect your upload key with the same seriousness described above; Play App Signing reduces the blast radius of a mistake, it doesn't remove the need for care.