rea-reverse

Play Protect Blocked Your App? A Developer's Guide to the Fix

Written for REA 6.4.0Updated 10 min read
On this page

Short answer: When Google Play Protect blocks or warns about an app you built and distribute yourself, the cause is almost always something in the APK you can read and change: a target API level that is too old, a sensitive permission such as READ_SMS or an accessibility service, a debug or public signing key, or a non-standard ZIP. Find which one it is, fix your build, keep one release key, and only then, if you are sure the app is clean, use Google’s Play Protect appeal form.

This guide is for developers who ship APKs outside Google Play (a website download, an enterprise portal, a test build sent to customers) and see “App blocked to protect your device”, “Harmful app blocked” or an old-Android compatibility warning on their own app. It is not about turning Play Protect off on a phone. That is the user’s choice, and it does not fix the reason your app was flagged for everyone else.

What you will learn:

  • Which Play Protect messages exist for developers and what triggers each one, according to Google’s developer guidance
  • How to check your own APK for those triggers with this site’s APK & AAB analyzer, with real output from builds I made
  • The legitimate fix for each finding
  • How packing and app hardening fit in, and why they can cause false positives
  • How to appeal, and what the form asks for

Only analyze and install apps you build or are authorized to test, on devices you control.

What Play Protect checks at install time

Google’s Play Protect developer guidance (last updated 2026-08-18, checked 2026-10-14) lists the warnings a developer can run into. The ones that matter for a sideloaded app are:

  1. App blocked to protect your device. An app installed from an internet-sideloading source (a browser, a messaging app, a file manager) declares RECEIVE_SMS, READ_SMS, a notification listener or an accessibility service. The install is blocked. Google calls this enhanced fraud protection in its regional announcements, for example the rollout to all users in Malaysia in April 2026. Google does not publish one list of all markets.
  2. Harmful app blocked. The app matches a malware or Mobile Unwanted Software category. Google asks developers to review their APIs and permissions, confirm that their code and SDKs are free of malicious code, and use valid, standard APK and ZIP headers.
  3. Deceptive accessibility tool. The accessibility config sets isAccessibilityTool="true" but the app does not help people with disabilities.
  4. Android app compatibility too low. targetSdkVersion is more than two API levels below the device’s API level. Google’s example: on Android 13 (API 33), apps targeting below API 31 get the warning.
  5. App scan recommended / send app for security check. Play Protect has not seen the app before. Google notes that appeals do not remove this message.

The categories behind “harmful” are defined on the PHA categories page: backdoors, billing fraud, stalkerware, hostile downloaders, phishing, spyware, trojans, riskware and others. The same page says an “uncommon” app is not necessarily harmful.

Step 1: Run the sideload checks on your APK

Open the APK & AAB analyzer, choose Outside Play (sideload) or Both, and drop the exact APK your users download. The file is read in your browser and not uploaded.

To show real output, I built a small app, dev.example.ppdemo, with aapt2, d8, zipalign and apksigner from build-tools 36.0.0. Version 1 is a deliberately bad build: target API 33, RECEIVE_SMS, READ_SMS, SYSTEM_ALERT_WINDOW, an accessibility service with isAccessibilityTool="true", a notification listener, and a signature from a key with the Android debug subject. I ran the analyzer core on it with the check date 2026-10-14 and the sideload scenario:

SIGN-01  high  Signed with an Android debug certificate
   v1 signer: CN=Android Debug,O=Android,C=US — Android SDK debug certificate (SHA-256 4a11a9df…5130983)
SIDE-02  high  Old targetSdk: Play Protect warning on install
   targetSdkVersion=33
   latest Android API level on 2026-10-14: 37
SIDE-03  high  Permissions blocked for sideloaded apps by enhanced fraud protection
   uses-permission android.permission.RECEIVE_SMS
   uses-permission android.permission.READ_SMS
   notification listener service .NotifService
   accessibility service .OtpReaderService
SIDE-04  high  Accessibility service marked as an accessibility tool
   service .OtpReaderService: isAccessibilityTool="true" (res/xml/a11y_tool.xml)
SIDE-06  high  High-risk combination of capabilities
   4 of 5: SYSTEM_ALERT_WINDOW, accessibility service, SMS (READ_SMS, RECEIVE_SMS), notification listener
