Build an Android App Bundle
Menu names below are from Unity 6, which uses File → Build Profiles. In Unity 2022 and earlier the same options live in File → Build Settings.
Switch to Android
Open File → Build Profiles, select Android (install the module with Unity Hub if it's missing) and make it the active profile with Switch Profile.
Set the package name
In Edit → Project Settings → Player → Android, under Other Settings → Identification, set the package name. It can't be changed after the first upload.
Choose IL2CPP and ARM64
Under Configuration, set Scripting Backend to IL2CPP, then enable ARM64 in Target Architectures. Google Play requires 64-bit native code, and ARM64 is only available with IL2CPP.
Turn on the bundle
Back in the build profile, tick Build App Bundle (Google Play) (shown while Export Project is off) and make sure Development Build is off.
Build
Click Build, choose a file name, and Unity writes the
.aab.
Building from CI? The same settings are available from an editor script, which also makes the version code bump impossible to forget:
using UnityEditor;
public static class ReleaseBuild
{
[MenuItem("Build/Android App Bundle")]
public static void Build()
{
PlayerSettings.Android.bundleVersionCode += 1;
EditorUserBuildSettings.buildAppBundle = true;
BuildPipeline.BuildPlayer(new BuildPlayerOptions
{
scenes = new[] { "Assets/Scenes/Main.unity" },
locationPathName = "Builds/game.aab",
target = BuildTarget.Android,
options = BuildOptions.None,
});
}
}Keystore and Play App Signing
Without your own keystore, Unity signs with a debug key, and Play Console rejects debug-signed bundles. Create one in the editor:
Open the Keystore Manager
Go to Edit → Project Settings → Player → Android → Publishing Settings and open Keystore Manager.
Create the keystore
Choose Keystore → Create New, save it (anywhere, or in your dedicated keystore folder), set a password and add a key with an alias.
Use it for builds
Back in Publishing Settings, select the keystore and key alias and enter the passwords.
This keystore is your upload key. On the first upload Play Console sets up Play App Signing and Google keeps the app signing key. Back up the keystore file and both passwords outside the project; a lost upload key means requesting a reset in Play Console.
Bundle Version Code and Target API Level
In Player → Other Settings → Identification, Version is what players see and Bundle Version Code is the integer Google compares. Increase Bundle Version Code before every build you upload; Play Console rejects reused codes.
Next to it is Target API Level. Since 31 August 2026, new apps and updates must target Android 16 (API level 36). On the automatic setting Unity uses the highest SDK it has installed, so check that this is at least 36. Older editor versions may not support the newest level; in that case, upgrade Unity before the test rather than during it.
Unity pitfalls
- Mono build. Mono can't produce ARM64. Play Console then flags the release for not meeting the 64-bit requirement. Switch to IL2CPP with ARM64.
- Development Build left on. Development builds are slower, show a development watermark and can be marked debuggable, which Play Console refuses.
- Old SDKs for ads and analytics. Outdated third-party SDKs bring old native libraries and permissions. Update them before testing: Play Console warns about libraries that don't support 16 KB memory pages, and from 1 February 2027 updates without support can't be released.
- Bundle too large. If the upload fails on size, enable Split Application Binary so Unity moves assets into Play Asset Delivery packs instead of the base module.
- Minify breaks plugins. Release minification can strip Java classes that plugins load by name. Add keep rules or test the minified release on a device before uploading.
- Forgetting the version code. The second upload of the same Bundle Version Code fails. Script the bump or put it on your release checklist.
Native crash symbols for IL2CPP builds
When a Unity game crashes on a tester's phone, the stack trace points into libil2cpp, libunity or libmain. Without symbols, Play Console shows raw addresses, and Google Play doesn't symbolicate crashes that arrived before you uploaded the symbols. Set this up before the first closed release, not after the first crash.
Turn on symbols
In File → Build Profiles → Android, set Debug Symbols to Public. Public symbols contain only the symbol table, which is enough for readable function names and keeps the file small. Debugging adds full debug information for attaching a native debugger locally.
Choose how they reach Google
Pick .zip to get a package named like
MyApp-0.1-v100-IL2CPP.symbols.zipthat you upload yourself, or embed the symbols in the app bundle so they upload with the.aab. In a build script, the snippet below does the second.Match symbols to versions
Symbols belong to exactly one Bundle Version Code. If you upload the zip by hand, do it in Play Console's App bundle explorer on that version's Downloads tab, before testers install it.
// Public symbols, embedded in the .aab so they upload with it
UserBuildSettings.DebugSymbols.level = DebugSymbolLevel.SymbolTable;
UserBuildSettings.DebugSymbols.format = DebugSymbolFormat.IncludeInBundle;If a native plugin ships a separate symbols file, select that file in the Inspector and set Shared Library Type to Symbol with the matching CPU. It must have the same name as the library and sit in a separate folder.
Play Console in short: from closed test to production
Once your Unity bundle is built and signed, the rest happens in Play Console and works the same for every framework. This is the checklist; the full Play Console walkthrough covers every menu and screen.
- Finish app setup on the Dashboard: privacy policy, app access, ads, content rating, target audience, data safety and store listing.
- Create a closed testing release under Test and release → Testing → Closed testing: choose your testers' countries, upload the
.aaband send it for review. - Add testers with a Google Group on the Testers tab and share the opt-in link. It works once the track shows Published.
- Keep at least 12 testers opted in for 14 days in a row. Internal testing doesn't count, and someone who leaves and rejoins starts their 14 days again.
- Ship at least one update during the test and write down what testers found and what you changed.
- Apply for production from the Dashboard and answer the three sections about your test, your app and your readiness. The decision is Google's; nobody can guarantee approval.
Plan for drop-outs: recruit more than 12 testers so one person leaving doesn't push back your timeline. See the full Play Console steps.
The full Play Console walkthrough
Closed track, Google Group and opt-in link, the 12 testers / 14 days rule and the production application, step by step on one page.
Iterate fast without breaking the test
For Unity: increase Bundle Version Code, build the .aab again and upload it to the same closed track. A small fix shipped mid-test is enough.
On your own devices, Build and Run installs the game on the phone selected under Run Device; once the output path is set, Ctrl+B (macOS: Cmd+B) repeats it. Unity's application patching shortens debug build times on your device, but it doesn't deliver anything to testers: they always need a new .aab on the closed track.
- Passwords aren't saved. Unity doesn't store keystore and key passwords on disk, so you re-enter them after every Editor restart. For repeatable CI builds, set them in the editor build script, next to the version code bump from the build section.
- Mind the size. Google Play limits the base module to 500 MB compressed download size. Larger games need asset packs through Play Asset Delivery; modules and install-time asset packs together can reach 4 GB.
- Rebuild after native updates. The Editor shows a build-time warning for any
.soaligned to 4 KB instead of 16 KB. Update to the latest patch release of your Editor and native packages such as Burst, then rebuild before the next upload. - Keep a stable Editor version. Switching the Unity version mid-test changes the engine libraries testers run. Fix the version for the whole 14 days unless a crash forces an update.
Frequently asked questions
Can I test on an Android emulator before uploading?
Unity doesn't support Android emulators. Test on a physical device; Unity Remote helps with input and the Device Simulator with screen layout, but neither replaces a release build on a real phone.
Which target API levels can Unity 6 use?
Unity's Android requirements page for recent Unity 6 versions says you can target API levels 35 and 36, and Google Play requires 36 for new apps and updates. The minimum supported Android version is 8.0 (API level 26).
Do I really need IL2CPP?
For Google Play, yes in practice: only IL2CPP builds ARM64, and Google Play requires 64-bit native code. IL2CPP is also what produces libil2cpp symbols for readable crash reports.
Why can't some testers start the game?
Unity 6 needs OpenGL ES 3.1 or Vulkan; OpenGL ES 3.0 and older aren't supported. Leave Vulkan enabled, and tell testers the minimum before they opt in so you don't lose them on day one.
Sources
Technical details were checked against the official documentation below. Menus and defaults change between versions; when in doubt, the official page wins.
- Unity Manual: Android build process
- Unity Manual: Android Player settings
- Unity Manual: Create a new keystore
- Android Developers: Target API level requirements
- Android Developers: Support 16 KB page sizes
- Unity Manual: Android symbols
- Unity Manual: Android requirements and compatibility
- Play Console Help: Download and install size limits
- Play Console Help: App testing requirements for new personal developer accounts
- Play Console Help: Set up an open, closed, or internal test
- Play Console Help: Deobfuscate or symbolicate crash stack traces
New to the 12 testers rule?
The general guide explains Google's requirement, how a TestBunny campaign runs day by day and what we can and can't guarantee.
Read the general guide