Most release blockers on Google Play can be read straight out of the file you are about to ship. The targetSdkVersion is in AndroidManifest.xml. Whether a native library is 16 KB aligned is written in its ELF program headers. Whether the build was signed with the debug key is written in the certificate. None of that needs a server, and none of it needs your source code.
This tool reads those fields from the finished APK or AAB, entirely inside your browser, and compares them with the Google Play and sideloading rules that most often stop a release. Every finding comes with the evidence it is based on, a fix, and a link to the official page that states the rule.
What it checks
It runs 34 checks: Google Play requirements, sideloading and install problems, signing, privacy and app protection. The IDs match the rule list used across this site, so a link such as #PLAY-02 in a report always means the same thing. The “When it fires” column gives the exact condition, for example that SIGN-03 only rejects when targetSdk is 30 or higher. If you only care about Google Play, the Google Play compliance checker is the same tool with the Play scenario pre-selected.
| ID | What is checked | Severity | When it fires | Applies to |
|---|---|---|---|---|
PLAY-01 | targetSdkVersion below the Google Play requirement | Will be rejected | Play only. Phones/tablets: targetSdk ≥ 36 from 2026-08-31 (high risk while an extension to 2026-11-01 is possible, if ≥ 35); Wear OS / Automotive ≥ 35; TV ≥ 34; XR ≥ 34. Form factor from required <uses-feature>. | Google Play |
PLAY-02 | 16 KB page size: ELF segments not 16 KB aligned | Will be rejected (from 2027-02-01) | Play only. .so files in lib/arm64-v8a and lib/x86_64 with any PT_LOAD p_align < 0x4000. High risk until 2027-02-01, reject from then. | Google Play |
PLAY-03 | 16 KB page size: uncompressed .so not 16 KB aligned in the ZIP | Will be rejected (from 2027-02-01) | Play, APK only. Uncompressed (STORED) 64-bit .so whose data offset is not a multiple of 16384; skipped when extractNativeLibs="true". High risk until 2027-02-01. | Google Play |
PLAY-04 | Missing 64-bit native libraries | Will be rejected | Play only. armeabi-v7a/armeabi without arm64-v8a, or x86 without x86_64; or an ELF whose class/machine does not match its ABI directory. | Google Play |
PLAY-06 | Debuggable or test-only build | Will be rejected | Play only. application android:debuggable="true" or android:testOnly="true". | Google Play |
PLAY-07 | Package name uses a reserved prefix | Will be rejected | Play only. Package name com.example.*, com.android.* or android.*. | Google Play |
PLAY-08 | SMS or Call Log permissions | Will be rejected | Play only. Any SMS or Call Log permission is requested. | Google Play |
PLAY-09 | QUERY_ALL_PACKAGES permission | High risk | Play only. QUERY_ALL_PACKAGES is requested (high risk: declaration review). | Google Play |
PLAY-10 | All files access | Will be rejected | Play only. MANAGE_EXTERNAL_STORAGE → reject; requestLegacyExternalStorage="true" alone → high risk. | Google Play |
PLAY-12 | REQUEST_INSTALL_PACKAGES permission | High risk | Play only. REQUEST_INSTALL_PACKAGES is requested. DEX evidence of self-update comes in a later version. | Google Play |
PLAY-13 | Background location permission | High risk | Play only. ACCESS_BACKGROUND_LOCATION is requested. | Google Play |
PLAY-16 | Photo and video permissions | Will be rejected | Play only, and only when targetSdk ≥ 33: READ_MEDIA_IMAGES or READ_MEDIA_VIDEO is requested. | Google Play |
SIDE-01 | targetSdkVersion too low to install on new Android versions | Will be rejected | Outside Play. targetSdk < 24 (Android 15+ refuses to install) or < 23 (Android 14+). | Outside Play (sideload) |
SIGN-01 | Signed with an Android debug certificate | Will be rejected | Any signer certificate whose subject CN is "Android Debug" (the SDK debug keystore is CN=Android Debug, O=Android, C=US; framework templates such as React Native use other O values). Reject on Play; high risk outside Play. Google states that Play does not accept apps signed with a debug certificate; that Play identifies them by this subject is likely but not documented. | Google Play / Outside Play (sideload) |
SIGN-03 | Only a v1 (JAR) signature | Will be rejected | APK only. No v2/v3 signature: reject only when targetSdk ≥ 30 (cannot install), high risk below 30; no signature at all is reported separately. | Google Play / Outside Play (sideload) |
PLAY-05 | An APK instead of an Android App Bundle for Google Play | High risk | Play scenario, APK files only. High risk: new apps must be published as an AAB (since August 2021); Google’s pages state the requirement for new apps. Reject for Android TV apps (required <uses-feature android.software.leanback>): Play no longer accepts APK updates for TV apps since 2023-06-30. | Google Play |
PLAY-11 | Accessibility service declared | High risk | Play only. Any <service> protected by BIND_ACCESSIBILITY_SERVICE. Its android:isAccessibilityTool value is read from the service config XML when the resource table resolves it. | Google Play |
PLAY-14 | Exact alarm permission | High risk | Play only. USE_EXACT_ALARM → high risk (only for apps whose core function is an alarm clock or calendar). SCHEDULE_EXACT_ALARM alone → advice (users can deny it). | Google Play |
PLAY-15 | Foreground service types and full-screen intents | High risk | Only when targetSdk ≥ 34. Reject (everywhere): a service declares a foregroundServiceType without its FOREGROUND_SERVICE_<TYPE> permission (it crashes when started). High risk: FOREGROUND_SERVICE without any typed service; on Play also every typed foreground service (Play Console declaration) and USE_FULL_SCREEN_INTENT. Which untyped services are started in the foreground needs DEX (later version). | Google Play / Outside Play (sideload) |
PLAY-17 | Contacts permission (new Play rule) | Advice | Play only. READ_CONTACTS is requested: advice; high risk when targetSdk ≥ 37 (the new minimum-scope rule applies to apps targeting Android 17, enforced from 2027-01-27). | Google Play |
SIDE-02 | Old targetSdk: Play Protect warning on install | High risk | Outside Play. targetSdk more than two API levels below the latest Android release on the check date (the latest level is kept in the rule data). | Outside Play (sideload) |
SIDE-03 | Permissions blocked for sideloaded apps by enhanced fraud protection | High risk | Outside Play. RECEIVE_SMS, READ_SMS, a notification listener or an accessibility service. In the select markets where Google Play Protect’s enhanced fraud protection is active (Google does not publish a full list), installs of such apps from browsers, messaging apps or file managers are blocked. | Outside Play (sideload) |
SIDE-04 | Accessibility service marked as an accessibility tool | High risk | Outside Play. An accessibility service whose config sets isAccessibilityTool="true". Only a hint: whether the app really is a tool for people with disabilities needs a human check. Unknown when the config XML cannot be read. | Outside Play (sideload) |
SIDE-06 | High-risk combination of capabilities | High risk | Outside Play. Three or more of: SYSTEM_ALERT_WINDOW, an accessibility service, SMS permissions, a device admin receiver, a notification listener. | Outside Play (sideload) |
SIDE-07 | No launcher entry | Advice | Outside Play. No activity or activity-alias with MAIN + LAUNCHER (or LEANBACK_LAUNCHER), and no keyboard, wallpaper, accessibility, dream, TV input, home-screen or other system-style component. | Outside Play (sideload) |
SIDE-08 | Split APK shipped as if it were a complete app | Will be rejected | Outside Play, APK only. Reject (cannot install alone): the file is a split (<manifest split>, isFeatureSplit), which fails with INSTALL_FAILED_INVALID_APK "Full install must include a base package"; or a base APK whose <manifest> sets android:isSplitRequired="true" or android:requiredSplitTypes, which fails with INSTALL_FAILED_MISSING_SPLIT. High risk: a base APK flagged only with <application android:isSplitRequired> or the meta-data com.android.vending.splits.required. The installer does not read those, so it may install but is incomplete without its splits (code or resources from the splits can be missing at runtime). | Outside Play (sideload) |
SIDE-09 | Non-standard ZIP structure | High risk | APK only. Duplicate entries, central directory / local header mismatches, unsafe paths, the encryption flag or an unknown compression method → high risk; extra bytes after the archive → advice. | Google Play / Outside Play (sideload) |
SIDE-10 | Android developer verification: what to register | Advice | Outside Play, APK only. Always lists the package name and signing certificate SHA-256 to register. High risk when the signer is the debug certificate or a public AOSP test key, which cannot prove ownership. | Outside Play (sideload) |
SIGN-02 | Signed with a publicly known key | Will be rejected | A signer certificate matches, by SHA-256, a key whose private half is public: the AOSP test certificates (testkey, platform, shared, media, …) or the React Native template’s debug.keystore (also in Expo’s bare template). Reject on Play; high risk outside Play. | Google Play / Outside Play (sideload) |
SIGN-04 | Weak signing key or certificate digest | High risk | RSA key under 2048 bits, a DSA key, or an MD5-based certificate signature → high risk; a SHA-1-based certificate signature → advice. | Google Play / Outside Play (sideload) |
SIGN-05 | Signing certificate expires before 22 October 2033 | Will be rejected | Play only. A signer certificate’s notAfter is before 2033-10-22. APK: reject (the rule applies to the app signing key). AAB: advice only (the AAB carries your upload key; Google signs the app with the app signing key, and the 2033 rule is stated for that key). | Google Play |
SIGN-08 | ZIP alignment and resources.arsc storage | Will be rejected | APK only. Reject only when targetSdk ≥ 30 and resources.arsc is compressed or not 4-byte aligned (cannot install). Other uncompressed entries not 4-byte aligned → advice. | Google Play / Outside Play (sideload) |
PRIV-07 | Cleartext traffic or user-installed CAs trusted | Advice | usesCleartextTraffic="true"; or not declared with targetSdk < 28 (cleartext then allowed by default); or the network security config permits cleartext or trusts user CAs outside <debug-overrides>. Unknown when the config cannot be read and nothing else is found. | Google Play / Outside Play (sideload) |
PROT-01 | App protection (packer / hardening) identified | Advice | Identification only: a commercial app-protection runtime by its library file name, or (weak signal) one very small classes.dex next to large assets. Protecting code is legitimate; this only explains the trade-offs. | Google Play / Outside Play (sideload) |
You choose a scenario before the check runs: Google Play, outside Play (sideloading or other stores), or both. Play-only rules such as the permission declarations are skipped when you only distribute outside Play, and install-time rules such as SIDE-01 apply everywhere.
You can also pick the date the rules are evaluated against. It defaults to today. Choosing a later date shows which requirements will start to bite, for example the 16 KB rule after 2027-02-01.
How your file stays private
The file is never uploaded. That is a property of how the page is built, not only a promise:
- The page hands the browser’s
Filehandle to a Web Worker. The worker reads slices of the file and decompresses entries with the browser’s built-inDecompressionStream. It contains no network code at all. - Only the parts that matter are read: the ZIP central directory,
AndroidManifest.xml, the resource table (resources.arsc, orresources.pbin an AAB), the launcher icon, the accessibility-service and network-security-config XML when the manifest points to them, the first bytes of each.soand of the React Native bundle, small version files, and the signing data. A 200 MB APK is analyzed by reading a few megabytes. - After the report is shown, the whole file is hashed with SHA-256 in 4 MB slices, still inside the worker. The hash is shown on the page and included in your own exports. Next to it is a link that searches the hash on VirusTotal: a plain link, so nothing is requested until you click it, and even then only the hash is in the address. The file itself is never uploaded anywhere.
- The analytics event sent after an analysis carries only coarse, fixed values: file kind, a size bucket, a duration bucket, success or an error code, and the number of failed checks. It never contains the file name, the package name, a hash or any file content. The full list is on the privacy page.
- The tool page shows no ads.
How to verify it yourself
You do not have to take our word for it.
- Open your browser’s developer tools and switch to the Network tab before you choose a file. Run an analysis and look at every request that appears. None of them carries your file. Apart from this site, the only hosts you should see are Google Fonts and Google Analytics.
- Or load this page, then disconnect from the network (turn off Wi-Fi, or tick Offline in the Network tab), and run the analysis. It completes, because nothing needs to leave your machine.
How to read the results
Each check ends in one of five states:
- Will be rejected: if the rule applies to your scenario, Google Play will block the release, or Android will refuse to install the package.
- High risk: likely to trigger a policy declaration review, a Play Protect warning, or a requirement that becomes mandatory on a known date.
- Advice: a best practice or an early warning.
- Unknown: the tool could not decide. Typically a value is a resource reference it cannot resolve yet, or the part of the file the rule depends on failed to parse. Unknown is not a pass. Check those items by hand.
- Passed: the tool looked and found nothing.
Every failed check lists its evidence, for example lib/arm64-v8a/libfoo.so: PT_LOAD p_align=0x1000, so you can confirm the finding with your own tools before changing anything.
A clean report is not an approval. Google Play reviews policy declarations, store listings, Data safety answers and runtime behavior that no file inspection can see. The results do not represent Google’s review decision. For source-level checks inside Android Studio, Google also offers Play Policy Insights.
Fixing the most common problems
16 KB page size (PLAY-02, PLAY-03)
Apps that target Android 15 or higher must support 16 KB memory pages on 64-bit devices. Google’s developer documentation states that from 2027-02-01, updates that do not comply cannot be published. Until then the tool reports these checks as high risk, not as rejections. Source: Support 16 KB page sizes.
- ELF alignment (PLAY-02). Build native code with NDK r28 or later, which aligns to 16 KB by default. With NDK r27 or earlier, add the linker flag
-Wl,-z,max-page-size=16384. For prebuilt.sofiles from an SDK vendor, ask the vendor for a 16 KB compatible version. - ZIP alignment (PLAY-03). Use Android Gradle Plugin 8.5.1 or later, which aligns uncompressed libraries correctly. If you cannot upgrade, set
useLegacyPackaging = trueso the libraries are compressed instead (installs get larger). You can confirm the result withzipalign -c -P 16 -v 4 app.apk.
targetSdk 36 (PLAY-01)
Since 2026-08-31, new apps and app updates for phones and tablets must target API level 36 (Android 16). You can request an extension in Play Console that runs until 2026-11-01. Wear OS and Android Automotive OS apps must target 35, and TV and XR apps 34; the tool reads uses-feature in the manifest to pick the right threshold. Source: Target API level requirements.
Raising targetSdk changes runtime behavior, so walk through the Android 16 behavior changes and test before you ship. The opposite case, SIDE-01, matters even outside Play: Android 14 refuses to install apps that target below API 23, and Android 15 and later refuse below API 24 (Android 15 behavior changes).
Debug certificate (SIGN-01)
A certificate whose subject is CN=Android Debug,O=Android,C=US is the key Android Studio generates for local builds. Google Play rejects it, and its private key sits on every developer machine, so anyone could sign an “update” that replaces yours. Create a dedicated release key (RSA 2048 bits or more), back it up, and sign release builds with it. On Play, enroll in Play App Signing so Google holds the app signing key and you keep an upload key. Sources: Sign your app, Play App Signing.
Only a v1 signature (SIGN-03)
The v1 (JAR) scheme signs individual ZIP entries and leaves the rest of the archive unprotected. Apps that target API 30 or higher must be signed with APK Signature Scheme v2 or later, or they will not install. The Android Gradle Plugin enables v2 and v3 by default, so a v1-only APK usually comes from a custom signing step. Sign with apksigner and keep v2/v3 enabled; once minSdk is 24 or higher you can drop v1. Always run zipalign before apksigner, never after. Sources: APK signing, apksigner, zipalign.
Permission findings (PLAY-08, 09, 10, 12, 13, 16)
These are not automatic rejections of the permission itself. They mean Google Play only allows the permission for specific core uses and asks you to fill in a declaration. If your app does not need it, remove it, including from libraries that merge it into your manifest. Otherwise use the narrower alternative: the SMS Retriever API instead of SMS permissions, <queries> instead of QUERY_ALL_PACKAGES, the Storage Access Framework or MediaStore instead of all files access, the system Photo Picker instead of READ_MEDIA_IMAGES. Note that from 2027-01-27 phone account verification is no longer an allowed use of READ_CALL_LOG (Policy deadlines). Each finding in the report links to its policy page: SMS and Call Log, package visibility, all files access, REQUEST_INSTALL_PACKAGES, background location, photo and video permissions.
AAB files and how to cross-check them with bundletool
An Android App Bundle stores its manifest and resource table as protobuf rather than binary XML. The tool decodes the base module’s manifest/AndroidManifest.xml, resources.pb and BundleConfig.pb, so an AAB gets the same manifest checks as an APK. References such as @string/app_name and @mipmap/ic_launcher are resolved to their default value and shown next to the raw resource ID. The report also lists the bundle’s modules (base, feature modules and asset packs, with their delivery mode) and the BundleConfig.pb settings that matter for 16 KB support: whether native libraries are kept uncompressed and at which page alignment.
The launcher icon is shown when it is a PNG or WebP bitmap; the highest-density one is picked. An adaptive icon is vector XML, which the tool does not render; it says so and shows the foreground bitmap when there is one.
To check the tool against Google’s own reader, run bundletool locally:
java -jar bundletool.jar dump manifest --bundle=app.aab
java -jar bundletool.jar dump resources --bundle=app.aab --values
java -jar bundletool.jar dump config --bundle=app.aab
The package, versionCode, versionName, min/target SDK, permissions, debuggable, label and icon should match the report. bundletool prints references by name (@string/app_name); the resource dump maps that name to the ID shown in the report and its values.
What it does not do
- No malware verdict. It does not scan for viruses and does not say whether an app is safe to install.
- No DEX decompilation. It does not turn
classes.dexinto Java or Kotlin. For that, use a local decompiler such as JADX (see the guides below). - No AAB conversion. It cannot turn an AAB into an installable APK in the browser; use
bundletoolfor that. It reads the bundle as it is: there are no generated split APKs to check, so the ZIP alignment check (PLAY-03) and the v1-only signature check (SIGN-03) apply to APKs only. - Detection by names, not by code. Frameworks, SDKs and app protection are identified from file names, the manifest and small version files. A renamed library or an SDK without a manifest component is not found, and a version is shown only when the package states it. Fingerprints from DEX code, and the checks that need it (self-update, dynamic code loading, R8, Play Integrity, Data safety hints), come in a later version.
- Packers are identified, never handled. Packing and app hardening are legitimate protection. PROT-01 names what it found and explains the false-positive and Play App Signing risks. The tool never unpacks, modifies, re-signs or repackages anything, and it gives no advice on hiding behavior from reviewers or scanners.
- No full signature verification. Certificates are read and checked, but v1/v2/v3 signatures are not cryptographically verified yet; use
apksigner verify -vfor that. - No review decision. Results do not represent Google’s review decision, and a clean report does not guarantee approval.
FAQ
Is the file really not uploaded? Yes. Analysis runs in a Web Worker in your tab. You can confirm it with the Network tab or by going offline, as described in How to verify it yourself.
Which file types are supported?
.apk and .aab up to 1 GiB. Split APK sets (.apks, .xapk) are not supported in the first version.
Why do I get “Unknown”?
A value the check depends on could not be read, for example a targetSdkVersion written as a resource reference, or a damaged signing block. Treat Unknown as “check this yourself”, not as a pass.
Does a clean report mean Google Play will approve my app? No. Play also reviews declarations, store listing, Data safety and runtime behavior. The tool only covers what can be read from the file.
How current are the rules? Each rule records when it was last checked against its official source and is reviewed monthly. A rule not checked for 90 days is marked as needing review in the report.
Related guides
- Check an APK for Android’s 16 KB Page Size Requirement: PLAY-02 and PLAY-03 step by step on sample APKs, cross-checked with
zipalignandllvm-readelf. - Android APK Analysis with REA: JADX, Apktool, ADB and Flutter: go from this report to the code that caused a finding.
- AAB to APK and APK Unpack: Extract Assets and Scripts with REA: convert an AAB with
bundletooland inventory every entry. - App Not Installed: Package Conflicts With an Existing Package: compare the signing certificate SHA-256 of two builds and fix the mismatch.
- App Not Installed as Package Appears to Be Invalid: turn the generic installer message into the real INSTALL_PARSE_FAILED code, then fix signing (SIGN-03), resources.arsc (SIGN-08) or split APKs (SIDE-08).
- App Isn’t Compatible With Your Phone: targetSdk, ABI, minSdk: read SIDE-01, PLAY-04 and the native library table against the real INSTALL_FAILED code.
- Android Developer Verification: Package Name and SHA-256 Cert: get the values the registration asks for from your own APK or AAB.
- Play Protect Blocked Your App? A Developer’s Guide to the Fix: read SIDE-02, SIDE-03, SIDE-06 and PROT-01, fix your build, then use the official appeal form.
- Debug Android App Crashes with adb logcat and bugreport in REA: when the build installs but crashes, read the crash log and the native tombstone.
- Install REA MCP and Connect Claude Code, Cursor and Codex: set up the local tool for deeper analysis.
- Is REA Safe? Install the Real Reverse Engineer Anything from npm: make sure the package you install is the genuine one.