Skip to content

TesteurManiak/flutter_file_saver

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

flutter_file_saver

melos Pub Version

Interface to provide a way to save files on the device in Flutter.

Platform Support

Android iOS Web Windows Linux MacOS
writeFileAsBytes ❌️ ❌️
writeFileAsString ❌️ ❌️

Under the hood, each implementation tries to use the native dialog to save the file:

Getting Started

Import the package

dependencies:
    flutter_file_saver: any

Platform Setup

Android Setup
android {
    defaultConfig {
        minSdkVersion 19
    }
}

Check example

iOS Setup (Needs iOS 16+)

Add the following permissions to your ios/Runner/Info.plist:

<key>UISupportsDocumentBrowser</key>
<true/>
<key>UIFileSharingEnabled</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>

Check example

MacOS Setup

Add the following permissions to your macos/Runner/DebugProfile.entitlements:

<key>com.apple.security.files.user-selected.read-write</key>
<true/>

Check example

Methods

writeFileAsBytes

Write a file on the device from a Uint8List.

FlutterFileSaver().writeFileAsBytes(
    fileName: 'file.txt',
    bytes: fileBytes,
);

writeFileAsString

Write a file on the device from a String. This will most of the time convert your data and perform a call to writeFileAsBytes.

FlutterFileSaver().writeFileAsString(
    fileName: 'file.txt',
    string: 'Hello World!',
);

Known Issues

Web - SecurityError: Failed to execute 'showSaveFilePicker' on 'Window'

This is a known issue with the showSaveFilePicker JavaScript API on the Web. It is caused when writeFileAsBytes/writeFileAsString is not immediately called after a user interaction (like a button click). This is a security feature of the browser to prevent malicious sites from opening file pickers without user consent.

ElevatedButton(
    onPressed: () async {
        final bytes = await compressFile();

        // Might throw a SecurityError if compressFile() has taken too long to execute.
        FlutterFileSaver().writeFileAsBytes(bytes: bytes, fileName: myFileName);
    },
    child: const Text('Save File'),
),

The fix is to call writeFileAsBytes/writeFileAsString immediately after a user interaction. For example, by having a two-phase save flow with a button specifically made to save the file:

ElevatedButton(
    onPressed: () async {
        // 1st phase: compress the file
        final bytes = await compressFile();

        if (!context.mounted) return;
        // 2nd phase: show a dialog to save the file
        showDialog(context: context, builder: (_) => DownloadDialog(bytes: bytes, fileName: myFileName));
    },
    child: const Text('Save File'),
),


class DownloadDialog extends StatelessWidget {
    const DownloadDialog({super.key, required this.bytes, required this.fileName});

    final Uint8List bytes;
    final String fileName;

    @override
    Widget build(BuildContext context) {
        return AlertDialog(
            title: const Text('Save File'),
            content: const Text('Do you want to save the file?'),
            actions: [
                TextButton(
                    onPressed: () {
                        // Will work because it is called immediately after a user interaction.
                        FlutterFileSaver().writeFileAsBytes(bytes: bytes, fileName: fileName);
                        Navigator.pop(context);
                    },
                    child: const Text('Save'),
                ),
            ],
        );
    }
}

Check the example

About

Interface to provide a way to save files on the device in Flutter.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 3

  •  
  •  
  •