Skip to content
Stacklyn Labs
  • Products
  • Services
  • Contact
  • About
  • GuidesStep-by-step buying and building playbooksBlogTutorials, architecture notes, updatesHelp CenterSetup, licence and support articles
  • Hire Us
  1. Home
  2. Help Center
  3. Flutter Release Build Signing: First Android and iOS Build

Flutter Release Build Signing: First Android and iOS Build

Last updated: October 20, 2026

On this page

Before you startAndroid release build signingiOS signing and uploadTroubleshooting
Before you startAndroid release build signingiOS signing and uploadTroubleshooting

The template is rebranded and runs on your phone. Now you need a file the stores will accept, and that means Flutter release build signing: a key you create and keep for Android, and your Apple Developer account for iOS. This article covers the first signed build on both platforms, in order.

Before you start

  • Set the final package name and bundle ID first. Both stores tie the app to that ID for good, so finish changing your app's package name before you sign anything.
  • Set the version in pubspec.yaml, for example version: 1.0.0+1. The number after + becomes the Android versionCode and the iOS build number.
  • Use Java 17. That's what our product guides specify. Gradle and Android Gradle Plugin versions differ by product, so check your template's guide rather than upgrading on your own.

Android release build signing

Step 1: Create the upload keystore

Run this once, from any folder:

keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload

On Windows, use a path such as C:\keys\upload-keystore.jks. keytool asks for a password and your name or company. -validity is in days, so 10000 is about 27 years; Android recommends at least 25.

If the terminal says keytool isn't found, it ships with the Java that Android Studio installs. Run flutter doctor -v, find the path after "Java binary at:", and use keytool from that same folder.

Step 2: Fill in android/key.properties

Most Stacklyn templates ship android/key.properties.example. Copy it to android/key.properties (or create that file if your template has no example) and fill it in:

storePassword=YOUR_STORE_PASSWORD
keyPassword=YOUR_KEY_PASSWORD
keyAlias=upload
storeFile=/absolute/path/to/upload-keystore.jks

Use an absolute path for storeFile. Templates resolve a relative path from different folders (android/app/ in StockPilot and AutoLog, android/ in Agri Ops), and an absolute path works in all of them. On Windows, write it with forward slashes: C:/keys/upload-keystore.jks.

Then protect two files:

  • Keep them out of Git. Most of our guides say key.properties and *.jks are already in the template's ignore files. Confirm with git check-ignore -v android/key.properties; no output means it isn't ignored.
  • Back up the keystore and both passwords to a password manager or encrypted storage. Every future update needs the same upload key. If you haven't settled who holds it, that's step 7 of the app reskin checklist.

Step 3: Check the release signing config

In most Stacklyn templates, android/app/build.gradle.kts reads key.properties automatically. If the file is missing, the release build falls back to the debug key. It still runs on a device, but Google Play doesn't accept debug-signed apps.

SubZero is the exception: its guide asks you to find the TODO: Add your own signing config comment in build.gradle.kts and add the release config yourself. Flutter's Android deployment guide has the full snippet. The core is:

signingConfigs {
    create("release") {
        keyAlias = keystoreProperties.getProperty("keyAlias")
        keyPassword = keystoreProperties.getProperty("keyPassword")
        storeFile = keystoreProperties.getProperty("storeFile")?.let { file(it) }
        storePassword = keystoreProperties.getProperty("storePassword")
    }
}
buildTypes {
    release {
        signingConfig = signingConfigs.getByName("release")
    }
}

Step 4: Understand Play App Signing

Android uses two keys. The upload key is the one you just made; you sign each .aab with it. The app signing key is held by Google, which re-signs what users download. New apps must use Play App Signing, and new apps must publish as an Android App Bundle.

The practical upside: if you lose the upload key, you can request an upload key reset in Play Console instead of losing the app. Treat that as a fallback, not a plan; the backup in Step 2 still matters.

Step 5: Build the app bundle

flutter clean
flutter pub get
flutter build appbundle --release

The bundle lands at build/app/outputs/bundle/release/app-release.aab. That's the file you upload. Zenith's guide adds AdMob values to this command, so use the version in its guide.

Release builds are always shrunk with R8, per Flutter's docs. Vet Vault, StyleBook, CleanSync and Agri Ops keep their plugin keep rules in android/app/proguard-rules.pro; leave that file in place. CleanSync's guide also says to test a release build on a real device before uploading, and that's good advice for any template: install a release APK (flutter build apk --release) on a real phone and open every screen before uploading.

Step 6: Verify the signature

