File Downloader in Flutter: A Complete Guide
Introduction
Downloading files in a Flutter app is a common requirement, whether for offline access, media consumption, or document storage. In this guide, we will implement a file downloader in Flutter using the dio
package and flutter_downloader
. We will handle permissions, display progress indicators, and ensure a smooth user experience.
Prerequisites
Before we start, ensure you have:
Flutter installed
Basic knowledge of Flutter and Dart
An IDE (VS Code or Android Studio)
Step 1: Setting Up Dependencies
Open your pubspec.yaml
file and add the required packages:
dependencies:
flutter:
sdk: flutter
dio: ^5.3.2
permission_handler: ^10.4.3
flutter_downloader: ^1.11.6
Run flutter pub get
to install them.
Step 2: Configuring Permissions
For Android, update AndroidManifest.xml
:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
For iOS, open Info.plist
and add:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Step 3: Implementing the Download Logic
Create a new Dart file file_downloader.dart
:
import 'package:dio/dio.dart'; import 'package:permission_handler/permission_handler.dart'; class FileDownloader { final Dio _dio = Dio(); Future<void> downloadFile( String url, String savePath, Function(int, int) onReceiveProgress) async { var status = await Permission.storage.request(); if (status.isGranted) { try { await _dio.download(url, savePath, onReceiveProgress: onReceiveProgress); } on DioError catch (e) { if (e.type == DioErrorType.unknown) { throw Exception("No address associated with hostname: $url"); } else { print(e.message); throw Exception("Download failed: ${e.message}"); } } catch (e) { print(e); throw Exception("Unexpected error: $e"); } } else { throw Exception("Permission Denied!"); } } }
Step 4: Integrating with UI
Modify main.dart
to include a download button:
import 'package:flutter/material.dart'; import 'file_downloader.dart'; void main() { runApp(MyApp()); } class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { final FileDownloader fileDownloader = FileDownloader(); final String fileUrl = 'https://link.testfile.org/500MB'; // Ensure this URL is correct final String savePath = '/storage/emulated/0/Download/dummyfile.zip'; double _progress = 0.0; String _status = "Idle"; void _startDownload() async { setState(() { _status = "Downloading..."; }); try { await fileDownloader.downloadFile(fileUrl, savePath, (count, total) { setState(() { _progress = count / total; }); }); setState(() { _status = "Download Complete!"; }); } catch (e) { setState(() { _status = "Download Failed: $e"; }); } } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: Text("File Downloader")), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed: _startDownload, child: Text("Download File"), ), SizedBox(height: 20), LinearProgressIndicator(value: _progress), SizedBox(height: 20), Text(_status), ], ), ), ), ); } }
Step 5: Running the App
Run your app using:
flutter run
Now, pressing the download button will download the file to the specified path.
Conclusion
We successfully implemented a file downloader in Flutter, handling permissions and showing progress updates. You can further enhance it by integrating a progress bar and error handling for a better user experience.