shipcheck

The Play permissions declaration

Updated September 7, 2026 · published by Baker Ventures LLC · sources cited inline

Some permissions need an approved declaration before Play will let you publish, and the review is slower than a normal release review.

The recurring ones: SMS and Call Log, All files access (MANAGE_EXTERNAL_STORAGE), background location, accessibility services, and a handful of others Google treats as sensitive.

The React Native version of the problem is that you did not request it. Android manifest merging folds every dependency's manifest entries into yours, and the merged result is what Play evaluates. A library you added for something unrelated can contribute READ_SMS or ACCESS_BACKGROUND_LOCATION, and nothing in your own manifest will show it.

So read the merged manifest, not your source manifest:

# what actually ships
find android -name "AndroidManifest.xml" -path "*merged*" -o -name "AndroidManifest.xml" -path "*build*" | head
grep -o 'android:name="android.permission.[A-Z_]*"' \
  android/app/build/intermediates/merged_manifests/release/AndroidManifest.xml 2>/dev/null | sort -u

Then decide per permission: declare it, or remove it. A permission you do not use is pure liability, and removing it is usually faster than getting a declaration approved.

Removing what a library added

If the library genuinely does not need it for the features you use:

<!-- android/app/src/main/AndroidManifest.xml -->
<manifest xmlns:tools="http://schemas.android.com/tools">
  <uses-permission android:name="android.permission.READ_SMS" tools:node="remove" />
  <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" tools:node="remove" />
</manifest>

In an Expo project this belongs in a config plugin or in app.config.js, not in the generated android/ directory, which prebuild regenerates. Editing the generated file works locally, disappears on the next EAS build, and produces an identical second failure with the change having been correct both times. Auditing what your config plugins added.

Then test the affected feature. Removing a permission that is actually used gives you a runtime failure, not a build error, and it will be found by a user rather than by CI.

What each declaration wants

SMS and Call Log. Restricted to a narrow set of use cases, usually where the permission is core to the app's declared function. A convenience feature is not an approvable reason, and this is the one most often solved by removing the dependency.

All files access. Requires that the app's core function genuinely needs broad file access. Most apps that request it want the media picker or scoped storage instead, which need no declaration at all and are the better implementation anyway.

Background location. A separate review, usually requiring a demonstration video and a clear explanation of the user-facing feature that needs location while backgrounded. Slow. If you only need location while the app is in use, request the foreground permission and the whole question disappears. The Apple equivalent is Guideline 2.5.4, and the same discipline applies.

Accessibility services. Only for genuine accessibility use, and used for anything else it is both a rejection and a policy problem.

The order to work in

  1. Read the merged manifest. You cannot decide about permissions you have not seen.
  2. For each sensitive permission, find the dependency that contributes it.
  3. Remove what you do not use. Fastest route to a publishable build.
  4. Declare what you do, with the video where one is required, well before you need the release.
  5. Check the Console's own release-blocking list for that version rather than reasoning from the email.

Step four is the timing mistake. Teams submit the declaration alongside the release they want out this week, and these reviews are not fast.

Where it sits with the other Play gates

RequirementWhat blocks
Permissions declarationPublishing, until approved
Target API levelUpdating an existing app below the floor
Data safety formRelease, when it mismatches behaviour
Foreground service typesRelease, when types are missing or wrong
Closed testingProduction access for new personal accounts

Several are hard gates with dates rather than judgement calls, which is why the annual check matters. What changes at each OS release.

shipcheck reads the merged manifest and reports sensitive permissions with the dependency that contributed each one, so the decision is a list rather than an investigation. What it checks. · Google Play rejections. · After a rejection.

About shipcheck

shipcheck is a pre-submission checker from Baker Ventures LLC that runs inside Claude Code. It reads your React Native or Expo project, finds the things that get apps rejected or blocked at upload, cites the exact App Store Review Guideline or Google Play policy clause, and names the file and line to fix.

It exists because React Native and Expo apps fail for reasons that are invisible in the code you wrote: capability arriving through a dependency, purpose strings added by a config plugin, a privacy manifest missing from an SDK you never chose directly, and a generated ios/ directory that discards your edits on the next prebuild. shipcheck checks what the binary and the config actually declare, not what you intended. The rejection references on this site are free, need no account, and link to the primary Apple or Google document for every claim.

Questions and answers

What is the Google Play permissions declaration?

A form in Play Console for permissions Google treats as sensitive, including SMS and Call Log, All files access, background location and accessibility. You declare why the app needs it, and until the declaration is reviewed and approved the release is blocked.

Why does my app request a permission I never added?

Because a dependency merged it in. Android manifest merging means a library's manifest entries become part of your app's manifest, and the merged result is what Play evaluates rather than the file you wrote.

How do I see the permissions my app actually requests?

Read the merged manifest from the build output, not android/app/src/main/AndroidManifest.xml. The merged file is the one that ships, and it commonly contains entries no one on the team added.

Can I remove a permission a library adds?

Yes, with a tools:node="remove" entry in your own manifest, provided the library genuinely does not need it for the features you use. Test the affected feature afterwards, because removing something that is used produces a runtime failure rather than a build error.

What is the background location declaration?

A separate review for apps requesting location while in the background. It typically requires a demonstration video and a clear explanation of the user-facing feature, and it is one of the slowest approvals in the Console.

How long does approval take?

Google does not guarantee a time and these reviews are frequently slower than an ordinary release review. Submit the declaration well before you need the release, not alongside it.

Cite this pageshipcheck. “The Play permissions declaration.” Baker Ventures LLC, September 7, 2026. https://shipcheck.bakerventuresstudio.com/rejections/play-permissions-declaration/