It’s not hard as it seems.
To implement in-app downloads in a Flutter app, you need to use libraries that can handle downloading files and managing states effectively. A common choice is the dio
package for making HTTP requests, along with the path_provider
package to save the downloaded file in the device’s local storage.
Here’s how you can implement in-app downloads in Flutter:
Step 1: Add Dependencies
Update your pubspec.yaml
file to include the required packages:
dependencies:
dio: ^5.0.0
path_provider: ^2.0.14
permission_handler: ^11.0.0
Run flutter pub get
to install the dependencies.
Step 2: Request Permissions
Before downloading a file, you must ensure the app has the required permissions to write files to the device’s storage.
import 'package:permission_handler/permission_handler.dart';
Future<void> requestStoragePermission() async {
if (await Permission.storage.request().isDenied) {
// Show a message if permission is denied
print('Storage permission denied');
}
}
Step 3: Implement the Download Functionality
Use the dio
package to handle the file download.
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:path_provider/path_provider.dart';
class Downloader {
final Dio _dio = Dio();
Future<void> downloadFile(String url, String fileName) async {
try {
// Get the directory for saving the file
final dir = await getApplicationDocumentsDirectory();
// Build the file path
final filePath = "${dir.path}/$fileName";
// Start the download
await _dio.download(
url,
filePath,
onReceiveProgress: (received, total) {
if (total != -1) {
// Show the download progress (in percentage)
print("Download Progress: ${(received / total * 100).toStringAsFixed(0)}%");
}
},
);
print("File downloaded successfully: $filePath");
} catch (e) {
print("Download failed: $e");
}
}
}
Step 4: Create a UI for the Download
Here’s an example of a simple UI to trigger the download:
import 'package:flutter/material.dart';
import 'downloader.dart';
class DownloadScreen extends StatelessWidget {
final String fileUrl = "https://example.com/sample.pdf";
final String fileName = "sample.pdf";
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("In-App Download Example"),
),
body: Center(
child: ElevatedButton(
onPressed: () async {
final downloader = Downloader();
await downloader.downloadFile(fileUrl, fileName);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Download started!")),
);
},
child: Text("Download File"),
),
),
);
}
}
Step 5: Handle Edge Cases
To make your download process robust:
- Network Errors: Wrap the download logic in a
try-catch
block to handle timeouts or connectivity issues. - File Overwriting: Check if the file already exists and handle appropriately.
- User Feedback: Show a loading spinner or progress bar during the download process.
Step 6: Add Progress Indicators (Optional)
You can enhance the UI by displaying the progress using a progress bar.
import 'package:flutter/material.dart';
import 'downloader.dart';
class DownloadScreenWithProgress extends StatefulWidget {
@override
_DownloadScreenWithProgressState createState() => _DownloadScreenWithProgressState();
}
class _DownloadScreenWithProgressState extends State<DownloadScreenWithProgress> {
double _progress = 0.0;
Future<void> startDownload() async {
final downloader = Downloader();
await downloader._dio.download(
"https://example.com/sample.pdf",
"${(await getApplicationDocumentsDirectory()).path}/sample.pdf",
onReceiveProgress: (received, total) {
if (total != -1) {
setState(() {
_progress = received / total;
});
}
},
);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Download complete!")),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Download with Progress"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
LinearProgressIndicator(value: _progress),
SizedBox(height: 20),
ElevatedButton(
onPressed: startDownload,
child: Text("Start Download"),
),
],
),
),
);
}
}
Key Considerations
- Permission Management: Use
permission_handler
to request permissions dynamically. - Offline Storage: Save files to device directories using
path_provider
. - Background Downloads: For downloads that need to continue when the app is in the background, consider using native integrations (e.g.,
workmanager
or platform channels).
Thank You, Hope You Enjoyed.
Learn more Implement In-App Download Feature In Flutter App Easily.