Check the bundle was signed with your key, not the debug key. Google's client-auth guide uses keytool -printcert -jarfile for this on an APK or AAB:

keytool -printcert -jarfile build/app/outputs/bundle/release/app-release.aab
keytool -list -v -keystore /absolute/path/to/upload-keystore.jks -alias upload

The owner and SHA-256 fingerprint from the first command should match the second. If the owner isn't the name you typed in Step 1, the build used the debug key; go back to Step 2.

iOS signing and upload

You need a Mac with Xcode and an Apple Developer Program membership in your name or your company's.

  1. Register the bundle ID. In Certificates, Identifiers & Profiles, add an Explicit App ID matching the bundle ID in Xcode. Your role must be Account Holder or Admin. Then create the app record in App Store Connect and pick that ID.

  2. Install pods and open the workspace. Run cd ios && pod install && cd .., then open ios/Runner.xcworkspace, not the .xcodeproj.

  3. Set signing. Select the Runner target, open Signing & Capabilities, keep Automatically manage signing on and choose your Team. Flutter's docs say automatic signing is enough for most apps. Turn it off only if you need manual signing with specific provisioning profiles, typically on a build server.

  4. Build the archive:

    flutter build ipa --release
    

    You get an .xcarchive in build/ios/archive/ and an .ipa in build/ios/ipa/.

  5. Upload. Drag the .ipa into Apple's Transporter app, or open the archive in Xcode (Window > Organizer), click Validate App, then Distribute App. Every upload needs a new build number. Flutter's iOS deployment guide covers the remaining options.

Signing is where first store builds stall: a keystore path resolved from the wrong folder, a password mismatch, a Gradle error that doesn't name the file you got wrong. If you'd rather not, our Flutter app reskinning service creates the upload keystore, wires it into the release build and hands you store-ready signed builds plus the keystore and passwords. Uploading and the store listing stay with you.

Troubleshooting

Gradle says the keystore was tampered with, or the password was incorrect. That wording comes from forum reports, not official docs. Check storePassword and keyPassword against what you typed in Step 1, and remove any quotes or angle brackets around the values. Forum posts also suggest building with the same Java you used to create the keystore.

Gradle can't find a key with your alias. keyAlias must equal the -alias value from Step 1. Run keytool -list -v -keystore <path> and read the "Alias name" line.

Gradle reports the keystore file isn't set, or storeFile is missing, for the release config. This is how developers on forums describe it, and the exact wording differs between reports. Gradle didn't find android/key.properties, or storeFile is empty or wrong. Check the file sits in android/, not android/app/, and use an absolute path.

Play Console rejects the upload as signed in debug mode. This message is also reported on forums. The release build fell back to the debug key, so key.properties wasn't found or, in SubZero, the signing config isn't wired yet. Repeat Steps 2, 3 and 6.

Play says the version code has already been used. Play won't take a versionCode you've already uploaded. Raise the number after + in pubspec.yaml and rebuild.

Xcode shows a signing error, or no team is selected. Choose your team under Signing & Capabilities, and check the bundle ID is registered to that team.

The Stacklyn Labs Help Center has the other setup guides for our templates.

Was this article helpful?

If you're still stuck, our team is happy to help directly.

Contact Support

Related Articles

Flutter App Backend Setup: Does Your Template Need One?

You bought one of our Flutter templates, it runs on your phone, and now you're looking up Flutter…

Oct 20, 2026 · 6 min readRead article
App Reskin Checklist: What to Decide Before You Touch the Code

You bought a Flutter template. It runs on your phone, and it still shows someone else's name under…

Oct 14, 2026 · 8 min readRead article
How to Change Your Flutter Package Name Before Release

You bought a Flutter template, swapped the logo, and ran it on your phone. Then you open android/app/build.gradle.kts…

Oct 14, 2026 · 9 min readRead article
Stacklyn Labs

Empowering businesses and developers with secure, high-performance digital tools, source templates, and scalable backend platforms.

FlutterWordPressBootstrap 5
Explore
  • Home
  • Products
  • Services
  • Guides
  • About
  • Blog
  • Contact
Developer Portfolios
  • CodeCanyon Store
  • Codester Profile
Support Resources
  • License Activation
  • Help Center
  • Buying Flutter Templates
Connect & Support
Direct Email Supportsupport@stacklynlabs.com
Business Operating HoursMon - Fri: 9:00 AM - 6:00 PM

© 2026 Stacklyn Labs. All Rights Reserved.
  • Privacy Policy
  • •
  • Terms of Service