Publishing a Flutter App on Google Play

The steps for putting a Flutter app on Google Play for the first time, in order, from developer account registration to review submission.


1. What You Need to Know Before You Start

Building a Flutter app doesn't mean you can immediately upload it to the store. There are a few things you absolutely must prepare before publishing.

Checklist

ItemDescription
Google accountThe account you'll use to sign up for Play Console
$25 registration feeOne-time cost
Credit or debit cardFor paying the fee (must support international payments)
App signing key (Keystore)The file holding the key that signs your app
Store listing imagesScreenshots, icon, feature graphic, etc.
Privacy policy URLA page explaining what personal data your app collects

Why Are These Required?

Google Play is an app market used by billions of people worldwide. To prevent malicious apps and protect users, Google requires developer verification, app signing, and a review process.


2. Registering a Google Play Console Developer Account

2-1. Access Play Console

Go to the Google Play Console sign-up page in your browser.

Sign in with your Google account. This account will be your developer account going forward, so it's recommended to use a dedicated app management account rather than a personal one.

2-2. Choose Your Account Type

There are two types:

  • Individual account: Register as an individual developer. You'll need your name and contact information.
  • Organization account: Register under a company or organization name. Requires proof of organization (such as a business registration number) and DUNS number verification, which takes more time.

Note: If you're an independent developer, choose "Individual account." You can switch to an organization account later if needed.

2-3. Enter Developer Information

Fill in the following:

  • Developer name: The name displayed publicly in the store. Use your real name or brand name.
  • Email address: The email users will see for support inquiries. This is public.
  • Phone number: Used for identity verification. Must be a number that can receive SMS.
  • Website (optional): Enter your developer website if you have one.

2-4. Identity Verification

Since 2023, Google requires identity verification even for individual accounts. You may need to upload a photo of your ID or complete an address verification process. Allow a few days for this to complete.

2-5. Pay the $25 Registration Fee

  • This is a one-time fee. The Apple Developer Program is $99 a year.
  • You'll need a credit or debit card that supports international payments.

2-6. Confirm Account Activation

Once payment is complete, you'll gain access to the Play Console dashboard. If you can see the "All apps" page, your account is active.

Note: Rather than uploading your app immediately after registration, it's more practical to finish preparing your build first. Follow the steps below before coming back to upload.


3. Generating an App Signing Key (Keystore)

What Is a Keystore?

A Keystore is a file holding the key that signs your app. Google Play only accepts builds signed with the same key as updates to an existing app.

So someone without your signing key can't publish an update under your package name.

What If You Lose It?

Since August 2021, Play App Signing (7-3) is mandatory for new apps, so the key you create here becomes your upload key. If you lose it, you can request an upload key reset in Play Console. A reset takes time, so keep a backup in a safe place.

3-1. Generate a Keystore with keytool

Open a terminal (or command prompt) and run the following command:

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

Here's what each option means:

OptionDescription
-genkeyGenerates a new key pair (public key + private key)
-vVerbose output
-keystore ~/upload-keystore.jksPath and filename where the key will be saved. You can change this to any location you prefer
-storetype JKSSaves in Java KeyStore format
-keyalg RSAGenerates the key with the RSA algorithm
-keysize 2048Sets the key length to 2048 bits
-validity 10000Sets the key's validity to 10,000 days (~27 years). The Android docs recommend at least 25 years
-alias uploadAn alias for the key, used to reference it later

3-2. Enter the Required Information

After running the command, you'll be prompted for the following:

