Articles · App ExamplesUpdated September 2026

Add a file picker to an app in an afternoon, then deal with what it hands back.

To add a file picker to an app you call the picker the operating system already ships, the user browses their phone and their cloud drives, and your code is handed a reference to whatever they chose. That takes an afternoon. The honest limit is the reference itself: on both platforms it is temporary, so a path you save today is dead after the next restart. If the files you want are photos rather than documents, the shorter route is adding photo upload instead.

This page covers what the picker actually returns, the real difference between the iOS and Android file models, how to stop users choosing a file you cannot open, and what has to happen in the seconds after someone taps a document.

See what your picker should accept

The short version

Call the system picker, then copy what it gives you straight away.

Both platforms ship a document picker. You call it, the user chooses, and you get a reference back. There is no file browser to build and no storage permission prompt to design, because the act of choosing is the permission.

Everything after that is the work. The reference expires, in different ways on each platform, so decide early whether you need the file once or for good. Once means read it and forget it. For good means copy or upload the bytes while the grant is still live, and treat what arrives as untrusted input.

What the picker hands back is not a file path

The picker is a single call and the result looks deceptively simple: a name, a size, a type and a URI. The URI is where people go wrong. It is a grant of access, scoped and time limited, not an address you can write into a database and open again next Tuesday.

Apple is blunt about it. The open and move operations provide security-scoped URLs for external documents, your app has to call startAccessingSecurityScopedResource before reading and stopAccessingSecurityScopedResource afterwards, and the documentation says outright not to save the URLs those operations provide. If you want that document again later, you save a bookmark created with the security scope option instead. The picker can also hand you a copy, though Apple's advice is to avoid copying when you can.

So the first decision is not which picker library to install. It is whether you need the file once or forever. Once means read it, act on it, drop the reference. Forever means getting the bytes somewhere you control before the grant goes away, and that is a storage decision, not a picker decision.

Apple, UIDocumentPickerViewController

iOS and Android do not agree on what a file is

This is the difference that decides how much code you write. On iOS the document picker reaches outside your app sandbox into the Files app, iCloud Drive and any other document provider the user has installed. You get a security-scoped URL, you open it, you release it. Access is per document and it is yours only while you hold it open.

On Android the same job runs through the Storage Access Framework. The user chooses a documents provider, which can be an external storage volume or cloud storage, and your app gets read and write access to a URI representing that document. Because the user made the choice in a system picker, this needs no storage permission at all. The catch is the lifetime: that URI permission grant lasts until the device restarts. To keep it you call takePersistableUriPermission, and even then you lose access if the document is later moved or deleted.

Two smaller Android details catch people out on the first real upload. The display name you read back is provider specific and is not necessarily the file name. The size column can be null, because the picker is allowed to return a remote file whose size is not known locally. Build the screen that lets someone choose a file in a mobile app as if the name and the size might both be missing, because sometimes they are.

Android Developers, access documents and other files from shared storage

Filter the file types before the picker opens

A picker with no filter is a support queue. Both platforms let you declare what you accept and then grey out everything else, so nobody can pick a document in app screens you have no parser for. Android takes MIME types such as application/pdf. iOS takes its own content type identifiers, and a cross-platform picker maps between the two for you.

Keep the list as narrow as your code is, and set a size limit in the same breath. A wildcard filter plus a phone full of 4K video is how a new upload feature dies in its first week. Decide about multiple selection at the same time: it is normally off by default, and turning it on changes your upload screen from one progress bar into a list with per-file failures.

Accepting a document is the easy half. If the point is that someone can upload a PDF from a phone and then read it back inside the app, the viewing screen is separate work, and that is covered in add pdf viewer.

Try it

What your picker should let through

Tap what your app can actually open. Everything else should never reach your code in the first place.

application/pdf

The picker greys out the rest, so nobody can hand you a file you have no code for.

Where the file goes in the next five seconds

Once you hold the handle you have three honest options: read it and act now, copy it into storage your app owns, or push it straight to a server. Some libraries make the copy for you. In a React Native and Expo project the module is expo-document-picker, and it copies the chosen file into the app cache directory by default so the rest of your code can read it immediately, at the cost of a pause on large files.

If the file goes to a server, you have just chosen a backend, and that is a real decision rather than a detail. Storage cost, signed upload URLs, resumable uploads and who is allowed to read the file back all arrive together. Those trade-offs are the same ones set out in vibe coding backend database, and they are cheaper to settle before the picker ships than after.

Then there is the part most first versions skip. A picked file is user input. The name can lie, the extension can lie, the declared type can lie, and on Android you may not get a size until you read the thing. Validate on your own server, cap the size, and never build a storage path out of the name someone handed you. The full version of that argument, including why the client cannot be the one checking, is in trusting a file a user picked.

Five ways to handle a picked file, and what each costs

RouteTakes any documentFile is there next weekCosts you storageRough effort
Pick, read, forget the referenceYesNoNoan afternoon
Pick and copy into the appYeson that phone onlydevice onlya day
Pick and upload to your serverYesYesYesa few days
Photo library picker onlyNoon that phone onlydevice or serveran hour
Link to a cloud file insteadNoif nobody moves itNoa day, plus sign in

Building the picker into an app you own

Most of the cost in this feature is never the picker. It is the plumbing behind it: somewhere to put files, an upload state that survives the app being backgrounded, a retry that does not send the same invoice twice, and a list screen that shows what is already there. Form builders give you a file field and stop at their own storage, which is fine right up to the day you need the file somewhere else.

Newly is an AI app builder. You describe the app in plain English and it writes a real React Native and Expo project you own, runs it on a cloud iPhone or Android simulator while it builds, and ships it to TestFlight and to Google Play internal testing. Plans are $25 a month, there is no free plan, and iOS builds go through App Store Connect with your own Apple Developer account.

What it does not do is decide your storage for you. There is no bundled backend and no built-in payments, so the bucket, the database and the upload endpoint stay your choices. The code comes out either way: a ZIP from Settings, the CLI, or two-way GitHub sync from the Deploy tab into a repo you own.

Questions people ask about file pickers

You call the picker the platform already provides rather than building a file browser. On iOS that is the document picker, on Android it is the Storage Access Framework, and a cross-platform picker module wraps both. The call takes minutes. The work is deciding what file types you accept and what you do with the reference you get back, because that reference does not last.

Describe the upload your app actually needs

Say what files people will send, how big they get and where they have to end up, and build the picker and the plumbing behind it together.

Start building