dir_picker 0.4.0 copy "dir_picker: ^0.4.0" to clipboard
dir_picker: ^0.4.0 copied to clipboard

A Flutter plugin for picking directories, supporting Android, iOS, macOS, Windows, Linux and Web via FFI and JNI.

dir_picker #

Platform License: MIT

A Flutter plugin for picking a directory across all platforms using native system dialogs. Returns a PickedLocation? — null if the user cancelled, and can list entries from a previously picked directory with DirPicker.listEntries().

Features #

  • 📁 All Platforms – Android, iOS, macOS, Windows, Linux, and Web
  • Native Performance – Powered by FFI (iOS/macOS/Windows) and JNI (Android) for near-zero overhead
  • 🎨 Customizable Dialogs – Platform-specific options for title, button labels, and more
  • 🔗 Persistent Permissions – Android SAF persistent URI access across reboots
  • 🐧 Linux Portals – XDG Desktop Portal with zenity/kdialog fallback

If you want to say thank you, star us on GitHub or like us on pub.dev.

Installation #

First, follow the package installation instructions and add dir_picker to your app.

Quick Start #

Platform Setup #

Android Configuration

Supported: API 21+ (Android 5.0+)

No configuration needed. The plugin uses the Storage Access Framework (Intent.ACTION_OPEN_DOCUMENT_TREE), which grants URI access through the system picker UI — no manifest permissions required.

iOS Configuration

Supported: iOS 13.0+

No configuration needed. The plugin uses UIDocumentPickerViewController, which is available without extra entitlements.

macOS Configuration

Supported: macOS 10.15+

Add the following entitlement to macos/Runner/Release.entitlements and macos/Runner/DebugProfile.entitlements:

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

Supported: Windows 10+

No configuration needed. The plugin uses the native IFileOpenDialog COM API.

Linux Configuration

The plugin tries the following dialog backends in order:

  1. XDG Desktop Portal – Works on all modern desktop environments via D-Bus (org.freedesktop.portal.FileChooser)
  2. zenity – GNOME fallback
  3. kdialog – KDE fallback

If none are available, the pick call throws. To install a fallback manually:

# GNOME
sudo apt install zenity

# KDE
sudo apt install kdialog
Web Configuration

No configuration needed. The plugin uses the File System Access API.

Browser support: Chrome 86+ and Edge 86+. Not supported in Firefox or Safari.

Note: On web, pick() returns a WebPickedLocation wrapping a FileSystemDirectoryHandle. Use .handle to access directory contents via the File System Access API. PickedLocation.uri is always null on web — browsers do not expose full filesystem paths. Requires package:web in your app's dependencies to work with the handle directly.

Basic Usage #

import 'package:dir_picker/dir_picker.dart';

final PickedLocation? location = await DirPicker.pick();

if (location == null) {
  print('Cancelled');
} else if (location is WebPickedLocation) {
  // Web: use handle to access directory contents via File System Access API
  // Requires package:web in your app's dependencies
  final handle = location.handle; // FileSystemDirectoryHandle
  print('Selected directory: ${location.name}');
} else {
  // Native (Android, iOS, macOS, Windows, Linux)
  print('Selected: ${location.uri}');
}

List directory entries #

final location = await DirPicker.pick();
if (location == null) return;

final entries = await DirPicker.listEntries(location, recursive: true);
for (final entry in entries) {
  print('${entry.relativePath} (dir: ${entry.isDirectory})');
}

Platform Options #

Pass a PickOptions to DirPicker.pick() to customize the dialog for the current platform:

final location = await DirPicker.pick(
  options: PickOptions.android(shouldPersist: true),
);

final location = await DirPicker.pick(
  options: PickOptions.macos(acceptLabel: 'Choose', message: 'Select a project folder'),
);

final location = await DirPicker.pick(
  options: PickOptions.linux(title: 'Select Folder', acceptLabel: 'Choose'),
);

final location = await DirPicker.pick(
  options: PickOptions.windows(title: 'Select Folder', acceptLabel: 'Choose'),
);

Options for other platforms are silently ignored — only the one matching the current platform is applied.

AndroidOptions #

