This is some working code I have for downloading a given URL to a given File object. The File object (outputFile) has just been created using new File(path), I haven't called createNewFile or anything.

private static void downloadFile(String url, File outputFile) {
  try {
      URL u = new URL(url);
      URLConnection conn = u.openConnection();
      int contentLength = conn.getContentLength();

      DataInputStream stream = new DataInputStream(u.openStream());

        byte[] buffer = new byte[contentLength];
        stream.readFully(buffer);
        stream.close();

        DataOutputStream fos = new DataOutputStream(new FileOutputStream(outputFile));
        fos.write(buffer);
        fos.flush();
        fos.close();
  } catch(FileNotFoundException e) {
      return; // swallow a 404
  } catch (IOException e) {
      return; // swallow a 404
  }
}
Answer from Eric Mill on Stack Overflow
Top answer
1 of 6
55

This is some working code I have for downloading a given URL to a given File object. The File object (outputFile) has just been created using new File(path), I haven't called createNewFile or anything.

private static void downloadFile(String url, File outputFile) {
  try {
      URL u = new URL(url);
      URLConnection conn = u.openConnection();
      int contentLength = conn.getContentLength();

      DataInputStream stream = new DataInputStream(u.openStream());

        byte[] buffer = new byte[contentLength];
        stream.readFully(buffer);
        stream.close();

        DataOutputStream fos = new DataOutputStream(new FileOutputStream(outputFile));
        fos.write(buffer);
        fos.flush();
        fos.close();
  } catch(FileNotFoundException e) {
      return; // swallow a 404
  } catch (IOException e) {
      return; // swallow a 404
  }
}
2 of 6
12

Permission

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />

Download Fuction Code

 public void downloadFile() {
        String DownloadUrl = audio1;
        DownloadManager.Request request1 = new DownloadManager.Request(Uri.parse(DownloadUrl));
        request1.setDescription("Sample Music File");   //appears the same in Notification bar while downloading
        request1.setTitle("File1.mp3");
        request1.setVisibleInDownloadsUi(false);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            request1.allowScanningByMediaScanner();
            request1.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
        }
        request1.setDestinationInExternalFilesDir(getApplicationContext(), "/File", "Question1.mp3");

        DownloadManager manager1 = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
        Objects.requireNonNull(manager1).enqueue(request1);
        if (DownloadManager.STATUS_SUCCESSFUL == 8) {
        DownloadSuccess(); 
        }
    }
