rea-reverse

Google Play App Rejection Reasons You Can Catch Before Upload

Published by rea-reverseUpdated 7 min read
On this page

Many Google Play rejections have nothing to do with screenshots or descriptions. They come from the release file itself: a targetSdkVersion below the current requirement, 32-bit native code without a 64-bit copy, a debuggable build, a debug signing certificate, or a restricted permission such as READ_SMS that nobody filed a declaration for. Every one of those can be read from the APK or AAB before you upload it, and fixed in your own build.

This guide builds a small App Bundle with the most common file-level problems, runs it through this site’s Google Play compliance checker, fixes each finding and runs it again. All output below is from those runs on 2026-10-14. The checker runs in your browser and does not upload the file.

Separate File Checks from Store ReviewSilent walkthrough with English captions.

Two kinds of rejection

  1. Store listing and declarations: privacy policy, Data safety form, content rating, ads declaration, sign-in details for reviewers. No file inspection can see these; Google’s Prepare your app for review page lists them.
  2. What the release file declares: target API level, ABIs, manifest flags, permissions, services, signing. These are facts in the APK or AAB, and this guide is about them.

Step 1: Check the bundle before you upload it

I built before.aab with aapt2, bundletool 1.18.3 and NDK r27, then signed it with jarsigner, the way an AAB is signed. It has the faults I see most often in real projects:

  • package com.example.rejectdemo, targetSdkVersion 35
  • android:debuggable="true" on the application
  • a native library in lib/armeabi-v7a/ only
  • READ_SMS, QUERY_ALL_PACKAGES, READ_MEDIA_IMAGES and FOREGROUND_SERVICE
  • a service with foregroundServiceType="dataSync" but no FOREGROUND_SERVICE_DATA_SYNC
  • signed with a key whose subject is CN=Android Debug,O=Android,C=US, the subject of the Android SDK’s debug keystore

Open the compliance checker (the Google Play scenario is pre-selected) and drop the file. The failed checks, as the analyzer core reported them:

PLAY-01 high    targetSdkVersion=35
                required: >= 36 (phone/tablet, since 2026-08-31)
                note: An extension to 2026-11-01 can be requested in Play Console;
                      without one, submissions are rejected.
PLAY-04 reject  lib/armeabi-v7a/ present, lib/arm64-v8a/ missing
PLAY-06 reject  application android:debuggable="true"
PLAY-07 reject  package="com.example.rejectdemo" (reserved prefix com.example.*)
PLAY-08 reject  uses-permission android.permission.READ_SMS
PLAY-09 high    uses-permission android.permission.QUERY_ALL_PACKAGES
                <queries>: none
PLAY-16 reject  uses-permission android.permission.READ_MEDIA_IMAGES
                targetSdkVersion=35
SIGN-01 reject  v1 signer: CN=Android Debug,O=Android,C=US — Android SDK debug certificate
                (SHA-256 575e39d821c4349d0e7699bdac8a01192e93d38d11506cc9aa34948c0fbf83d4)
PLAY-15 reject  service com.example.rejectdemo.SyncService (dataSync): missing FOREGROUND_SERVICE_DATA_SYNC
                targetSdkVersion=35

The report groups these as Will be rejected, High risk and Advice. I cross-checked the facts with the SDK tools: bundletool dump manifest listed the same four permissions, keytool -printcert -jarfile before.aab printed the same SHA-256, and llvm-readelf -lW showed the r27 arm64 library’s LOAD segments aligned to 0x1000.

Checked against the rules in force on 2026-11-01 (the date picker in the checker), the same file reports PLAY-01 as reject: the extension window has closed.

Step 2: Fix the reasons in the file

Finding Fix
PLAY-01 target API Raise targetSdk to 36 for phones and tablets (Wear OS and Automotive 35, TV and XR 34; the checker picks the form factor from required <uses-feature> entries). Then test against that version’s behavior changes; that testing is the real work. See target API level requirements.
PLAY-04 32-bit only Add arm64-v8a (and x86_64 if you ship x86) to abiFilters, and get 64-bit builds of every prebuilt .so (64-bit requirement).
PLAY-02 / PLAY-03 16 KB High risk until 2027-02-01, reject after (16 KB page sizes). NDK r28 and newer align to 16 KB by default; the walk-through is in Check an APK for 16 KB page size.
PLAY-06 debuggable / testOnly Build the release build type and delete any android:debuggable or android:testOnly you added by hand.
PLAY-07 com.example package Pick a reverse-domain application ID you own.
SIGN-01 / SIGN-02 debug or public key Sign with your own upload key and enroll in Play App Signing.
PLAY-05 APK instead of AAB Build with ./gradlew bundleRelease. New apps must upload an AAB; an APK is a hard rejection only for Android TV updates.

Gotchas behind those rows:

  • com.example is not documented as reserved. Google’s application ID page uses com.example.myapp only as a placeholder, but Play Console refusing com.example uploads is widely reported. Change it before the first upload: the same page warns that Play treats a changed ID as a different app.
  • React Native templates ship a public key. The template’s release build type signs with its bundled debug.keystore until you configure your own key, and SIGN-02 matches it the same way it matches the AOSP test keys.
  • Key validity. Play requires the upload key to be valid past 22 October 2033 (Sign your app), so create one valid for 25 years or more. SIGN-05 flags an earlier expiry: reject for an APK, advice for an AAB, because an AAB carries the upload key.

