Skip to main content

Device Files

Building a Flutter app that targets iOS, Android, and Web (as a PWA) is a fantastic approach, but managing files across these environments requires a mental shift.

The single biggest trap developers fall into when writing file logic for Flutter Web/PWAs is assuming a physical file path exists. On mobile, files live at a distinct string path (like /storage/... or /var/mobile/...). On the Web, files exist strictly as secure, virtual browser memory objects (Blobs). Therefore, on the web target, file.path will always be null.

Here is how to structure your Flutter app to handle files flawlessly across all three targets.


1. The Essential Package

Instead of writing native code or conditional abstractions yourself, use the file_picker package. It maps to native pickers on iOS and Android and automatically renders standard HTML file-upload elements when compiled for the web.

Add it to your pubspec.yaml:

dependencies:
file_picker: ^12.0.0 # Use the latest stable version


2. Writing Cross-Platform File Logic

Because web files lack string paths, you must handle file content using bytes or a stream.

Here is a clean, production-safe pattern for picking a file that works identically on iOS, Android, and your PWA:

import 'package:file_picker/file_picker.dart';
import 'dart:typed_data';
import 'dart:io'; // Note: Only use File from dart:io conditionally or safely

Future<void> pickAndProcessFile() async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['jpg', 'pdf', 'png'],
withData: true, // REQUIRED for Web to load file bytes into memory
);

if (result != null) {
PlatformFile file = result.files.first;

// 1. Metadata (Works perfectly across Web, iOS, and Android)
String fileName = file.name;
int fileSize = file.size;

// 2. Read file contents safely
if (file.bytes != null) {
// This block executes successfully on Web, iOS, and Android
Uint8List fileBytes = file.bytes!;

// You can now upload these bytes to a server, or display them locally:
// e.g., Image.memory(fileBytes)
} else if (file.path != null) {
// Fallback fallback for mobile if you want to interact via file paths
// WARNING: This block WILL be skipped on the Web/PWA
final nativeFile = File(file.path!);
}
} else {
// User cancelled the picker
}
}

⚠️ Performance Warning for Large Files: Loading files into memory via withData: true (file.bytes) is ideal for small files like images and documents. If your PWA or mobile app allows uploading massive files (e.g., 100MB+ videos), use file.readStream instead of loading all the raw bytes into RAM simultaneously to avoid crashing lower-end devices.


3. Saving Files and Offline PWA Data

What if you need to save or cache files locally for offline use?

On mobile, developers usually use path_provider to look up the device's application documents directory. However, on Web, path_provider is unsupported because browsers block direct access to the computer's storage directories.

For Local Offline App Storage:

If your PWA needs to store data or documents offline, avoid traditional file writing entirely. Use cross-platform database abstractions that write to local storage on mobile and IndexedDB on the web automatically:

  • Hive or Isar: Extremely fast, lightweight NoSQL databases that can store raw file bytes (Uint8List) inside binary boxes natively across all targets.

For Exporting/Downloading Files:

If you want to let a user download a file generated inside the app, use file_picker's saveFile() method, which triggers a "Save As" window on supported targets or a standard browser file download on web.


4. Platform Baseline Checklist

Ensure your app configuration accommodates the specific platform boundaries to avoid runtime crashes:

PlatformConfiguration RequirementWhat it handles
AndroidUses standard system intents. No special storage permissions are required for basic file picking on modern API levels.Scoped Storage System Picker
iOSIf your app creates files that the user should see in their system "Files" app, add UIFileSharingEnabled and LSSupportsOpeningDocumentsInPlace to your Info.plist.iCloud & Device Document Picker
Web (PWA)Managed entirely by browser security gates. Ensure your web/manifest.json is fully configured so the browser prompts the user to "Install" it onto their home screen.Native HTML <input> file dialog