Scoped Storage Stories: Durable Access
Android 10 is greatly restricting access to external storage via filesystem APIs. Instead, we need to use other APIs to work with content. This is the second post in a series where we will explore how to work with those alternatives, starting with the Storage Access Framework (SAF).
So, you used
ACTION_CREATE_DOCUMENT to get a
that you can use to read and/or write some content. Great!
You got that
Uri in the scope of some
Activity. Perhaps you called
directly on the
Activity. Or, perhaps you called
Fragment which, in turn, is managed by some
The good news is that your
Activity should be able to work with that
even across configuration changes.
The bad news is that your rights to that
Uri content end there, by default.
Uri in Other Components
You might try using that
Uri from other components in your app. Perhaps you
Uri in some shared repository and have another
Activity get that
Uri and try using it. Or, perhaps you try passing the
Uri to some
or try using it via
You will find out fairly quickly that your
Uri rights vanish. You have access
to the content identified by the
Uri from the
Activity that receives the
Uri, and that’s it.
You can pass along those rights to other components of your app, or even components of other apps. To do that, though, you need to:
Uriin the “data” facet of an
Intentto start the other component (e.g.,
val intent = Intent(this, TheOtherActivity::class.java) .setData(theUri) .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) startActivity(intent)
Intent flags indicate that you want to pass along the read or write
rights that your component has to the component that you are starting.
Note that this works for any
Uri, not just those from the Storage
ACTION_GET_CONTENT, for example, works the same as does
ACTION_OPEN_DOCUMENT in terms of these component-level access rights.
Getting Long-Term Access
Intent flags has clear limitations:
Not everything offers you a place to put those flags (e.g.,
Eventually, your process gets terminated, at which point all of your rights lapse
For Storage Access Framework
Uri values, you can request long-term access
to the content via
takePersistableUriPermission() on a
You just pass in the
Uri along with
This will give you the ability to work with that
Uri not only between components,
but between process invocations. You can save the
String representation of
Uri somewhere (e.g.,
SharedPreferences) and use it again in the future.
However, bear in mind that there is no guarantee that the underlying content
itself is durable. The user might use some other app to move or delete that
content, at which point your persisted
Uri becomes pointless. You will need to
be able to deal with the
FileNotFoundException and related forms of
that you will get when this sort of thing occurs.
In addition to
takePersistableUriPermission(), there is:
releasePersistableUriPermission(), to say that you no longer need durable access; and
getPersistedUriPermissions(), to retrieve information about all outstanding persisted permissions that you took using
takePersistableUriPermission()and have not released using
What Else Is There?
Previously, I covered the basics of using the Storage Access Framework.
Upcoming posts in this series will include:
Need Android app development training for your team? Mark Murphy has trained hundreds! Learn more!