Fileuploading. Works on all platforms (iOS, Android and web)
import 'package:flutter/material.dart'; import 'package:flutter/foundation.dart'; import 'package:file_picker/file_picker.dart'; class FilePickerTest extends StatefulWidget { const FilePickerTest({super.key}); @override State<FilePickerTest> createState() => _FilePickerTestState(); } class _FilePickerTestState extends State<FilePickerTest> { Uint8List? dataBytes; /* * Simpler Stream Handling: If your goal is to process the entire stream from start to finish in a simpler, * more readable way without needing immediate feedback, then await for is recommended. * It simplifies the code because it allows you to handle data in a sequential, * synchronous style rather than dealing with callbacks and the complexities of stream events. */ Future<void> pickFilesMethod1({ required Function callback, List<String>? allowedExtensions, bool allowMultiple = false, }) async { FilePickerResult? result = await FilePicker.platform.pickFiles( withReadStream: true, allowMultiple: allowMultiple, type: FileType.any, onFileLoading: (FilePickerStatus status) => debugPrint('status: $status'), ); if (result != null) { for (PlatformFile file in result.files) { // Max filesize 5 MB if (file.size > 5000000) { debugPrint('Invalid file size: ${file.size} bytes'); await callback([], 406); // Error code for large file return; } final Stream<List<int>> stream = file.readStream!; final List<int> bytes = []; try { // Use `await for` for simpler and more readable stream handling await for (final chunk in stream) { bytes.addAll(chunk); } // Successfully processed file await callback(bytes, 201); } catch (error) { debugPrint('An error occurred while reading the file: $error'); await callback([], 500); // General error code } } } } /* * Real-Time Processing: * If your use case requires handling each data chunk as soon as it becomes available (for example, * in a live data stream or when showing a progress bar), then stream.listen() is appropriate. */ Future<void> pickFilesMethod2({ required Function callback, List<String>? allowedExtensions, bool allowMultiple = false, }) async { FilePickerResult? result = await FilePicker.platform.pickFiles( withReadStream: true, allowMultiple: allowMultiple, //type: (allowedExtensions != null) ? FileType.custom : FileType.any, //allowedExtensions: allowedExtensions, type: FileType.image, onFileLoading: (FilePickerStatus status) => debugPrint('status: $status'), ); if (result != null) { for (PlatformFile file in result.files) { Stream<List<int>> stream = file.readStream!; List<int> bytes = []; stream.listen( (data) { bytes.addAll(data); }, onError: (err) { debugPrint('An error: $err'); }, onDone: () async { if (file.size > 5000000) { //max 5Mbytes await callback([], 406); debugPrint('Invalid filesize'); return; } callback(bytes, 201); }, cancelOnError: true, ); } } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), body: Container( decoration: BoxDecoration( border: Border.all(), borderRadius: const BorderRadius.all( Radius.circular(10), ), ), margin: const EdgeInsets.all(10), width: double.infinity, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed: () => pickFilesMethod1( callback: (bytes, status) => setState(() { dataBytes = Uint8List.fromList(bytes); })), child: const Icon(Icons.upload_file), ), const SizedBox( height: 20, ), if (dataBytes == null) const SizedBox( width: 500, child: Placeholder(), ), if (dataBytes != null) Image.memory( dataBytes!, width: 500, ), ], ), ), ); } }