Sharing files on Android in a world with runtime permissions

There are some growing pains we're going to experience while upgrading to runtime permissions.

The most painful one I've run into so far is sharing files. When done correctly, sharing a file involves a sender app creating an accessible URI and a receiver app reading a stream of data from that URI.

Unfortunately, there are two common problems people run into when implementing sharing:

  1. Creating a URI is easy, but granting permissions can be tricky.
  2. Badly written receivers expect the URI will be a file. If you send them a more generic URI they might not know how to handle it!

The easy (but short-sighted) solution to both problems is to use external storage. That way they're all files and they're all globally readable.

Enter Marshmallow: READ_EXTERNAL_STORAGE is, understandably, a dangerous permission. You need to request it explicitly at runtime.

Ideally, you wouldn't need it at all! If both the sender and receiver work correctly, they can share files without any dangerous permissions. The problem is both apps need to handle file sharing correctly to achieve permission-free nirvana. In particular, if the sending app uses external storage then the receiver needs access.

The unfortunate conclusion is that your receiver app will still need access to external storage, even if you do everything correctly. There are plenty of apps out there that still use external storage for sharing.

Here's normally where I'd write about how to properly share files, but Google has already done that for me. Everyone who is sharing files ought to read and follow these directions.

In the meantime, be aware that you'll have to request READ_EXTERNAL_STORAGE if your receiver app gets a URI that leads to external storage. The process I added to Trello is:

  1. Receive a URI.
  2. Attempt to query metadata about the URI.
    • If successful, we're all good!
    • If failure, then request permission for READ_EXTERNAL_STORAGE.
  3. Read the file from the URI.

If you want to test your app against a bad app, try my Rage Faces app (and source). In my defense, I was much worse at Android development back then.

I'd written this post and was editing today when Mark Murphy put out a post on exactly the same topic. He's got more specific technical tips than I present here so I highly suggest you go read it.