Parameter Type Default Description
shouldPersist bool true Take persistable URI permission so the app retains access across reboots (SAF takePersistableUriPermission).

MacosOptions #

Parameter Type Default Description
acceptLabel String 'Select' Label for the confirmation button (NSOpenPanel.prompt).
message String 'Choose a directory' Descriptive text shown inside the panel (NSOpenPanel.message).

LinuxOptions #

Parameter Type Default Description
title String 'Select Directory' Window title of the dialog.
acceptLabel String 'Select' Label for the confirmation button (XDG Portal and zenity only).

WindowsOptions #

Parameter Type Default Description
title String 'Select Directory' Window title of the dialog (IFileDialog::SetTitle).
acceptLabel String 'Select' Label for the confirmation button (IFileDialog::SetOkButtonLabel).

Core Concepts #

Return value #

Result Meaning
IOPickedLocation Native platforms — use .uri to get the selected directory URI.
WebPickedLocation Web — use .handle (FileSystemDirectoryHandle) to access directory contents. .uri is null.
null The user cancelled.

Native Mechanisms #

Platform Mechanism
Android SAF (Intent.ACTION_OPEN_DOCUMENT_TREE) via JNI
iOS UIDocumentPickerViewController via FFI
macOS NSOpenPanel via FFI
Windows IFileOpenDialog (COM) via pure Dart FFI
Linux XDG Desktop Portal → zenity → kdialog
Web window.showDirectoryPicker() (JS interop)

Common Use Cases #

Simple directory pick (native) #

final location = await DirPicker.pick();
if (location != null) {
  print('Selected: ${location.uri}');
}

Simple directory pick (web) #

import 'package:dir_picker/dir_picker.dart';
import 'package:web/web.dart' as web; // required to use FileSystemDirectoryHandle

final location = await DirPicker.pick();
if (location is WebPickedLocation) {
  final web.FileSystemDirectoryHandle handle = location.handle;
  // list files, read contents, etc.
}

Custom dialog labels #

final location = await DirPicker.pick(
  options: PickOptions.macos(
    acceptLabel: 'Use This Folder',
    message: 'Select the folder to import from',
  ),
);

// or on Linux/Windows:
final location = await DirPicker.pick(
  options: PickOptions.linux(
    title: 'Import Folder',
    acceptLabel: 'Use This Folder',
  ),
);

Android — enable persistent permission #

final location = await DirPicker.pick(
  options: PickOptions.android(shouldPersist: true),
);

DirPicker.listEntries #

static Future<List<FileSystemEntry>> listEntries(
  PickedLocation location, {
  bool recursive = false,
})

Returns a flat list of descendants under the picked root. The root itself is excluded from the results.

FileSystemEntry fields:

Field Type Description
name String Basename of the entry.
relativePath String Path relative to the picked root, always using / separators.
isDirectory bool Whether the entry is a directory.
uri Uri? Native URI when available; always null on web.
size int? File size in bytes; null for directories or when unavailable.
lastModified DateTime? Last modified timestamp when available.

API Reference #

DirPicker.pick #

static Future<PickedLocation?> pick({PickOptions? options})

Returns a PickedLocation (either IOPickedLocation or WebPickedLocation), or null if the user cancelled.

options is a PickOptions sealed class — pass the platform-specific subclass using its factory constructor (e.g. PickOptions.android(...), PickOptions.macos(...)). Options for other platforms are ignored.

Platform Support #

Android iOS macOS Windows Linux Web

Minimum versions:

  • Flutter ≥ 3.3.0
  • Dart SDK ≥ 3.6.0
  • Kotlin 2.1.0
  • Swift 5.9
  • Android API 21+
  • iOS 13.0+
  • macOS 10.15+
  • Windows 10+
  • Web: Chrome/Edge 86+

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

MIT License — see LICENSE file for details.

3
likes
150
points
212
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin for picking directories, supporting Android, iOS, macOS, Windows, Linux and Web via FFI and JNI.

Repository (GitHub)
View/report issues

Topics

#dir-picker #directory #picker #ffi #jni

License

MIT (license)

Dependencies

dbus, ffi, flutter, flutter_web_plugins, jni, path, web

More

Packages that depend on dir_picker

Packages that implement dir_picker