Permissions that need a declaration

A finding here does not mean the permission is forbidden. It means the permission is limited to specific core uses, and Play Console will ask for a declaration:

Rule Severity Fires on Narrower alternative
PLAY-08 reject any SMS or Call Log permission SMS Retriever API
PLAY-09 high QUERY_ALL_PACKAGES <queries> for the packages you need
PLAY-10 reject MANAGE_EXTERNAL_STORAGE (high if only requestLegacyExternalStorage="true") Storage Access Framework, MediaStore
PLAY-12 high REQUEST_INSTALL_PACKAGES Play In-App Updates for self-updates
PLAY-13 high ACCESS_BACKGROUND_LOCATION foreground location only
PLAY-14 high USE_EXACT_ALARM (advice for SCHEDULE_EXACT_ALARM alone) inexact alarms, WorkManager
PLAY-16 reject READ_MEDIA_IMAGES or READ_MEDIA_VIDEO, only when targetSdk ≥ 33 system Photo Picker
PLAY-17 advice (high when targetSdk ≥ 37) READ_CONTACTS Android Contact Picker
PLAY-11 high a service protected by BIND_ACCESSIBILITY_SERVICE declaration plus in-app disclosure

Who may keep them: SMS and Call Log only for the default SMS, Phone or Assistant handler (policy); broad photo and video access only when it is the app’s core feature (policy); QUERY_ALL_PACKAGES for apps such as device search, antivirus, file managers and browsers (policy). Everyone else removes the permission. If you qualify, file the declaration and expect the checker to keep reporting it, because the review is still ahead. Two dates from the policy deadlines table: from 2027-01-27, phone-call account verification no longer qualifies for READ_CALL_LOG, and apps without a need for broad contacts access must switch to the Contact Picker.

Foreground services (PLAY-15)

From targetSdk 34, a service that declares a foregroundServiceType without its FOREGROUND_SERVICE_<TYPE> permission crashes when started, so the checker rejects it in every scenario. On Play, every typed foreground service also needs a declaration on the App content page, with a description, the user impact and a video showing how the user triggers the feature (requirements). USE_FULL_SCREEN_INTENT is enabled by default only for calling and alarm apps.

Step 3: Find where an unwanted permission came from

Often you never typed READ_SMS. A library merged it in. Android Studio’s Merged Manifest tab on AndroidManifest.xml shows the source of every element, and the build writes the full log to build/outputs/logs/manifest-merger-<buildVariant>-report.txt (Merge multiple manifest files). If the library’s feature that needs the permission is one you don’t use, remove the permission from your app’s manifest:

<uses-permission android:name="android.permission.READ_SMS" tools:node="remove" />

Removing a permission a library really uses can break that feature, so test it, or replace the library.

Step 4: Run it again

after.aab uses dev.example.rejectdemo, targetSdk 36, a release upload key (CN=Example Upload), NDK r28 builds for armeabi-v7a and arm64-v8a, no debuggable, no SMS, package query or media permissions, and adds FOREGROUND_SERVICE_DATA_SYNC. One finding remains:

PLAY-15 high    service dev.example.rejectdemo.SyncService: foregroundServiceType=dataSync (Play Console declaration)
                targetSdkVersion=36

That is expected: the file is fixed, and what remains is the foreground service declaration you file in Play Console.

What the file cannot tell you

A clean report covers the release file only. Keep a checklist for the rest:

  • Data safety form that matches every SDK in the app
  • Privacy policy link, and account deletion if users can create accounts
  • Sign-in details for reviewers if any part of the app is behind a login
  • Store listing that does not mislead or impersonate
  • For personal developer accounts created after November 13, 2023: a closed test with at least 12 testers opted in for 14 days before production (testing requirements)

Play Console also runs its own pre-review checks on the Publishing overview page, covering missing declarations, crash rates and possible policy problems. Google notes that passing them does not guarantee approval either, and the same goes for the checker.

After a rejection: Policy status, resubmit, appeal

  1. Read the reason. In Play Console, select the app and open Policy status in the left menu (Check your app’s policy status). For a rejection, “the last version that you successfully published is still available on Google Play”. The email names the policy.
  2. Fix and resubmit. Google’s resubmission steps say to “update all release types in addition to your production release”, which includes the internal, closed and open test tracks, and to deactivate the non-compliant bundle: “If you fail to deactivate the non-compliant app bundle(s), your attempt to resubmit your app will fail.” A rejection for a permission you already removed usually means an older bundle that still requests it is active on a test track.
  3. Appeal only if you believe the decision is wrong. The same page allows “one appeal per app removal, suspension, or other enforcement action”. If the file triggered the rule, fix it instead. An appeal will not change what the manifest says.
  4. Allow time. Google says some reviews take “up to seven days or longer in exceptional cases” (Publish your app).

A note on packers and hardening

If your app uses a commercial protection runtime, the checker reports PROT-01 as advice. Packing and hardening are legitimate; the finding only explains the trade-offs. Packer start-up code can look like a malware packer to heuristic scanners. Protections that verify their own signature can break under Play App Signing, because Google re-signs the app. Choose a solution that documents Play App Signing support, keep the same signing certificate, and never download executable code from outside Google Play.