A photo-selection flow can work exactly as expected while the application declares more access than it needs. Our Android media-permission design record describes a store rejection that led the team beyond a single permissions array: config plugins and dependency manifests also contributed declarations. For an Expo application that generates native projects, the built manifest is the evidence that matters. This is a focused companion to my broader Expo production article, explaining permission provenance without claiming that a working picker alone proves policy compliance or that a configuration edit establishes store approval.
A user task should justify the requested access
Selecting one progress photo or profile picture is a narrow task. Browsing an entire media library continuously is a different task. The permission request should match the capability the product needs, rather than inherit every declaration a package can support.
Android’s system photo picker offers a narrower selection path than broad media-library access for supported scenarios. That makes the task a useful starting point for permission review. Do not begin by asking how to persuade a reviewer that every permission is necessary. First establish whether the user-facing workflow needs it at all.
The configuration array is not the whole native app
In a generated native project, several inputs can influence the final Android manifest. Explicit configuration is one. Config plugins can add declarations. Library manifests can merge their own declarations during the native build. Removing one source does not necessarily remove the final permission.
The team’s design record identifies this multi-source problem. It is a useful reminder that declarative configuration is an input to a build process, not the resulting artifact. A clean source file can coexist with an overbroad merged manifest. The review must follow the build far enough to inspect what the package will actually contain.
Scroll the table horizontally to see all columns.
| Contributor | What to inspect |
|---|---|
| Explicit configuration | Declared application permissions |
| Config plugin | Changes made during native generation |
| Dependency manifest | Declarations merged from libraries |
| Built artifact | Actual result submitted for review |
Unused packages can still affect a build
A dependency need not be imported by a screen to contribute native configuration. A registered plugin or bundled manifest can participate in generation regardless of whether the visible interface uses the package. That creates a gap between “we do not call this API” and “the application does not declare this access.”
I would inventory native dependencies and plugins against actual product usage. Removing an unused package can be the simplest correction when it contributes unnecessary declarations, but verify its other roles first. A dependency cleanup should not accidentally remove a capability another feature relies on. The generated result remains the final check.
Fix the source of truth, then regenerate
For projects using native generation, hand-editing a generated manifest can produce a temporary success that disappears on the next build. The durable fix belongs in configuration, plugin composition or a narrowly scoped manifest adjustment that runs reproducibly.
The historical plan includes stripping residual broad media declarations and checking the regenerated output. I would review that pattern against the current Expo and Android versions before reusing it. The goal is not to copy a private plugin. It is to ensure that a fresh generation produces the intended minimal set without relying on an unrecorded manual edit.
The submitted native artifact is the result of several inputs
A working photo-picker interaction does not establish which permissions are declared in the installed build.
Build inputs
- Application configuration
Review the explicit declarations and intended user task.
- Plugins + dependency manifests
Inspect what generation and manifest merging add.
- Built native artifact
Verify the final declarations and the picker flow on the actual release path.
Fix the source, regenerate, inspect and test. An over-the-air JavaScript update cannot remove a native manifest declaration.
Native declarations require a native release
An over-the-air JavaScript update cannot rewrite the manifest inside a binary already installed on a device. If the problem is a native permission declaration, the corrected application needs a compatible new binary and the normal store process. That boundary is easy to miss when many interface changes can be shipped through OTA.
The existing Expo production guide discusses this broader native-versus-JavaScript distinction. Here it becomes a concrete release decision. Validate the build output before submission, then distinguish submitted, accepted and available-to-users states. The reviewed design leaves resubmission as a manual step, so this article does not manufacture a later approval result.
Review the artifact and the interaction
A useful acceptance pass includes the generated manifest, package configuration and a real selection flow on supported devices. Test choosing one image, cancelling, changing permission state and revisiting the screen. A successful TypeScript check cannot establish the operating system’s permission dialog or store policy outcome.
Keep the test evidence precise. A source-derived React Native figure demonstrates layout and component behaviour under fictional data. It is not a native permission test. Device behaviour needs device evidence. Clear labels prevent a polished article image from being mistaken for proof that a store submission passed.
Keep policy explanations current and narrow
Store policy changes over time, so a copied justification from an old document can become inaccurate. Use current official requirements and describe the actual feature rather than a planned future use. Do not add unsupported device or medical claims to make a permission seem more important.
A narrower application can be easier for users to trust as well as easier to explain. Asking for one selected image at the moment it is needed gives a clearer mental model than requesting a whole library during onboarding. That is a product-design benefit, but it should not be turned into an invented conversion statistic.
Questions worth asking
Why does the permission reappear after I remove it? Inspect config plugins and dependency manifests, then examine a freshly generated build. The visible configuration array may be only one contributor.
Can I ship the fix with EAS Update? Not when the required change is in the installed native manifest. Follow the native-build release path and runtime compatibility rules.
Does passing the local checklist guarantee approval? No. It establishes technical evidence for the reviewed build. Store acceptance is a separate outcome governed by current requirements and the actual submitted artifact.
Sources
Technical references checked .


