Signing — what it means and why
Android refuses to install an app that nothing has signed, and refuses to update one unless the new version carries the same signature as the old. Here is what a signature actually proves, how to make a key of your own, and why the file holding it is the one thing in your project you can never replace.
The sentence that stopped you
Last lesson ended with a refusal:
INSTALL_PARSE_FAILED_NO_CERTIFICATESA complete, working, finished app — and the phone would not take it. Not because anything was wrong with the code. Because nobody had put their name to it.
This lesson is about that name. It is one of the few parts of Android where the design is genuinely strict, and once you see why, the strictness stops feeling arbitrary.
Think about a signet ring — the heavy kind with a family crest cut into the face. You press it into hot wax on the back of a letter and it leaves a mark.
Two things are true about that mark, and only those two.
Anyone can check it. A person who has seen your letters before can look at a new one and say "yes, that is the same crest as last time." They do not need to know anything secret to do that. The crest is public; the ring is not.
Nobody else can make it. The ring never leaves your hand. A forger can copy the shape of the wax, but not the ring that made it, and a careful eye tells the difference.
Now notice what the seal does not say. It does not say the letter is true. It does not say it is kind, or well argued, or worth reading. It says one thing: this came from the same place the last one came from.
And one more thing, which is the whole of the second half of this lesson. If you drop the ring down a drain, no jeweller alive can make you a matching one. You can have a new ring cut, with a new crest — but everyone who was waiting for the old seal will look at the new one and refuse the letter.
What a signature proves, and what it does not
Android checks a signature at install time and again at every update. Here is the exact guarantee, in one sentence:
The app you are installing now was made by whoever made the version already on this phone.
That is continuity, not endorsement. A signature does not mean an app is safe, or reviewed, or free of bugs. Malware is signed too. What signing buys you is the thing that would otherwise be a disaster: nobody can push an "update" to your app onto your users' phones. Not a stranger, not a rival, not somebody who happens to guess your applicationId. Only whoever holds your .
That is why you saw INSTALL_FAILED_UPDATE_INCOMPATIBLE in the last lesson. The debug build and the release build had the same applicationId and different keys, so Android treated them as two unrelated apps and refused to let one replace the other. Working exactly as designed.
The two halves of a key
uses a — two long numbers generated together, which only work with each other.
- The does the signing. You keep it and never share it. If somebody else gets a copy, they can publish updates to your app.
- The holds the public half plus a short description of who you say you are. It rides along inside the APK, so any phone can check the signature without asking anyone or being online.
Android does not compare whole certificates every time. It compares a — a short hash that identifies a key without revealing it. When you see a line like SHA-256: 3A:7F:C1:… in a build log or the Play Console, that is what it is.
The tool that attaches a signature to a built APK is , and it is also what tells you which key an existing APK was signed with. Gradle runs it as the last step of every build, which is why you have never had to type its name.
The keystore: a box with keys in it
You do not handle keys directly. They live in a — a single password-protected file, usually named something.jks.
Three facts about it, and all three cause confusion at some point:
- A keystore can hold several keys. Each has a name, called a . So signing needs both the file and the alias.
- There are two passwords, not one. One opens the file. One unlocks the key inside it. People often set them the same, which is fine, and then get very confused by an error that distinguishes them.
- It is not part of your project. It must not sit in the project folder, must never be committed to , and must never be shared. It is closer to a passport than a source file.
The keystore you have been using all along
You already own one. Android created it for you the very first time you built anything: the .
It is not a secret. Its password is the word android, its alias is androiddebugkey, and every Android developer on the planet has an identical arrangement. That is deliberate — it is what makes pressing Run frictionless.
It is also exactly why Google Play will not accept a debug-signed app. A key everyone knows the password to proves nothing at all about who made the app.
Making a key of your own
The underlying tool is , which ships with Java. Tools with buttons — Android Studio, Pocket Studio — put a form in front of it, but this is what they run:
1keytool -genkeypair -v \
2 -keystore release-key.jks \
3 -alias upload \
4 -keyalg RSA -keysize 2048 \
5 -validity 10000-validity 10000 is about 27 years. That is not a typo and it is not paranoia: Google Play requires a key valid until at least 22 October 2033, and there is no downside to going further. A key that expires is a key that stops you shipping.
It then asks for your name, organisation and country. Those go into the certificate. Be honest, but know that this is not a legal identity check — it is a label.
Wiring it into the build
Once the keystore exists, the build file needs to know four things: which file, which alias, and the two passwords.
The keystore.properties file it reads sits in the project root and looks like this:
1storeFile=/storage/emulated/0/Keys/release-key.jks
2storePassword=the-password-you-chose
3keyAlias=upload
4keyPassword=the-other-password-you-choseAnd the point of the whole arrangement is this single addition to .gitignore:
1keystore.properties
2*.jksPasswords typed straight into build.gradle.kts end up in every backup, every ZIP you share, and every Git history forever. Keeping them in one ignored file is a two-minute habit that cannot be retrofitted once the secret is out.
Where Pocket Studio stands on this
Straight answer, because you should not have to guess.
Producing a signed release build is a paid Pocket Studio feature. The Free tier's output is debug APKs. Paid tiers add signed release APKs and , raise the cap on how many builds you get, and include the on-device .
That does not change anything you have made. Every app in this course is a genuine Android app, built by genuine , installed on a genuine phone. All three still sit on your home screen and all three can be handed to a friend as an APK. And the ideas in this lesson — key pairs, keystores, why an update has to match — belong to Android, not to any one editor. They are true in every tool you will ever use for this, so the lesson is worth having either way.
The one-way door
Now the part that people learn the hard way.
If you lose the keystore you signed a published app with, you can never update that app again. Not with an apology, not with proof of identity, not with a support ticket. The key is gone, and no new key produces the same signature.
What you can do is publish a different app: a new key, a new applicationId, a new store listing, zero reviews, zero ratings, zero installs. Everyone using the old version keeps using it forever, because their phones will refuse anything signed with the new key.
The same applies to the password. A keystore whose password you have forgotten is a keystore you have lost.
The moment you create a keystore, put a copy somewhere that is not the phone: a cloud drive, a memory card, an email to yourself, ideally more than one of those. Write both passwords down in a password manager, not in a note file next to the keystore.
This is the single highest-value five minutes in the whole of Part 6. It costs nothing today and is worth an entire app later.
What Play App Signing changes
Google noticed that lost keys were a permanent, unfixable disaster, so publishing now works differently. It is called , and it splits the one key into two.
| Key | Who holds it | What it does |
|---|---|---|
| App signing key | Signs every copy users actually download | |
| Upload key | You | Signs the file you send to Google |
When you upload, Google checks your , strips your signature off, and re-signs with the it keeps for you. Users only ever see Google's signature.
The consequence is worth stating plainly: losing your upload key is recoverable. You ask Google to reset it, prove who you are, and register a new one. The app signing key, the one users' phones actually check, never moved.
That does not make the backup advice optional. Play App Signing only covers apps published through Google Play. An APK you hand to a friend directly, or put on your own website, is signed by your key and nobody else's — and for that one, the one-way door is still a one-way door.
You can inspect a real signature right now. This works on any tier, because the APK on your phone was signed the day you built it.
- Open Pocket Studio, tap Projects, open Dice Duel.
- Tap Build and press Run, so a fresh
app-debug.apkdefinitely exists. - Tap Editor, open the file tree, and go to
app/build/outputs/apk/debug/. - Long-press
app-debug.apkand choose Rename. Change the extension from.apkto.zip, exactly as you did in Lesson 2.8. - Open the ZIP and look inside
META-INF. You will find the version receipts, and no certificate file — because a modern signature lives in the APK Signing Block, not as an entry. - Rename it back to
.apkbefore you forget. - Open
app/build.gradle.ktsand look at yourbuildTypesblock. Confirm there is nosigningConfigline anywhere in it — and yet the APK you just opened is signed. That is the debug keystore doing its job invisibly. - Open the Terminal and run
./gradlew :app:signingReport. It prints one block per build type, saying which key each would be signed with. - Find the
Variant: debugsection. The owner isCN=Android Debug, O=Android, C=US— not your name, because this is the shared key everyone has. Note theSHA-256:line: that is the Android compares on every update. - Look for a
Variant: releasesection in the same output. It will sayConfig: null, because you have not set one up. That single word is the whole gap this lesson closes.
keystore.properties — /storage/emulated/0/Keys/release-key.jks — rather than a bare filename, and the ambiguity disappears.storePassword in keystore.properties. Watch for a trailing space — a properties file keeps everything after the =, including spaces you cannot see. If you are certain the password is right, restore the keystore from your backup: the file itself may be damaged.keyPassword, not storePassword. If you set both to the same thing when you created the keystore, copy storePassword into keyPassword and the error goes.keystore.properties pattern that means the properties file is missing, misspelled, or in the wrong folder — the if (keyFile.exists()) guard let the build continue, and the emptiness surfaced here instead.keystore.properties and sits in the project root, beside settings.gradle.kts — not inside app/. Then check every key name matches the strings in your build file, character for character.keytool -list -v -keystore release-key.jks and read the Alias name: lines. Then set keyAlias in keystore.properties to one of them, exactly as spelled — aliases are case-sensitive.- proves one thing: this version came from whoever made the last one. Not that the app is safe, reviewed, or any good.
- A is a secret that signs and a public that travels inside the APK so any phone can check it.
- The is one password-protected file that may hold several keys, each under a , each with its own second password.
- Your has been signing every build since Lesson 0.3. Its password is public knowledge, which is precisely why Play refuses it.
- A names the file, the alias and the passwords; the release build type points at it. Keep the passwords in an ignored
keystore.properties, never inbuild.gradle.kts. - Producing a signed release build is a paid Pocket Studio feature. Everything you have built so far, and everything you build next, works fine without it.
- Lose the keystore for a published app and you can never update it — a new key means a new listing. Back it up the day you make it.
- splits this in two: Google holds the , you hold the , and a lost upload key can be reset.
- Next: what actually stands between a signed build and a page on Google Play — the account, the fee, the graphics, the forms and the waiting.