SIDE-10  high  Android developer verification: what to register
   package: dev.example.ppdemo
   signer SHA-256: 4a11a9df…5130983 (debug certificate)

Each of these maps to one of Google’s messages. Here is exactly what each rule tests, so you know what a pass or a fail means.

Rule Severity Fires when
SIDE-02 high targetSdk is more than two API levels below the latest Android release on the check date (37 on 2026-10-14, so below 35)
SIDE-03 high RECEIVE_SMS, READ_SMS, a notification listener service or an accessibility service
SIDE-04 high an accessibility service whose config sets isAccessibilityTool="true"; unknown if the config XML cannot be read
SIDE-06 high three or more of SYSTEM_ALERT_WINDOW, an accessibility service, SMS permissions (READ_SMS, RECEIVE_SMS, SEND_SMS), a device admin receiver, a notification listener
SIDE-09 high / advice duplicate entries, central directory and local header mismatches, unsafe paths, the encryption flag or an unknown compression method (high); data after the archive (advice)
SIGN-01 high outside Play any signer certificate with subject CN “Android Debug”
SIGN-02 high outside Play a signer matches, by SHA-256, a key whose private half is public: the AOSP test keys or the React Native template’s debug.keystore
SIDE-10 advice, high with a debug or public key always lists the package name and signer SHA-256 to register for developer verification

SIDE-02 is deliberately stricter than Google’s wording. Google compares against the device’s API level. The tool does not know your users’ devices, so it compares against the newest release, the worst case. A target of 33 is fine on an Android 13 phone and gets the warning on Android 17.

SIDE-06 does not mean “malware”. The fix text in the rule says it directly: this combination is common in apps that Play Protect classifies as harmful, so it draws scrutiny even when every part has a legitimate use.

Step 2: Fix the build, one finding at a time

Old targetSdk (SIDE-02). Raise targetSdkVersion and test against that version’s behavior changes. Google’s target API guide lists them per level. Targeting the current or previous release avoids the warning.

SMS permissions (SIDE-03, SIDE-06). If you read SMS only for a one-time code, drop READ_SMS and RECEIVE_SMS and use the SMS Retriever API or the SMS User Consent API. Neither needs an SMS permission. This single change removed most findings on my test app.

Accessibility and notification listeners (SIDE-03, SIDE-04, SIDE-06). Keep them only if they are the product. Set isAccessibilityTool="false" unless the app is designed primarily for people with disabilities, and show a prominent in-app disclosure before the user enables the service. If you really need these capabilities, the rule’s fix text points to distribution through an app store and Android developer verification, since these are exactly the installs the fraud protection blocks from browsers and file managers.

Signing (SIGN-01, SIGN-02). Create a private release key (RSA 2048 bits or more), sign every public build with it, and never change it. A debug key differs on every machine, and a public key lets anyone sign an “update” of your app. If users already have a debug-signed build, see package conflicts for the migration, because the new key cannot update the old install.

ZIP structure (SIDE-09). Rebuild with the official toolchain (AGP, or zipalign then apksigner). Do not edit the archive by hand or with third-party tools after the build.

Version 2 of my app targets API 36, has none of those permissions and is signed with a 3072-bit release key. In the sideload scenario only one finding remained:

SIDE-10  advice  Android developer verification: what to register
   package: dev.example.ppdemo
   signer SHA-256: 39b9d3743dc22a57099a31b559c990bc6d60b4133317c134ee029d0707ed386a
   note: Registration is not checked here (no network). These are the values the developer console asks for.

That is the expected result for a clean build. The values are what you register next.

Step 3: Developer verification and one long-lived key

Play Protect has no public reputation API, but two things are clearly in your control. The first is signing every release with the same key. The second is Android developer verification. Per that page (checked 2026-10-14), protections began on 2026-09-30 for users installing from participating stores in Brazil, Indonesia, Singapore and Thailand on certified devices running Android 7+, with global expansion in 2027. You register in the Android Developer Console if you distribute only outside Play, or in Play Console. SIDE-10 gives you the package name and certificate SHA-256 to enter. Android developer verification: package name and SHA-256 walks through it.