TEXT
Enter keystore password: (type your password — it won't be shown on screen)
Re-enter new password: (type the same password again)

What is your first and last name?
  [Unknown]: Jane Doe
What is the name of your organizational unit?
  [Unknown]: Development
What is the name of your organization?
  [Unknown]: MyCompany
What is the name of your City or Locality?
  [Unknown]: New York
What is the name of your State or Province?
  [Unknown]: NY
What is the two-letter country code for this unit?
  [Unknown]: US

You'll be asked to confirm the information at the end. Type y to proceed.

Note: The name, organization, and other details entered here are not displayed in the store — they're just metadata stored inside the key. Don't stress over them. Just make sure you remember the password.

3-3. Verify the File Was Created

Once the command completes, the .jks file will be at the specified path:

Bash
ls -la ~/upload-keystore.jks

If the file exists, you're done. Back it up somewhere safe — cloud storage, a USB drive, and ideally multiple locations.

Warning: Never commit this Keystore file to Git. Add it to .gitignore immediately.


4. Creating the key.properties File

What Is key.properties?

Hardcoding sensitive information like your Keystore password and file path directly into your code is risky — anyone who reads the code would see your password. Instead, store this information in a separate file that's only referenced at build time. That file is key.properties.

4-1. Create the File

Create a key.properties file inside your project's android folder:

Bash
# Run from the project root
touch android/key.properties

4-2. Fill In the Contents

Open android/key.properties in a text editor and enter the following:

PROPERTIES
storePassword=your_keystore_password
keyPassword=your_key_password
keyAlias=upload
storeFile=/Users/yourusername/upload-keystore.jks
FieldDescription
storePasswordThe password for the Keystore file (set in step 3-2)
keyPasswordThe password for the key entry (usually the same as storePassword)
keyAliasThe alias you specified with the -alias option when generating the key
storeFileThe absolute path to the Keystore file

Note: Enter the storeFile path accurately. On macOS it'll look like /Users/yourusername/upload-keystore.jks; on Windows, use C:\\Users\\yourusername\\upload-keystore.jks (double backslashes) or forward slashes.

4-3. Add to .gitignore

This file contains passwords, so it must never be committed to Git. Open android/.gitignore and add:

TEXT
key.properties

To verify:

Bash
# Run from the project root
git status

If key.properties doesn't appear in the "Untracked files" list, .gitignore is working correctly.


5. Configuring Signing in build.gradle.kts

Why Do We Need to Modify build.gradle.kts?

A fresh Flutter project is configured to sign with a debug key by default. The debug key is only for testing during development. To submit to the store, you need to sign with the key you just created. The build.gradle.kts file is where you tell the build system which key to use for release builds.

Note: Recent Flutter projects use the Kotlin DSL format (build.gradle.kts) by default. When searching online, you may find examples using the Groovy format (build.gradle) — the syntax is different, so be careful.

5-1. The Original File

The original android/app/build.gradle.kts looks roughly like this:

Kotlin
plugins {
    id("com.android.application")
    id("kotlin-android")
    id("dev.flutter.flutter-gradle-plugin")
}

android {
    namespace = "com.example.just_qr"
    compileSdk = flutter.compileSdkVersion
    ndkVersion = flutter.ndkVersion

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }

    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_11.toString()
    }

    defaultConfig {
        applicationId = "com.example.just_qr"
        minSdk = flutter.minSdkVersion
        targetSdk = flutter.targetSdkVersion
        versionCode = flutter.versionCode
        versionName = flutter.versionName
    }

    buildTypes {
        release {
            signingConfig = signingConfigs.getByName("debug")
        }
    }
}

flutter {
    source = "../.."
}

5-2. The Updated File

Update it as follows. Changed sections are marked with comments:

Kotlin
import java.util.Properties                    // [ADDED] Import Properties class

plugins {
    id("com.android.application")
    id("kotlin-android")
    id("dev.flutter.flutter-gradle-plugin")
}

// [ADDED] Read key.properties file
val keystoreProperties = Properties()
val keystorePropertiesFile = rootProject.file("key.properties")
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(keystorePropertiesFile.inputStream())
}

android {
    namespace = "com.example.just_qr"
    compileSdk = flutter.compileSdkVersion
    ndkVersion = flutter.ndkVersion

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_11
        targetCompatibility = JavaVersion.VERSION_11
    }

    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_11.toString()
    }

    // [ADDED] Define signing configuration
    signingConfigs {
        create("release") {
            keyAlias = keystoreProperties["keyAlias"] as String
            keyPassword = keystoreProperties["keyPassword"] as String
            storeFile = file(keystoreProperties["storeFile"] as String)
            storePassword = keystoreProperties["storePassword"] as String
        }
    }

    defaultConfig {
        applicationId = "com.example.just_qr"
        minSdk = flutter.minSdkVersion
        targetSdk = flutter.targetSdkVersion
        versionCode = flutter.versionCode
        versionName = flutter.versionName
    }

    buildTypes {
        release {
            // [CHANGED] Switch from debug signing to release signing
            signingConfig = signingConfigs.getByName("release")
        }
    }
}

