The permission Play rejected isn't in your manifest
Google Play reviews the merged manifest, not the one you wrote. Here is how to see what your release build really asks for, strip what a library added, and replace media permissions with the photo picker.

Play Console flags a restricted permission on your update. You open AndroidManifest.xml, search for it, and find nothing. You never added it. It is still in the build.
That is the most common way a permission problem catches people. This post walks through why it happens and how to fix it for good, using Chapter 4 (Sensitive Permissions) of Pass Google Play Review.
The trap: you are reading the wrong manifest
Google Play treats some permissions as restricted. You may only ship them when a simpler, narrower option cannot do the job, and several need a declaration in Play Console before an update can be sent.
The surprise is rarely a permission you added. It is one a library merged in. The final manifest is a merge of yours and every dependency's. Libraries contribute permissions, services and receivers. The merged result is what ships, and it is what Play reviews. So searching your own source file and finding nothing alarming proves very little.
Step 1: look at what you actually ship
Check the permissions in the built release, not the source:
# APK: list permissions from the merged manifest
apkanalyzer manifest permissions app/build/outputs/apk/release/app-release.apk
In Android Studio you can also open your manifest and switch to the Merged Manifest tab. It shows each entry and which library contributed it. That tells you whether a permission is yours or came along with a dependency.
Step 2: remove what a library added and you don't need
tools:node="remove" takes an unwanted entry out of the merged result:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"
tools:node="remove" />
</manifest>
Run apkanalyzer on the new release build afterwards and confirm the permission is gone from the list.
Step 3: pick the narrower option first
For every restricted permission, the book's rule is to ask in a fixed order. Most features have a narrower option that needs no permission and no declaration.
| Permission | Narrower option first | If you really need it |
|---|---|---|
| READ_MEDIA_IMAGES, READ_MEDIA_VIDEO | Photo picker | Core broad-access use only (gallery-type apps), declaration |
| MANAGE_EXTERNAL_STORAGE | Storage Access Framework, MediaStore | Declaration; core need only |
| ACCESS_BACKGROUND_LOCATION | Foreground location while in use | Declaration form, video, prominent disclosure, privacy policy |
| USE_EXACT_ALARM | Inexact alarms, WorkManager, SCHEDULE_EXACT_ALARM | Calendar and alarm clock apps only |
Photos and videos: the picker needs no permission
Play Console Help ("Understanding Restricted Permissions with minimum scope alternatives", checked October 2026) says apps targeting Android 13 or later may only request READ_MEDIA_IMAGES and READ_MEDIA_VIDEO if system pickers like the Android Photo Picker are not sufficient for core functionality. Full compliance became mandatory on May 28, 2025.
Gallery-type apps that manage all of a user's photos qualify. An app that lets the user choose a picture to edit, attach or upload does not. A custom picker does not automatically qualify either.
The photo picker needs no permission at all. With androidx.activity 1.7.0 or higher, in Compose:
@Composable
fun AvatarPicker(onPicked: (Uri) -> Unit) {
val pickMedia = rememberLauncherForActivityResult(
ActivityResultContracts.PickVisualMedia()
) { uri ->
if (uri != null) onPicked(uri) // null when the user backs out
}
Button(onClick = {
pickMedia.launch(
PickVisualMediaRequest(
ActivityResultContracts.PickVisualMedia.ImageOnly
)
)
}) { Text("Choose photo") }
}
A few details from the chapter:
- On devices without the picker, the library falls back to
ACTION_OPEN_DOCUMENTon its own. - Use
PickMultipleVisualMedia(maxItems)for several items. - By default, access to a picked item lasts until the device restarts or the app stops. If you upload in the background, persist it:
context.contentResolver.takePersistableUriPermission(
uri, Intent.FLAG_GRANT_READ_URI_PERMISSION
)
The picker grants access to exactly what the user selects and nothing else. There is no permission prompt, no declaration, and nothing to justify in Play Console.
A case note from a real app
The book includes a case note from the author's own app, CaptionBurn (com.charlesh.captionburn). Play Console refused to send a CaptionBurn update with the issue "Use alternative system pickers for photos / videos". The live bundle requested READ_MEDIA_VIDEO.
The app already chose videos with PickVisualMedia, so the permission had no job. The fix removed it from the build. The current manifest in chartmann1590/captionburn strips every media and storage permission a library might merge in, with tools:node="remove":
READ_MEDIA_IMAGESREAD_MEDIA_VIDEOREAD_MEDIA_VISUAL_USER_SELECTEDREAD_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGE
One more detail worth knowing: the Photo and video permissions declaration page kept listing the old permission from the live bundle until the new release went live. Seeing it there after the fix does not mean the fix failed.
Checklist before you send an update
- Read the permission list from the release build with
apkanalyzer manifest permissions, not from your source manifest. - Check the Merged Manifest tab to see which library added each entry.
- Remove unused library permissions with
tools:node="remove". - Choose media with the photo picker. No
READ_MEDIA_*unless the app is gallery-type. - Persist picked URIs with
takePersistableUriPermissionif you upload in the background. - For every other restricted permission, try the narrower option in the table first.
- After the fix ships, expect the declaration page to show the old permission until the new release is live.