Whether verification removes a specific Play Protect warning is not stated by Google. Do not promise users that it will.

Packing and hardening: legitimate, but a false-positive risk

Protecting your code with a commercial packer or hardening service is legitimate. The analyzer treats it that way. PROT-01 is advice only and identifies two kinds of signal: a known commercial protection runtime by its native library name, or a weak structural hint, one very small classes.dex next to large assets. My version 3 had a 616-byte DEX and a 3 MB asset, and produced:

PROT-01  advice  App protection (packer / hardening) identified
   weak structural signal: classes.dex: 616 bytes
   weak structural signal: assets/payload.bin: 3000000 bytes
   note: Packing and hardening are not treated as a problem; this result explains review and false-positive risks.

The trade-offs, as the rule states them: packer start-up code looks structurally like malware packers, so heuristic engines may flag it; protections that verify their own signature can break under Play App Signing, because Google re-signs the app. The legitimate remedies:

  • Pick a vendor that documents Play App Signing support, or use R8 alone for Play builds.
  • Keep the same signing certificate across releases.
  • Never download executable code from outside Google Play in a Play build.
  • Submit releases to the major antivirus vendors before launch, through their false-positive or whitelisting channels.
  • If Play Protect still flags the protected build, appeal (below) and say which protection product you use.

This guide does not compare protectors or explain how to make one less visible to scanners. The point is to ship a protected build that is also correctly signed and declared.

Step 4: Appeal if you are sure

Google’s guidance says to appeal a Play Protect classification only after you have reviewed it and confirmed the app is not Mobile Unwanted Software or a PHA. The form is the Play Protect Appeals Submission Form. On 2026-10-14 it asked for:

  • email address (required) and developer name (optional)
  • application package name (required)
  • “SHA256 Hash of the apk of the uploaded file on Virus Total” (required)
  • additional information to support your appeal (required)

The form says that all appeal decisions are final and that you will not receive a response, and that Android Enterprise partners should use the Partner Escalation Desk. Apps published on Google Play use the Play policy appeal process instead.

The analyzer shows the whole-file SHA-256 (for my v2: b458e5239a6da5ac15e8949966c97c2a85214a763726814570428c282a79a12d) with a Search this hash on VirusTotal link. That link only searches. The form asks for the hash of a file uploaded to VirusTotal, so you will have to upload the APK there yourself, and VirusTotal shares submitted files with its community and partners. Do it with the public release build, not an unreleased one. Then make sure the hash on VirusTotal equals the one the analyzer shows.

In “additional information”, write what an analyst needs: what the app does, why each sensitive permission is there (or that you removed it in this version), the signing certificate SHA-256, any protection product you use, and where users download it.

Enterprise and internal apps

If the app is only for your organization’s devices, private apps through managed Google Play avoid the sideloading path entirely. Google documents this under Publish private apps from the Play Console. For Device Policy Controllers blocked during enrollment, the developer guidance points to DPC approval through Android Enterprise.

What REA 6.4.0 does and does not do here

REA, the open-source project by morluto, has no Play Protect or Play policy checks in 6.4.0. inspect-android-package reads the manifest and reports signature_verification: "not_performed". On a test device you can use read-adb-logcat for a bounded log dump after an install attempt and inspect-adb-package to see the installer and version of what is installed. See adb logcat and bugreport with REA. I did not capture a Play Protect block on a device for this guide, so no device log is shown.

FAQ

Will an appeal remove “App scan recommended”? No. Google’s guidance says appeals do not remove that message. It appears for apps Play Protect has not seen before.

My app needs READ_SMS. What now? In markets where the fraud protection is active, such apps are blocked when installed from browsers, messaging apps and file managers. Distributing through an app store and completing developer verification is the route the analyzer’s fix text gives.

Does a clean analyzer report mean Play Protect will not warn? No. The analyzer reads the file. Play Protect also uses its own scanning and reputation, which no file inspection can see.

Is packing my app against Google’s rules? No rule here says so. PROT-01 is advice. Google Play does prohibit downloading executable code from outside Play, and riskware is defined by evasion that shows different functionality. Protecting your own legitimate code is neither.

Next steps