Download file from url, save to phones storage
Asked Answered
C

6

46

I'm working on a project, that requires me to download a file from URL, once a button is tapped, and store it to phone storage (probably downloads folder).

Any ideas on how to do this? The file that is being downloaded is also not always the same and can be anything from an image to a pdf.

Callean answered 15/1, 2019 at 10:31 Comment(2)
Please provide the code that demonstrates what you try to accomplish, what you tried, and where you failed. StackOverflow is not a code-monkey service. flutter.io/docs/cookbook/networking/fetch-data, flutter.io/docs/cookbook/persistence/reading-writing-filesZitazitah
At what location are you storing the downloaded files in case of ios and in case of android?Faber
B
31

Use https://pub.dartlang.org/packages/flutter_downloader. Don't forget to do platform configurations.

Basically, this is how you should use the package. There is a detailed long example in the link.

final taskId = await FlutterDownloader.enqueue(
  url: 'your download link',
  savedDir: 'the path of directory where you want to save downloaded files',
  showNotification: true, // show download progress in status bar (for Android)
  openFileFromNotification: true, // click on notification to open downloaded file (for Android)
);

Edit: Some people said the package on top is not well maintained. Try this one https://pub.dev/packages/flowder

Brunhild answered 15/1, 2019 at 10:38 Comment(9)
Thanks so much. Cant believe I didnt find this library sooner. Btw, how do you specify the path to the downloads folder? I know how you move around in the system in linux and such, but how does it work here?Callean
github.com/fluttercommunity/flutter_downloader/blob/master/… Check the example please. It shows how to specify the download directory.Brunhild
Im so close, but I cant get permission to work.. my app has storage permissions, even installed permission plugin for that, but i keep getting "OS Error: Permission denied, errno = 13".. Any ideas? Tried to find a solution, but it just doesnt seem to workCallean
Did you do platform specific permissions? like Manifest in Android?Brunhild
This package is full of problems!Ginetteginevra
@Ginetteginevra No idea, it has been roughly 2 and half years since the answer.Brunhild
this package has issues and it's not maintained. Any other option @westdabestdb?Exhalant
flowder is null safety onlyAblepsia
+1 for the flowder. However for flowder version 0.2.0, you might want to check this thread github.com/Crdzbird/flowder/pull/10Preeminent
L
16

If you want to download and save file from URL without external libraries, you can use this code. It works for me, but I do not check it on big files. Good luck.

Future<String> downloadFile(String url, String fileName, String dir) async {
        HttpClient httpClient = new HttpClient();
        File file;
        String filePath = '';
        String myUrl = '';
    
        try {
          myUrl = url+'/'+fileName;
          var request = await httpClient.getUrl(Uri.parse(myUrl));
          var response = await request.close();
          if(response.statusCode == 200) {
            var bytes = await consolidateHttpClientResponseBytes(response);
            filePath = '$dir/$fileName';
            file = File(filePath);
            await file.writeAsBytes(bytes);
          }
          else
            filePath = 'Error code: '+response.statusCode.toString();
        }
        catch(ex){
          filePath = 'Can not fetch url';
        }
    
        return filePath;
      }

For Android do not forgetto add these lines in the manifest file, otherwise it will not work on real device after build apk:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Lysenkoism answered 26/7, 2020 at 8:28 Comment(4)
@MillieHudson Saving a file to a path on the device doesn't have an effect on the apps performance. The way you handle the download has an effect on performance.Fieldstone
Does it works on flutter web?Clomp
Muhammad Umair Saqib I didn't test on web, because I specialized in mobile development. But you can check, I don't think it takes a lot of time.Lysenkoism
How to specify the dir so that it works on iOS phones as well?Cholula
P
16
static var httpClient = new HttpClient();
Future<File> _downloadFile(String url, String filename) async {
  var request = await httpClient.getUrl(Uri.parse(url));
  var response = await request.close();
  var bytes = await consolidateHttpClientResponseBytes(response);
  String dir = (await getApplicationDocumentsDirectory()).path;
  File file = new File('$dir/$filename');
  await file.writeAsBytes(bytes);
  return file;
}
Palatalized answered 3/11, 2020 at 10:43 Comment(3)
where is it downloaded? I did not find downloaded file in 'Downloads' folder in android. Any suggestion?Hatred
Nothing happens...Auxiliary
The getApplicationDocumentsDirectory() from pub.dev/packages/path_provider is used in this example. So, the downloaded file is located under data/data/com.example.app (here your app package name)/app_flutter/downloaded_file. You can open this path trough Device File Explorer.Lysenkoism
B
7

FlutterChina's Dio seems like the way to go. https://github.com/flutterchina/dio/. It's robust and gives you options to retrieve the progress of your download/upload

Bezant answered 15/1, 2019 at 12:42 Comment(0)
H
0

You can use flutter_cache_manager and then simply do this:

await DefaultCacheManager().getSingleFile(url)

It will download the file to a cache, and return the file. The cache should be cleaned up over time (I don't know what the cache eviction policies are).

You get the benefit that trying to download the same file again returns it immediately from the cache.

Hinge answered 2/4 at 10:9 Comment(0)
R
-1
 Future<String?> _saveFileToDevice(String filename, List<int> data) async {
// Get the path to the app's documents directory
var status = await Permission.storage.status;
if (!status.isGranted) {
  await Permission.storage.request();
}

var dir = Platform.isAndroid
    ? '/storage/emulated/0/Download'
    : (await getApplicationDocumentsDirectory()).path;

// Create the file and write the data to it
var file = File('$dir/$filename');

bool alreadyDownloaded = await file.exists();

String incrementCount(String fileName) {
  int dotIndex = fileName.lastIndexOf('.');
  String newFileName = fileName.substring(0, dotIndex) +
      "(${count += 1})" +
      fileName.substring(dotIndex);

  return newFileName;
}

if (alreadyDownloaded) {
  String newFileName = incrementCount(file.path);

  var newFile = File('$newFileName');
  await newFile.writeAsBytes(data, flush: true);

  String subStringFileName = newFileName.substring(29);
  CommonWidgets.makeToast(
      fontSize: 14,
      toastMsg: '${subStringFileName} saved to Downloads Folder');

  file = newFile;
  print('modified updating ....--> $file');
} else {
  await file.writeAsBytes(data, flush: true);

  CommonWidgets.makeToast(
      fontSize: 14,
      toastMsg: '${filename} saved to Downloads Folder');
}

return 'file://${file.path}';
}

This function will download the Uint8List bytes-> Which we have to convert file into Uint8List Bytes

Ravin answered 26/4, 2023 at 10:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.