flutter {
    source = "../.."
}

5-3. Detailed Explanation of Changes

1) Importing Properties and reading key.properties

Kotlin
import java.util.Properties

val keystoreProperties = Properties()
val keystorePropertiesFile = rootProject.file("key.properties")
if (keystorePropertiesFile.exists()) {
    keystoreProperties.load(keystorePropertiesFile.inputStream())
}
  • Properties is a Java class for reading .properties files.
  • rootProject.file("key.properties") locates the android/key.properties file.
  • The if (keystorePropertiesFile.exists()) check reads the file only when it exists. But if it's missing, the as String casts in signingConfigs below hit null and fail during Gradle configuration, so even debug builds break where key.properties doesn't exist (e.g., CI servers, another developer's machine). To build there too, wrap the signingConfigs block in the same check.

2) The signingConfigs block

Kotlin
signingConfigs {
    create("release") {
        keyAlias = keystoreProperties["keyAlias"] as String
        keyPassword = keystoreProperties["keyPassword"] as String
        storeFile = file(keystoreProperties["storeFile"] as String)
        storePassword = keystoreProperties["storePassword"] as String
    }
}
  • create("release") creates a new signing configuration named "release".
  • Values read from key.properties are mapped to each property.
  • storeFile must be wrapped in the file(...) function to convert it to a File object.

3) Updating the signing config in buildTypes

Kotlin
buildTypes {
    release {
        signingConfig = signingConfigs.getByName("release")
    }
}
  • The existing "debug" reference is changed to "release".
  • Release builds will now be signed with the Keystore you created.

5-4. Update applicationId (Important)

In the code above, applicationId is set to "com.example.just_qr". Package names starting with com.example cannot be registered on Google Play. You must change it to a unique package name.

Kotlin
applicationId = "com.yourdomain.just_qr"

Examples:

  • com.janedoe.justqr
  • io.github.yourgithubid.justqr

Warning: Once an applicationId is registered on the store, it can't be changed. The convention is to use a domain you own in reverse. If you don't have one, io.github.yourgithubid.appname is a common choice.

Recent Flutter templates have no package attribute in AndroidManifest.xml; the package name comes from namespace and applicationId in build.gradle.kts. If you change namespace, also update the package declaration and folder location of MainActivity.kt.


6. Building a Release AAB

AAB vs APK

Since August 2021, Google Play requires all new apps to be submitted in AAB (Android App Bundle) format.

FormatUse Case
APKDirect device installation or testing. Cannot be submitted to the store (for new apps)
AABFor submission to Google Play. Google automatically generates optimized APKs for each user's device

AAB results in smaller app sizes because Google selects only the resources needed for each specific device when generating the APK.

6-1. Pre-Build Checks

Before building, verify the following:

Bash
# Check that Flutter environment is healthy
flutter doctor

# Make sure all packages are installed
flutter pub get

# Check for code errors
flutter analyze

6-2. Run the AAB Build

From your project root directory, run:

Bash
flutter build appbundle --release

On success, you'll see:

TEXT
Built build/app/outputs/bundle/release/app-release.aab

6-3. Locate the Build Output

The generated AAB file is at:

TEXT
build/app/outputs/bundle/release/app-release.aab

This is the file you'll upload to Google Play Console.

6-4. Troubleshooting Build Failures

If the build fails, check the following:

  1. Is the path and password in key.properties correct?
  2. Does the Keystore file actually exist at the specified path?
  3. Are there any typos in build.gradle.kts?
  4. Try running flutter clean and rebuilding:
Bash
flutter clean
flutter pub get
flutter build appbundle --release

6-5. Version Management

App versions are managed in pubspec.yaml:

YAML
version: 1.0.0+1
  • 1.0.0 is the versionName — the version number shown to users.
  • +1 is the versionCode — an integer used internally by the store. It must be higher than the previous value with every update.

When releasing updates:

YAML
version: 1.0.1+2    # Bug fix
version: 1.1.0+3    # New feature
version: 2.0.0+4    # Major changes

Warning: Forgetting to increment the versionCode (the number after +) will cause your upload to be rejected. It must always be greater than the previous submission.


