better_download_saver

pub package License: BSD-3-Clause Platform

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 Downloads directory 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 Downloads folder using MediaStore.
  • 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 MimeTypeMap to 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.