All entries

    The Photo Picker Worked. Google Play Still Rejected the App.

    Why Android permissions can return through plugins and merged manifests, how to inspect generated native output, and why this fix needs a new binary.

    Mobile development bench with selected photos, manifest layers and narrowly scoped permissions against futuristic Tokyo
    GPT-generated technical pixel-art illustration with a futuristic city backdrop. Conceptual engineering imagery, not a product screenshot or measured result.

    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.

    The configuration array is not the whole native app
    ContributorWhat to inspect
    Explicit configurationDeclared application permissions
    Config pluginChanges made during native generation
    Dependency manifestDeclarations merged from libraries
    Built artifactActual 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.

    EXPLAINED / SYSTEM FLOW

    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

    1. Application configuration

      Review the explicit declarations and intended user task.

    2. Plugins + dependency manifests

      Inspect what generation and manifest merging add.

    3. Built native artifact

      Verify the final declarations and the picker flow on the actual release path.

    THE KEY DISTINCTION

    Fix the source, regenerate, inspect and test. An over-the-air JavaScript update cannot remove a native manifest declaration.

    Build-layer model for the article’s permission issue, not a screenshot of the permission dialog or a policy guarantee.

    Do not remove unrelated capabilities blindly

    A focused media fix should not delete camera, microphone or health-related declarations merely because they appear nearby. Each has its own product justification and runtime behaviour. The right review asks whether the specific capability is needed and whether the application requests it appropriately.

    Likewise, do not assume every runtime permission call becomes a harmless no-op on every supported platform. Library and operating-system versions matter. Verify the actual path used by the installed app. A policy-oriented change should preserve the intended selection flow and handle cancellation or denial without trapping the user.

    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.

    FURTHER READING

    Sources

    Technical references checked .

    END OF ENTRY / 21
    BEHIND THE JOURNAL

    Eeshan Singh

    I’m Eeshan Singh Pokharia, an AI Full Stack Developer and CoFounder of UltraFit360. I work across AI features, full-stack product development, and web and mobile experiences—from Figma and frontend interactions to the systems behind them.

    This issue connects my mobile interface work to the binary that actually reaches the store. I want the lesson to be concrete: review the generated native result, distinguish implemented changes from store acceptance, and avoid promising broad access for a one-photo task.

    Meet the author