7. Creating Your App and Uploading the AAB in Play Console

7-1. Create the App

  1. Log in to Google Play Console.
  2. From the "All apps" page, click "Create app".
  3. Fill in the following:
    • App name: The name displayed in the store (can be changed later)
    • Default language: English (or your preferred language)
    • App or game: App
    • Free or paid: Free (an app published as free can't be changed to paid later)
  4. Agree to the Developer Program Policies and US export laws.
  5. Click "Create app".

7-2. Understanding the Dashboard

After creating the app, you'll see the dashboard. The left menu has many sections you'll need to fill in before you can publish. The top of the dashboard shows "Tasks to complete before your app can be published" — work through these one by one.

7-3. App Signing Setup

Go to the App signing settings page in Play Console (its menu location has moved as Play Console has been redesigned).

With Google Play App Signing, Google securely manages your app's signing key. Your key acts as an "upload key," while Google generates a separate "app signing key" to sign the APK that reaches users.

Note: Google Play App Signing is mandatory for new apps. Because the upload key and app signing key are separate, if you lose your upload key you can request a reset in Play Console and register a new one.

7-4. Upload the AAB File

  1. In the left menu, click "Release" > "Production". On a new personal account, Production is still locked, so start on the "Closed testing" track (7-5).
  2. Click "Create new release".
  3. Under the "App bundles" section, upload your AAB file — drag app-release.aab onto the upload area or use the file picker.
  4. Once uploaded, the version code and version name will appear automatically.
  5. Write release notes — the "What's new" text shown to users.
TEXT
Example:
- Initial release
- QR code generation and scanning
  1. Click "Save". Don't click "Review release" yet — you need to complete the store listing first.

Tip: If it's your first time, upload to the "Internal testing" track first. Internal testing restricts installation to specific email addresses, so any issues won't be exposed to the general public.

7-5. New Personal Accounts Start with a Closed Test

Personal developer accounts created after November 13, 2023 can't publish straight to Production. First run a closed test with at least 12 testers opted in continuously for at least 14 days, then apply for production access from the dashboard. Until then, the Production track stays disabled.


8. Writing Your Store Listing

Your store listing is everything users see when they find your app on Google Play.

8-1. Main Store Listing

In the left menu, go to "Store presence" > "Main store listing".

App name (max 30 characters)

TEXT
Good: Just QR - Fast QR Code Reader
Bad: QRCodeReaderScannerGeneratorFreeBest (keyword stuffing)

Warning: Excessive keyword repetition in the app name or description may violate Google's policies and result in rejection.

Short description (max 80 characters)

A one-line description shown beneath the app name:

TEXT
Example: Scan and create QR codes quickly and easily

Full description (max 4,000 characters)

Describe your app's features in detail. Naturally incorporate key search terms for App Store Optimization (ASO).

TEXT
Example:
Just QR is a clean app for scanning and generating QR codes in one place.

Key features:
- Instantly scan QR codes with your camera
- Generate QR codes for URLs, text, contacts, and more
- Save generated QR codes to your gallery
- Clean and intuitive interface

...

8-2. Graphic Assets (Images)

Prepare the following images for your store listing:

App icon (required)

  • Size: 512 × 512 pixels
  • Format: PNG (32-bit, alpha allowed)
  • Use the same design as your Flutter app icon at high resolution.

Feature graphic (required)

  • Size: 1024 × 500 pixels
  • Used as a banner in several places on Google Play.
  • Create a banner image that showcases your app's core function.
  • Free tools like Figma or Canva work well for this.

Screenshots (required)

  • Minimum 2, maximum 8
  • Phone screenshots: at least 2 required
    • Format: JPEG or 24-bit PNG (no alpha)
    • Each side 320px to 3840px, and the long side can't be more than twice the short side
  • Use real app screenshots or mockups with device frames.
  • Pick screens that best highlight your app's key features.

How to take screenshots:

Bash
# Run the Flutter app and take a screenshot in the emulator
flutter run

# Or capture from a physical device
# Android: Press Power + Volume Down simultaneously

Tip: To add descriptive text to your screenshots, search for "app store screenshot template" in Figma or Canva for free templates.

Tablet screenshots (optional)

  • If your app works well on tablets, add tablet screenshots too.

8-3. Category and Tags

Category

  • Choose the category that best fits your app.
  • For a QR code app, "Tools" is appropriate.

Tags

  • Select relevant tags from the list Google provides.

8-4. Contact Details

  • Email address (required): For user support inquiries. This is public.
  • Phone number (optional): Public if provided.
  • Website (optional): Your app's website, if you have one.

8-5. Privacy Policy

Google Play requires a privacy policy URL for all apps. Even if your app collects no personal data at all, you still need a page that explicitly states that.

Ways to create a privacy policy page:

  1. GitHub Pages (free, recommended)

    • Create a privacy-policy.md file in a GitHub repo and deploy it with GitHub Pages.
  2. Free generator tools

  3. Google Sites (free)

    • Create a simple page on Google Sites.

Your privacy policy must cover:

  • What personal data the app collects (or state explicitly that it collects none)
  • How collected data is used
  • How long data is retained and how it's deleted
  • Whether data is shared with third parties
  • Contact information for inquiries
TEXT
Simple privacy policy example:

# Privacy Policy

The Just QR app ("the App") does not collect any personal information.

## Information Collected
This app does not collect, store, or transmit any personal data.

## Camera Permission
This app uses the camera permission solely for scanning QR codes.
Images captured via the camera are processed entirely on-device
and are never transmitted to external servers.

## Contact
For inquiries about this privacy policy, please contact:
Email: your-email@example.com

Effective date: January 1, 2024

8-6. App Content Settings

In the left menu, go to "Policy" > "App content" and complete the following declarations:

Privacy policy: Enter the URL you created above.

Ads: Indicate whether your app contains ads.

App access: Indicate whether all app features are freely accessible or whether a login is required.

Content ratings: Complete the questionnaire to receive an automatic IARC rating. You'll be asked about violence, sexual content, etc., and an age rating will be assigned based on your answers.

Target audience: Select the intended age range for your app. Additional requirements apply if your app targets children under 13.

Data safety: Declare what types of data your app collects and shares. You must complete this section even if your app collects no data.

Note: Every item in the "App content" section must be completed. Missing even one will prevent you from submitting for review.

8-7. Country / Region Settings

Under "Release" > "Production" > "Countries / regions", select where you want your app to be available.

  • To release in all countries, use "Add countries/regions" and select all.
  • To release in a specific country only, select just that country.

9. Submitting for Review

9-1. Pre-Submission Checklist

Before submitting for review, confirm all of the following:

  • Does applicationId NOT start with com.example?
  • Is the version code and version name correct?
  • Is the main store listing complete (name, description, screenshots, etc.)?
  • Is the privacy policy URL valid and accessible?
  • Is the App content section fully filled in?
  • Is the content rating questionnaire complete?
  • Is the data safety section complete?
  • Are target countries selected?
  • Is the AAB file successfully uploaded?

9-2. Submit for Review

  1. Check the Play Console dashboard. "Tasks to complete before publishing" should show 0.
  2. Go to "Release" > "Production".
  3. Open the version you saved and go to the review step.
  4. Fix any errors shown. Warnings don't block publishing, but errors must be resolved before you can continue.
  5. Save the version, then send the changes for review from Publishing overview. Button names have changed as Play Console has been updated, so follow what the screen shows.

9-3. Review Timeline

  • Google says that for certain developer accounts it reviews more thoroughly, which can take up to 7 days, or longer in exceptional cases. When that applies, the expected timeframe is shown on your dashboard.
  • While under review, the app status will show as "In review."
  • You'll receive an email notification when the review is complete.

9-4. Common Reasons for Rejection

  1. Metadata policy violation: Keyword stuffing in the app name or description
  2. App not functional: App crashes or core features don't work
  3. Privacy policy missing or inconsistent: Data collection practices don't match what the privacy policy states
  4. Excessive permission requests: Requesting permissions unrelated to app functionality (e.g., a calculator requesting camera access)
  5. Intellectual property violation: Unauthorized use of another brand's logo or name
  6. Insufficient functionality: App is a simple website wrapper or has very little to offer

9-5. What to Do If Your App Is Rejected

  1. Read the rejection reason carefully. It will be in Play Console and in the notification email.
  2. Fix the issue.
  3. Build a new AAB. (Remember to increment versionCode!)
  4. Resubmit.
  5. If the rejection reason is unclear, you can use Play Console's appeal feature.

10. Common Mistakes / FAQ

Q1. I submitted with "com.example" still in the package name

Package names starting with com.example are rejected at the upload stage in Play Console. You need to change both applicationId and namespace in build.gradle.kts. Also update the directory structure under android/app/src/main/kotlin/ to match the new package name.

Q2. I forgot my Keystore password

There's no way to recover a Keystore password. If you're using Google Play App Signing, you can request an upload key reset in Play Console and register a new upload key. Otherwise, the app can no longer be updated.

Q3. My upload is rejected because I didn't increment versionCode

Increment the number after + in the version field in pubspec.yaml:

YAML
# Before
version: 1.0.0+1

# After
version: 1.0.1+2

Q4. My app is over 200 MB

Google Play limits an AAB's base module to 200 MB of compressed download size. Ways to reduce Flutter app size:

Bash
# List dependencies (remove unused packages from pubspec.yaml)
flutter pub deps

# Remove unnecessary assets (images, fonts, etc.)

# Build with obfuscation and optimization
flutter build appbundle --release --obfuscate --split-debug-info=build/debug-info

--obfuscate makes the code harder to reverse-engineer. --split-debug-info separates debug info into a separate file, reducing app size.

Q5. I'm seeing a warning about 64-bit support

Google Play only allows apps that support 64-bit. Flutter builds for both 32-bit and 64-bit by default, so this usually isn't an issue. If you do see a warning, check the ndk configuration in build.gradle.kts.

Q6. What is the Internal Testing track?

Play Console has several testing tracks:

TrackDescription
Internal testingUp to 100 testers, invite-only via email. Deploys without review
Closed testingManage testers via email list or Google Groups. Reviewed. New personal accounts meet the 12-tester, 14-day requirement here
Open testingPublic beta — anyone can join. Review required
ProductionLive to all users. Full review

For first-timers, it's safest to go Internal testing → Closed/Open testing → Production step by step.

Q7. I'm getting a target API level requirement error

Google Play raises the targetSdk requirement every year. Starting August 31, 2026, new apps and updates must target API 36 (Android 16) or higher. Using the latest Flutter version usually satisfies this, but if you're on an older version of Flutter, you may need to upgrade.

Bash
# Upgrade Flutter
flutter upgrade

# If that doesn't work, set it directly in build.gradle.kts
# Inside the defaultConfig block:
targetSdk = 36    # the API level Google Play requires

Q8. What's the difference between build.gradle and build.gradle.kts?

When searching online, you'll find examples in two formats:

  • build.gradle: Groovy-based (older format)
  • build.gradle.kts: Kotlin DSL-based (newer format)

Recent Flutter projects use build.gradle.kts by default. The syntax differs between the two, so copying Groovy examples directly into build.gradle.kts will cause errors. Key differences:

GROOVY
// Groovy (build.gradle)
signingConfigs {
    release {
        keyAlias keystoreProperties['keyAlias']
        storeFile file(keystoreProperties['storeFile'])
    }
}
Kotlin
// Kotlin DSL (build.gradle.kts)
signingConfigs {
    create("release") {
        keyAlias = keystoreProperties["keyAlias"] as String
        storeFile = file(keystoreProperties["storeFile"] as String)
    }
}

Q9. I want to update my app after it's live

  1. Make your code changes.
  2. Increment the version in pubspec.yaml (versionCode is mandatory).
  3. Build a new AAB with flutter build appbundle --release.
  4. Create a new release in Play Console and upload the new AAB.
  5. Submit for review.

Q10. Can I change a free app to paid?

No. Once an app is published as free, it cannot be changed to paid. The reverse — changing paid to free — is allowed. If you're considering monetization, either start as paid from the beginning or use in-app purchases (IAP) instead.


Wrap-Up

Key summary:

  1. Register a Play Console developer account ($25 one-time fee).
  2. Generate a Keystore and keep it safe.
  3. Configure key.properties and build.gradle.kts.
  4. Build the AAB with flutter build appbundle --release.
  5. Create your app in Play Console and upload the AAB. New personal accounts run a closed test (12 testers, 14 days) before applying for production access.
  6. Complete the store listing in full.
  7. Submit for review and wait for approval.