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.6Run 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 runNow, 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.
