how to download and save a file from internet to the internal storage(android) in Flutter/dart?

7,049

I've checked the minimal repro you've posted and it seems that you're using Flutter plugin dio to download the file. I've reused the Future<void> downloadFile() from your code and modified it a bit to check if the plugin works as expected. As of version 3.0.10 of the dio plugin, the onProgress on dio.download() is now onReceiveProgress, but it still essentially has the same function.

Here's the method for downloading the image file based from your code with a bit of modification.

Future downloadFile() async {
  Dio dio = Dio();
  var dir = await getApplicationDocumentsDirectory();
  var imageDownloadPath = '${dir.path}/image.jpg';
  await dio.download(imageSrc, imageDownloadPath,
      onReceiveProgress: (received, total) {
    var progress = (received / total) * 100;
    debugPrint('Rec: $received , Total: $total, $progress%');
    setState(() {
      downloadProgress = received.toDouble() / total.toDouble();
    });
  });
  // downloadFile function returns path where image has been downloaded
  return imageDownloadPath;
}

The plugin works as expected and successfully downloads the image file. Though I'm unable to verify how you're able to determine that the image that you're trying to download fails on your repro. In my sample app, Future downloadFile() returns a String where the image path is stored. I then use this to update the Image Widget to display the downloaded image - this determines that the download has been successful.

Here's the complete sample app.

import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final imageSrc = 'https://picsum.photos/250?image=9';
  var downloadPath = '';
  var downloadProgress = 0.0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Expanded(flex: 5, child: Image.network(imageSrc)),
            Expanded(
              flex: 2,
              child: Row(
                children: [
                  ElevatedButton(
                    // Download displayed image from imageSrc
                    onPressed: () {
                      downloadFile().catchError((onError) {
                        debugPrint('Error downloading: $onError');
                      }).then((imagePath) {
                        debugPrint('Download successful, path: $imagePath');
                        displayDownloadImage(imagePath);
                      });
                    },
                    child: Text('Download'),
                  ),
                  ElevatedButton(
                    // Delete downloaded image
                    onPressed: () {
                      deleteFile().catchError((onError) {
                        debugPrint('Error deleting: $onError');
                      }).then((value) {
                        debugPrint('Delete successful');
                      });
                    },
                    child: Text('Clear'),
                  )
                ],
              ),
            ),
            LinearProgressIndicator(
              value: downloadProgress,
            ),
            Expanded(
                flex: 5,
                child: downloadPath == ''
                // Display a different image while downloadPath is empty
                // downloadPath will contain an image file path on successful image download
                    ? Icon(Icons.image)
                    : Image.file(File(downloadPath))),
          ],
        ),
      ),
    );
  }

  displayDownloadImage(String path) {
    setState(() {
      downloadPath = path;
    });
  }

  Future deleteFile() async {
    final dir = await getApplicationDocumentsDirectory();
    var file = File('${dir.path}/image.jpg');
    await file.delete();
    setState(() {
      // Clear downloadPath on file deletion
      downloadPath = '';
    });
  }

  Future downloadFile() async {
    Dio dio = Dio();
    var dir = await getApplicationDocumentsDirectory();
    var imageDownloadPath = '${dir.path}/image.jpg';
    await dio.download(imageSrc, imageDownloadPath,
        onReceiveProgress: (received, total) {
      var progress = (received / total) * 100;
      debugPrint('Rec: $received , Total: $total, $progress%');
      setState(() {
        downloadProgress = received.toDouble() / total.toDouble();
      });
    });
    // downloadFile function returns path where image has been downloaded
    return imageDownloadPath;
  }
}

In the sample app, clicking the 'Download' button will have the network image displayed at the top portion of the screen downloaded. After the download is successful, the downloaded image will be displayed using Image.file() at the lower portion of the screen.

enter image description here

Share:
7,049
PrakashKing
Author by

PrakashKing

Updated on December 07, 2022

Comments

  • PrakashKing
    PrakashKing over 1 year

    i need to save file eg.jpg to "internalstorage/appname/files/" and show a notification if it does exists already in folder. when a button is pressed/activity intiated,it should download file to local storage of andorid device with dart code. help me find solution.

    **code:**
       import 'dart:io';
      import 'dart:async';
      import 'package:flutter/material.dart';
     import 'package:flutter_downloader/flutter_downloader.dart';
     import './landing_page.dart';
     import 'package:dio/dio.dart';
     import 'package:path_provider/path_provider.dart';
     import 'package:simple_permissions/simple_permissions.dart';
     import 'package:flutter/services.dart';
    
    
     class MoviesPage extends StatefulWidget {
    
      @override
     State createState() => new MoviesPageState();
     }
    
     class MoviesPageState extends State<MoviesPage> {
      final dUrl ="https://cdn.putlockers.es/download/0BBCA7584749D4E741747E32E6EB588AEA03E40F";
     bool downloading = false;
     var progressString = "";
    static const MethodChannel _channel =
         const MethodChannel('flutter_downloader');
    
     @override
      void initState() {
        super.initState();
       downloadFile();
    
       }
    
    
      Future<void> downloadFile() async {
        Dio dio = Dio();
    
        try {
         var dir = await getApplicationDocumentsDirectory();
    
         await dio.download(dUrl, "${dir.path}/file.torrent",
              onProgress: (rec, total) {
              print("Rec: $rec , Total: $total");
    
           setState(() {
            downloading = true;
            progressString = ((rec / total) * 100).toStringAsFixed(0) + "%";
          });
         });
          } catch (e) {
          print(e);
          }
    
        setState(() {
         downloading = false;
         progressString = "Completed";
         });
         print("Download completed");
         }
        @override
         Widget build(BuildContext context) {
         return Scaffold(
              appBar: AppBar(
             title: Text("AppBar"),
            ),
         body: Center(
           child: downloading
               ? Container(
                   height: 120.0,
                  width: 200.0,
                   child: Card(
                     color: Colors.black,
                     child: Column(
                         mainAxisAlignment: MainAxisAlignment.center,
                         children: <Widget>[
                           CircularProgressIndicator(),
                          SizedBox(
                        height: 20.0,
                      ),
                      Text(
                        "Downloading File: $progressString",
                        style: TextStyle(
                          color: Colors.white,
                        ),
                      )
                    ],
                  ),
                ),
              )
            : Text("No Data"),
      ),
    );
     }
    }
    

    thanks in advance.post your solutions in full fludged manner.