Simple way to download and read files on android API>28

Eliot Hijano
2 min readAug 16, 2021

Android 10+ has introduced a new way for apps to access storage. Even though this is good news for users, it has changed the way developers have to code apps in order to write and read documents programmatically.

For API<29, the old paradigm consisted on adding the following permissions to our Manifest file

The line android:maxSdkVersion=”28" is needed to avoid the dreaded warning stating “WRITE_EXTERNAL_STORAGE no longer provides access when targeting Android 11+, even when using requestLegacyExternalStorage”, which invalidates the usual hack. For systems with API≤28, these permissions are enough and we can download papers as usual. For example,

One could then open the downloaded file programmatically simply by using the command

Needless to say, for API≥29, this code is deprecated and entirely useless. The new scoped storage changes fundamentally the way apps access local data in our phone.

A way to make everything work again is through the use of the DownloadManager class. Lets imagine we have to download a file in the background of our app. For this, we create an asynchronous task, which I will call “downloadPDFTask”. Instead of using the deprecated class AsyncTask, I will use my own class BaseTask. Don’t worry though, they do basically the same thing.

In this task, the downloadManager requests a download from a given url address, and queues it on your phone’s download manager. The target directory is the Downloads folder, in an abstract sense. We do not need to specify exactly the path where the document is being downloaded. The result of the operation “enqueue” is a “Long” instance containing a number that identifies the download. It is the “id” associated to the file that the task has downloaded. This id can then be used to open the downloaded file by our app.
Lets assume that the method “receiveDownloadId” called by our context activity updates a “long” variable that now contains the download identification number. Something like

public void receiveDownloadId(Long id){ downloadID = id; }

We can then locate the downloaded file as follows

The resulting Uri can be used to open a file with

File pdfFile = new File(pdfUri.getPath());

or we can open the pdf in some other app using something fancier like

All in all, it is pretty trivial to download and open files on your app in Android 11+. We don’t even need to be careful about what path exactly is being used when downloading, as we can extract Uri’s from the download id’s generated by DocumentManager.

I hope this helps other people updating their apps for ≥Build.VERSION_CODES.Q !

--

--