Store
Google Play
Rule
App signing
When
September 2026
Status
Caught before upload every time so far

The trap

Flutter’s Android template signs the release build with the debug key until you change it. The usual fix loads a key.properties file in build.gradle.kts, inside an if (keystorePropertiesFile.exists()) check.

That check is the problem. When the file is missing, the build falls back to the debug key, finishes, and hands you a signed bundle. No warning. A Shorebird release inherits the same config, so it does the same.

Our apps are forked from each other, and key.properties is gitignored, so every new fork starts without it. The first release build of every fork is a debug-signed bundle unless someone remembers.

Why it matters more on the first upload

On an existing listing, Play refuses a bundle signed with the wrong key. Annoying, but you find out.

On a first upload, there’s nothing to refuse it against. If someone follows the template’s keytool -genkey instructions and makes a fresh key, that key becomes the listing’s upload key. Every app we have shares one upload key, and getting a listing off a stray one means an upload key reset through Play Console support.

What we do

Check the artifact, not the intent. Before any upload:

keytool -printcert -jarfile app-release.aab | grep SHA1

Compare that fingerprint with the one you expect. Our preflight script does it on every bundle and fails the release if it doesn’t match. Wiring up a new fork means copying the existing key.properties and keystore in, never generating anything.

Frequently asked questions

Why is my Flutter release build signed with the debug key?

Usually because key.properties is missing and build.gradle.kts only loads it if the file exists, so the build falls back to debug signing without a warning. Check the bundle with keytool -printcert -jarfile.

Check before you submit

The checks behind this page are skills for Claude Code, and the listing checker is free in your browser.

More cases