🌐
Medium
medium.com › @eliothijanoc › simple-way-to-download-and-read-files-on-android-api-28-3557e6d240e5
Simple way to download and read files on android API>28 | by Eliot Hijano | Medium
August 16, 2021 - Even though this is good news for ... 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 ...
🌐
GeeksforGeeks
geeksforgeeks.org › android › how-to-download-file-from-url-in-android-programmatically-using-download-manager
How to Download File from URL in Android Programmatically using Download Manager? - GeeksforGeeks
July 23, 2025 - Below is the code for the MainActivity.java file. ... import android.app.DownloadManager; import android.content.Context; import android.net.Uri; import android.os.Bundle; import android.view.View; import android.widget.Button; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { Button button; DownloadManager manager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = findViewById(R.id.download); button.setOnClickListener(new View.OnClickListener()
🌐
Iditect
iditect.com › program-example › download-a-file-programmatically-on-android.html
Download a file programmatically on Android
To download a file programmatically on Android, you can use the DownloadManager system service. Here's an example of how to download a file using the DownloadManager in Android:
🌐
Android Developers
developer.android.com › api reference › downloadmanager
DownloadManager | API reference | Android Developers
Skip to main content · English · Deutsch · Español – América Latina · Français · Indonesia · Polski · Português – Brasil · Tiếng Việt · 中文 – 简体
🌐
Blogger
techicaltutorial.blogspot.com › 2020 › 03 › android-download-file-programmatically-example.html
android download file programmatically example - Android Tutorial
March 26, 2020 - strings) { String apkUrl = strings[0]; try { if (!outputFile.exists()) { notifyFromBackground("Downloading..."); URL url = new URL(apkUrl); HttpURLConnection c = (HttpURLConnection) url.openConnection(); c.setDoOutput(true); c.connect(); file.mkdirs(); FileOutputStream fos = new FileOutputStream(outputFile); InputStream is = c.getInputStream(); byte[] buffer = new byte[2048]; int len1 = 0; while ((len1 = is.read(buffer)) != -1) { fos.write(buffer, 0, len1); } fos.close(); is.close(); } // Do the install notifyFromBackground("Installing..."); Intent promptInstall = new Intent(Intent.ACTION_VIEW
Find elsewhere
🌐
Stack Overflow
stackoverflow.com › questions › 14998212 › how-to-open-downloaded-file-in-android-programatically
java - How to open downloaded file in Android programatically? - Stack Overflow
44 Call Main thread from secondary thread in Android · 11 How to launch browser to open local file · 35 Download a file programmatically on Android · 13 Android open file · 1 Opening file on android · 7 android cannot open downloaded file · 4 Android open downloaded file ·
🌐
Android Developers
developer.android.com › core areas › app data and files › access documents and other files from shared storage
Access documents and other files from shared storage | App data and files | Android Developers
The Download directory. Furthermore, on Android 11 (API level 30) and higher, you cannot use the ACTION_OPEN_DOCUMENT_TREE intent action to request that the user select individual files from the following directories:
🌐
Stack Overflow
stackoverflow.com › questions › 60113588 › best-ways-to-download-files-on-android-programmatically
best ways to download files on Android programmatically? - Stack Overflow
Are you going to other types of network requests as well? If so, making use of Volley (pretty good article exactly for downloading files) makes sense to introduce a library specialized in networking requests otherwise it's just overhead and increases the size of the app.
🌐
Stack Overflow
stackoverflow.com › questions › 21672455 › how-to-download-a-file-programmatically-and-show-it-as-a-download-in-android
How to download a file programmatically and show it as a download in Android - Stack Overflow
I'm trying to make an app to download files, I can do it, but when I go to de Downloads application in the Android device, the downloaded file isn't there. I've tried to download that file in many ...
🌐
GitHub
github.com › itinance › react-native-fs › issues › 950
Unable to download file in Android 11 (ENOENT: no such file or directory, open '/storage/emulated/0/fileName.pdf') · Issue #950 · itinance/react-native-fs
November 13, 2020 - import React from 'react'; import { SafeAreaView, View, Text, StatusBar, TouchableOpacity, } from 'react-native'; import {downloadPDFFile} from './src/FileHelper'; const App = () => { return ( <> <StatusBar barStyle="dark-content" /> <SafeAreaView> <View style={{flex:1, marginTop: '50%', marginLeft: '10%'}}> <TouchableOpacity style={{ justifyContent:'center', alignItems:'center', width: '80%', height: 40, backgroundColor: 'green' }} onPress={() => { downloadPDFFile((res) => { console.log(res); }); }}> <Text style={{color: '#000000'}}>Download File</Text> </TouchableOpacity> </View> </SafeAreaV
Author   itinance
Top answer
1 of 2
5

I found an solution on Stackoverflow (Can't find the link anymore)

 private boolean downloadTask(String url) throws Exception {
    if (!url.startsWith("http")) {
        return false;
    }
    String name = "temp.mcaddon";
    try {
        File file = new File(Environment.getExternalStorageDirectory(), "Download");
        if (!file.exists()) {
            //noinspection ResultOfMethodCallIgnored
            file.mkdirs();
        }
        File result = new File(file.getAbsolutePath() + File.separator + name);
        DownloadManager downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
        request.setDestinationUri(Uri.fromFile(result));
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        if (downloadManager != null) {
            downloadManager.enqueue(request);
        }
        //mToast(mContext, "Starting download...");
        MediaScannerConnection.scanFile(DetailsActivity.this, new String[]{result.toString()}, null,
                new MediaScannerConnection.OnScanCompletedListener() {
                    public void onScanCompleted(String path, Uri uri) {
                    }
                });
    } catch (Exception e) {
        Log.e(">>>>>", e.toString());
        //mToast(this, e.toString());
        return false;
    }
    return true;
}

This should work for Android 11

2 of 2
0

Use this Function it save File in Download folder :

private boolean downloadTask(String url , String name) throws Exception {
               try {
                   File file = new File(Environment.getExternalStorageDirectory(), "Download");
                   if (!file.exists()) {
                       //noinspection ResultOfMethodCallIgnored
                       file.mkdirs();
                   }
                   File result = new File(file.getAbsolutePath() + File.separator + name);
                   DownloadManager downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
                   DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
                   request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
                   request.setDestinationUri(Uri.fromFile(result));
                   request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
                   request.setAllowedOverRoaming(false).setTitle(name);//for mp3 title
                   request.setDescription("Something useful. No, really.");
                   if (downloadManager != null) {
                       downloadManager.enqueue(request);
                   }
                   //mToast(mContext, "Starting download...");
                   MediaScannerConnection.scanFile(MainActivity.this, new String[]{result.toString()}, null,
                           new MediaScannerConnection.OnScanCompletedListener() {
                               public void onScanCompleted(String path, Uri uri) {
                                   Log.i("tag >>>>", "on Downlaod check it");
                                   

                               }
                           });
               } catch (Exception e) {
                   Log.i("tag >>>> ", e.toString());
                   return false;
               }
               return true;
           }

But in Manifest add some lines.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />

<application
        android:requestLegacyExternalStorage="true"
        android:usesCleartextTraffic="true"
  >

Add this line in OnCreate :

//check permission
if (Build.VERSION.SDK_INT >= 23) {
    Log.i("log ", "if in Build.VERSION.SDK_INT>=23");
    checkper(); //<-- this is a function
} else {
    Log.i("log ", " else else in Build.VERSION.SDK_INT>=23");
}

This is checkper() Function:

private final int MY_PERMISSIONS_REQUEST_READ_CONTACTS = 1;
    private void checkper() {
        if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {


            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO},
                    MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        } else if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO},
                    MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        } else if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO},
                    MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        } else if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {

            ActivityCompat.requestPermissions(MainActivity.this,
                    new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO},
                    MY_PERMISSIONS_REQUEST_READ_CONTACTS);

        } else {

            Log.i("log", "else in checkper()");
            //your code
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED
                        && grantResults[1] == PackageManager.PERMISSION_GRANTED
                        && grantResults[2] == PackageManager.PERMISSION_GRANTED
                        && grantResults[3] == PackageManager.PERMISSION_GRANTED) {

                    Log.i("log", "if in onRequestPermissionsResult()");
                    //dar seri aval har do ra dasti ok kardim amad inja
                    //your code
                } else {

                    Log.i("log", "else in onRequestPermissionsResult()");
                    // yeki taiiid kardi
                }

            }


        }//switch
    }//onRequestPermissionsResult
