How to Add a File Picker Flutter Plugin to Your Cross-Platform App

To add a file picker flutter plugin, run flutter pub add file_picker, declare native permissions in AndroidManifest.xml and Info.plist, then invoke await FilePicker.platform.pickFiles() to open the native file picker UI and receive selected files as PlatformFile objects.

Adding a file picker flutter plugin enables your Flutter application to access native file selection dialogs across Android, iOS, macOS, and web platforms. The file_picker package implements a federated plugin architecture that delegates platform-specific logic to separate implementations while exposing a unified Dart API. This guide walks through the complete integration process using the dependency management and registration mechanisms found in the flutter/flutter repository.

Installing the File Picker Dependency

The first step to add a file picker flutter plugin is declaring the dependency in your project configuration and resolving the federated platform implementations.

Using the Flutter CLI

Execute the following command in your project root:

flutter pub add file_picker

This command updates your pubspec.yaml and runs flutter pub get automatically. According to the Flutter tool's command handling in packages/flutter_tools/lib/src/commands/pub.dart, this workflow ensures the package and its transitive dependencies—including the federated implementations file_picker_android, file_picker_ios, file_picker_macos, and file_picker_web—are resolved and locked in pubspec.lock.

Configuring Native Platform Permissions

Because the file picker interacts with device storage and media libraries, you must declare permissions in native configuration files. The plugin leverages Flutter's generated plugin registrant system to handle native registration automatically without manual boilerplate.

Android Manifest Setup

Add the following permissions to android/app/src/main/AndroidManifest.xml:

<manifest ...>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <!-- Optional: write permission if you plan to create files -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <application ...>
    </application>
</manifest>

The Android embedding automatically registers the plugin via GeneratedPluginRegistrant.java, located at engine/src/flutter/shell/platform/android/test/io/flutter/plugins/GeneratedPluginRegistrant.java in the Flutter repository. This generated class registers the plugin with the FlutterEngine at startup, eliminating the need for manual registration code in your MainActivity.

iOS Info.plist Setup

For iOS, add usage descriptions to ios/Runner/Info.plist:

<dict>
  <key>NSPhotoLibraryUsageDescription</key>
  <string>We need access to your photo library to let you pick files.</string>
  <key>NSCameraUsageDescription</key>
  <string>Camera access is required to pick photos directly.</string>
</dict>

Similar to Android, iOS uses GeneratedPluginRegistrant.swift (found at engine/src/flutter/shell/platform/ios/GeneratedPluginRegistrant.swift) to automatically register the plugin with the engine during app launch.

Web Configuration

No additional configuration is required for web platforms. The plugin automatically falls back to the HTML <input type="file"> element when running in a browser, handled by the file_picker_web implementation.

Implementing the File Picker API

Once dependencies and permissions are configured, you can invoke the file picker from your Dart code using the platform interface.

Basic File Selection

Import the package and call pickFiles():

import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';

Future<void> selectFiles() async {
  final result = await FilePicker.platform.pickFiles(
    allowMultiple: true,
    type: FileType.any,
  );
  
  if (result == null) {
    // User cancelled the picker
    return;
  }
  
  // Process selected files
  for (final file in result.files) {
    print('Selected: ${file.name} (${file.size} bytes)');
  }
}

The core API resides in packages/file_picker/file_picker/lib/file_picker.dart, where FilePicker.platform acts as the platform interface delegate that routes calls to the appropriate native implementation.

Handling FilePickerResult and PlatformFile

The pickFiles() method returns a FilePickerResult object containing a list of PlatformFile instances. Each PlatformFile provides:

  • name: The file name with extension
  • path: The absolute file path (null on web)
  • size: File size in bytes
  • bytes: Uint8List containing the file data (available on all platforms, essential for web)
if (result != null) {
  final PlatformFile file = result.files.first;
  
  if (file.bytes != null) {
    // Use file.bytes for upload or processing
    await uploadFileData(file.bytes!, file.name);
  }
  
  if (file.path != null) {
    // Use file.path for local file operations (mobile/desktop only)
    final localFile = File(file.path!);
    final contents = await localFile.readAsString();
  }
}

Understanding the Federated Plugin Architecture

The file_picker plugin uses Flutter's federated plugin architecture. Rather than containing all platform logic in a single package, the implementation is split across platform-specific packages:

  • file_picker_android
  • file_picker_ios
  • file_picker_macos
  • file_picker_web

When you add the top-level file_picker dependency, Flutter's tooling automatically resolves and includes the correct platform implementations based on your build target. This architecture is managed by the plugin handler logic in packages/flutter_tools/gradle/src/main/kotlin/plugins/PluginHandler.kt for Android builds, which copies the plugin's native AARs into the final application package.

Summary

  • Install the plugin using flutter pub add file_picker, which updates pubspec.yaml and resolves federated platform dependencies via the Flutter tool's pub command handler in packages/flutter_tools/lib/src/commands/pub.dart.
  • Configure permissions by adding READ_EXTERNAL_STORAGE to AndroidManifest.xml and NSPhotoLibraryUsageDescription to Info.plist, allowing the plugin to access native file systems through the automatically generated registrants (GeneratedPluginRegistrant.java and GeneratedPluginRegistrant.swift).
  • Implement the API by calling FilePicker.platform.pickFiles(), which returns a FilePickerResult containing PlatformFile objects with name, path, size, and bytes properties.
  • Handle platform differences by checking for path (null on web) and using bytes for universal file access, leveraging the federated plugin architecture that separates implementations into file_picker_android, file_picker_ios, and file_picker_web.

Frequently Asked Questions

How do I add a file picker flutter plugin without using the command line?

You can manually edit the pubspec.yaml file in your project root. Under the dependencies section, add file_picker: ^5.5.0 (or the latest version), then run flutter pub get to download the package. This achieves the same result as flutter pub add file_picker by invoking the pub logic defined in packages/flutter_tools/lib/src/commands/pub.dart.

Why does my app crash when opening the file picker on Android?

Crashes typically occur when the READ_EXTERNAL_STORAGE permission is missing from android/app/src/main/AndroidManifest.xml. The plugin requires this permission to access the device's file system through the native Android embedding. Additionally, on Android 10+ (API 29+), ensure you handle scoped storage properly or request the appropriate permissions, as the GeneratedPluginRegistrant.java (located at engine/src/flutter/shell/platform/android/test/io/flutter/plugins/GeneratedPluginRegistrant.java) registers the plugin but does not grant runtime permissions.

Can I use the file picker on web platforms, and what are the limitations?

Yes, the file_picker plugin supports web through the file_picker_web federated implementation. However, on web platforms, the path property of PlatformFile is always null because browsers cannot provide local file system paths for security reasons. You must use the bytes property to access file content, which loads the entire file into memory. This behavior is handled automatically by the plugin's web implementation without requiring additional configuration in index.html.

What is the difference between FileType.any and specific file types when picking files?

FileType.any allows the user to select any file type from the device's storage, mapping to generic MIME type filters on Android and uniform type identifiers on iOS. Specifying FileType.image, FileType.video, FileType.media, or FileType.custom restricts the picker to specific MIME types or file extensions, improving user experience by filtering the native file browser. These type constraints are passed through the method channel to the native implementations (file_picker_android and file_picker_ios) which apply the appropriate platform-specific filters before displaying the picker UI.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →