better_download_saver
A zero-permission, highly secure Flutter plugin to save files directly to the public Downloads directory on Android (using native Scoped Storage / MediaStore API) and the secure app Documents folder on iOS.
🎯 The Goal of this Plugin
Modern mobile operating systems have strict storage guidelines. On modern Android versions (Android 10+), requesting broad storage read/write permissions at runtime can easily result in rejected Google Play Store submissions or failed cybersecurity audits due to over-privileged permission requests.
better_download_saver was designed to solve this exact problem:
- Zero Runtime Permissions: Natively writes files to the public
Downloadsdirectory using the MediaStore API on Android Q+ (API 29+), meaning no runtime permission prompt is required. - 100% Cybersecurity Audited: Does not require permissive FileProvider XML configurations or broad directory access, keeping your app fully secure and compliant with corporate cybersecurity audits.
- Auto-MIME Type Detection: Automatically resolves file extensions (like
.pdf,.png,.xlsx,.zip) to their native MIME type configurations or allows custom override. - Name Collision Resolution: Queries the native MediaStore database to detect and capture auto-suffixed filenames (e.g.
comprobante (1).pdf) so your app always gets the exact absolute path of the saved file.
✨ Features
- Android 10+ (API 29+): Zero storage permission needed to write to the public
Downloadsfolder usingMediaStore. - Android 9 and below: Gracefully falls back to standard public Downloads folder storage (requiring traditional write permissions).
- iOS: Standard, secure app documents directory writing.
- MIME Type Auto-Detection: Leverages native Android
MimeTypeMapto automatically detect MIME types based on file extension. - No Bloat: Highly lightweight, zero third-party Dart dependencies.
🚀 Getting Started
Add the package to your pubspec.yaml:
dependencies:
better_download_saver: ^0.0.1
code Example
1. Basic File Saving (Automatic MIME Detection)
Simply pass the filename and file bytes. The plugin will automatically detect that .pdf corresponds to application/pdf:
import 'dart:typed_data';
import 'package:better_download_saver/better_download_saver.dart';
Future<void> downloadDocument(Uint8List pdfBytes) async {
final saver = BetterDownloadSaver();
// Save to public Downloads directory
final String? savedPath = await saver.saveToDownloads(
fileName: 'receipt_transaction_1029.pdf',
bytes: pdfBytes,
);
if (savedPath != null) {
print('File successfully downloaded and saved at: $savedPath');
// You can now open this file using packages like open_filex
} else {
print('Failed to save file.');
}
}
2. Saving Custom File Types (e.g., CSV, PNG)
You can optionally supply a custom MIME type manually:
Future<void> downloadCsv(Uint8List csvBytes) async {
final saver = BetterDownloadSaver();
final String? savedPath = await saver.saveToDownloads(
fileName: 'monthly_report.csv',
bytes: csvBytes,
mimeType: 'text/csv', // Optional custom override
);
if (savedPath != null) {
print('Report saved at: $savedPath');
}
}
🛠️ Platform-Specific Setup
Android
- For Android 10+ (API 29+): No permissions are needed. It works out of the box!
- For Android 9 and below (API <= 28): Ensure you have added the legacy write permission to your
AndroidManifest.xml(only needed for legacy support):
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
iOS
Files are stored securely in the app's local Documents folder:
- Path:
/var/mobile/Containers/Data/Application/.../Documents/ - No extra permissions or setup are needed.
📄 License & Creator
- Created with ❤️ by Jhonaiquel.
- Released under the BSD 3-Clause License. See LICENSE for details.