🌐
Stack Overflow
stackoverflow.com › questions › 69781962 › writing-a-file-to-download-folder-android-11-sdk-30
kotlin - Writing A File to Download Folder (Android 11 SDK 30) - Stack Overflow
October 30, 2021 - I'm developing an applicaiton using Android 11 and Kotlin. I've successfully written a file to the Download folder on the device. When writing to the folder again using the same file name, the resu...
🌐
Stack Overflow
stackoverflow.com › questions › 76930780 › how-to-download-files-in-android-using-java
How to download files in Android using Java - Stack Overflow
private void download(String title, String url) throws IOException { File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES+"/"+getPackageManager().getApplicationLabel(getApplicationInfo())); if (!directory.exists()) { directory.mkdir(); } File fileName = new File(directory,title); if(!fileName.exists()){ fileName.createNewFile(); } URL u = new URL(url); HttpURLConnection connect = (HttpURLConnection) u.openConnection(); if (connect.getResponseCode() != HttpURLConnection.HTTP_OK) { Log.w("ERROR SERVER RETURNED HTTP", connect.getResponseCode() + ""); } try (InputStream is = connect.getInputStream(); FileOutputStream fos = new FileOutputStream(fileName);) { byte[] bytes = new byte[1024]; int b = 0; while ((b = is.read(bytes, 0, 1024)) != -1) { fos.write(bytes, 0, b); } } }
🌐
Kodular
community.kodular.io › discuss
How To Downloads Files In Android 11 With Custom Folder? - Discuss - Kodular Community
July 1, 2022 - hello Kodulers… I want to downloads file in Android 11 with custom Filder…so how can i do it? please Help Me And give me Solution … Thanks
🌐
Medium
medium.com › @aungkyawmyint_26195 › downloading-file-properly-in-android-d8cc28d25aca
Downloading File properly in Android | by Aung Kyaw Myint | Medium
June 26, 2019 - To start download process, we need to prepare DownloadManger.Request which contains all the information to request a new download. While the URI is the only required parameter, if we don’t provide the file destination for downloaded file, the default is a shared volume where the system might delete your file if it needs to reclaim space for system use.
Top answer
1 of 5
44

More than 10 months have passed and yet not a satisfying answer for me have been made. So I'll answer my own question.

As @CommonsWare states in a comment, "get MediaStore.Downloads.INTERNAL_CONTENT_URI or MediaStore.Downloads.EXTERNAL_CONTENT_URI and save a file by using Context.getContentResolver.insert()" is supposed to be the solution. I double checked and found out this is true and I was wrong saying it doesn't work. But...

I found it tricky to use ContentResolver and I was unable to make it work properly. I'll make a separate question with it but I kept investigating and found a somehow satisfying solution.

MY SOLUTION:

Basically you have to download to any directory owned by your app and then copy to Downloads folder.

  1. Configure your app:

    • Add provider_paths.xml to xml resource folder

      <paths xmlns:android="http://schemas.android.com/apk/res/android">
          <external-path name="external_files" path="."/>
      </paths>
      
    • In your manifest add a FileProvider:

      <application>
          <provider
               android:name="androidx.core.content.FileProvider"
               android:authorities="${applicationId}.provider"
               android:exported="false"
               android:grantUriPermissions="true">
               <meta-data
                   android:name="android.support.FILE_PROVIDER_PATHS"
                   android:resource="@xml/provider_paths" />
           </provider>
       </application>
      
  2. Prepare to download files to any directory your app owns, such as getFilesDir(), getExternalFilesDir(), getCacheDir() or getExternalCacheDir().

    val privateDir = context.getFilesDir()
    
  3. Download file taking its progress into account (DIY):

    val downloadedFile = myFancyMethodToDownloadToAnyDir(url, privateDir, fileName)
    
  4. Once downloaded you can make any threatment to the file if you'd like to.

  5. Copy it to Downloads folder:

    //This will be used only on android P-
    private val DOWNLOAD_DIR = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
    
    val finalUri : Uri? = copyFileToDownloads(context, downloadedFile)
    
    fun copyFileToDownloads(context: Context, downloadedFile: File): Uri? {
        val resolver = context.contentResolver
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val contentValues = ContentValues().apply {
                put(MediaStore.MediaColumns.DISPLAY_NAME, getName(downloadedFile))
                put(MediaStore.MediaColumns.MIME_TYPE, getMimeType(downloadedFile))
                put(MediaStore.MediaColumns.SIZE, getFileSize(downloadedFile))
            }
            resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)
        } else {
            val authority = "${context.packageName}.provider"
            val destinyFile = File(DOWNLOAD_DIR, getName(downloadedFile))
            FileProvider.getUriForFile(context, authority, destinyFile)
        }?.also { downloadedUri ->
            resolver.openOutputStream(downloadedUri).use { outputStream ->
                val brr = ByteArray(1024)
                var len: Int
                val bufferedInputStream = BufferedInputStream(FileInputStream(downloadedFile.absoluteFile))
                while ((bufferedInputStream.read(brr, 0, brr.size).also { len = it }) != -1) {
                    outputStream?.write(brr, 0, len)
                }
                outputStream?.flush()
                bufferedInputStream.close()
            }
        }
    }
    
  6. Once in download folder you can open file from app like this:

    val authority = "${context.packageName}.provider"
    val intent = Intent(Intent.ACTION_VIEW).apply {
        setDataAndType(finalUri, getMimeTypeForUri(finalUri))
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP) {
            addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION)
        } else {
            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        }
    }
    try {
        context.startActivity(Intent.createChooser(intent, chooseAppToOpenWith))
    } catch (e: Exception) {
        Toast.makeText(context, "Error opening file", Toast.LENGTH_LONG).show()
    }
    
    //Kitkat or above
    fun getMimeTypeForUri(context: Context, finalUri: Uri) : String =
        DocumentFile.fromSingleUri(context, finalUri)?.type ?: "application/octet-stream"
    
    //Just in case this is for Android 4.3 or below
    fun getMimeTypeForFile(finalFile: File) : String =
        DocumentFile.fromFile(it)?.type ?: "application/octet-stream"
    

Pros:

  • Downloaded files survives to app uninstallation

  • Also allows you to know its progress while downloading

  • You still can open them from your app once moved, as the file still belongs to your app.

  • write_external_storage permission is not required for Android Q+, just for this purpose:

    <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        android:maxSdkVersion="28" />
    

Cons:

  • You won't have access to downloaded files once after clearing your app data or uninstalling and reinstalling again (they no longer belongs to your app unless you ask for permission)
  • Device must have more free space to be able to copy every file from its original directory to its final destination. This is important speacially for large files. Although if you have access to the original inputStream you could directly write to downloadedUri instead of copying from an intermediary file.

If this approach is enough for you then give it a try.

2 of 5
12

You can use the Android DownloadManager.Request. It will need the WRITE_EXTERNAL_STORAGE Persmission until Android 9. From Android 10/ Q and above it will not need any permission (it seems it handle the permission itself).

If you want to open the file afterwards, you will need the user's permission instead (also if you only want to open it within an external app (e.g. PDF-Reader).

You can use the download manager like this:

DownloadManager.Request request = new DownloadManager.Request(<download uri>);
request.addRequestHeader("Accept", "application/pdf");
    
// Save the file in the "Downloads" folder of SDCARD
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,filename);

DownloadManager downloadManager = (DownloadManager) getActivity().getSystemService(Context.DOWNLOAD_SERVICE);
downloadManager.enqueue(request);

This are the references: https://developer.android.com/reference/kotlin/android/app/DownloadManager.Request?hl=en#setDestinationInExternalPublicDir(kotlin.String,%20kotlin.String)

https://developer.android.com/training/data-storage

🌐
Medium
medium.com › @zohaibansari100 › a-guide-for-downloading-files-to-external-storage-in-your-android-application-e4b2d8193d41
A guide for Downloading files to External Storage in your Android Application.
November 21, 2019 - After searching through many recent open source projects and asking devs on stackoverflow and reddit, I realized that everyone was achieving this in a similar way, i.e using a separate file which manages the download by creating a File instance programmatically and passing it to the local storage through a file output stream.