Being able to consume files from an android part device is part of any native app development. This process is quite easy when in native development using Kotlin/Java, but probably even easier with Flutter, courtesy of multiple packages available to use for free.
This tutorial will explore examples and packages for picking files in flutter.
(a). file_picker example
file_picker is a package that allows you to use a native file explorer to pick single or multiple absolute file paths, with extension filtering support.
Here are the supported features:
- Uses OS default native pickers
- Pick files using custom format filtering — you can provide a list of file extensions (pdf, svg, zip, etc.)
- Pick files from cloud files (GDrive, Dropbox, iCloud)
- Single or multiple file picks
- Different default type filtering (media, image, video, audio or any)
- Picking directories
- Flutter Web
- Desktop (MacOS, Linux and Windows through Flutter Go)
- Load file data immediately into memory (
Uint8List
) if needed;
Let's look at how use this package with a step by step example.
Here is what will be created in the example:
Step 1: Install it
You start by installing. Add the file_picker
in your pubspec.yaml file:
dependencies:
file_picker: ^3.0.4
Then flutter pub get
to fetch it.
Step 2: Write code
Then start by importing the package:
import 'package:file_picker/file_picker.dart';
Then if you want to pick a single file you can use the following code:
FilePickerResult? result = await FilePicker.platform.pickFiles();
if(result != null) {
File file = File(result.files.single.path);
} else {
// User canceled the picker
}
If you want to pick multiple files use the following code:
FilePickerResult? result = await FilePicker.platform.pickFiles(allowMultiple: true);
if(result != null) {
List<File> files = result.paths.map((path) => File(path)).toList();
} else {
// User canceled the picker
}
Sometimes you wish to pick only a certain type of files. Say you want only to pick jpg images, pdf files as well as ms word documents, here is the code you can use:
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['jpg', 'pdf', 'doc'],
);
So now that you've picked your file, you actually want to use that picked file in your code. Let's say you want to print the details like name and size. Here is the code you use;
FilePickerResult? result = await FilePicker.platform.pickFiles();
if(result != null) {
PlatformFile file = result.files.first;
print(file.name);
print(file.bytes);
print(file.size);
print(file.extension);
print(file.path);
} else {
// User canceled the picker
}
Or let's say you want to pick a single file and load it to firebase cloud storage, here is a sample code:
FilePickerResult? result = await FilePicker.platform.pickFiles();
if (result != null) {
Uint8List fileBytes = result.files.first.bytes;
String fileName = result.files.first.name;
// Upload file
await FirebaseStorage.instance.ref('uploads/$fileName').putData(fileBytes);
}
Full Example
Here is a full example of how to use this package:
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class FilePickerDemo extends StatefulWidget {
@override
_FilePickerDemoState createState() => _FilePickerDemoState();
}
class _FilePickerDemoState extends State<FilePickerDemo> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
String? _fileName;
List<PlatformFile>? _paths;
String? _directoryPath;
String? _extension;
bool _loadingPath = false;
bool _multiPick = false;
FileType _pickingType = FileType.any;
TextEditingController _controller = TextEditingController();
@override
void initState() {
super.initState();
_controller.addListener(() => _extension = _controller.text);
}
void _openFileExplorer() async {
setState(() => _loadingPath = true);
try {
_directoryPath = null;
_paths = (await FilePicker.platform.pickFiles(
type: _pickingType,
allowMultiple: _multiPick,
allowedExtensions: (_extension?.isNotEmpty ?? false)
? _extension?.replaceAll(' ', '').split(',')
: null,
))
?.files;
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
} catch (ex) {
print(ex);
}
if (!mounted) return;
setState(() {
_loadingPath = false;
print(_paths!.first.extension);
_fileName =
_paths != null ? _paths!.map((e) => e.name).toString() : '...';
});
}
void _clearCachedFiles() {
FilePicker.platform.clearTemporaryFiles().then((result) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
backgroundColor: result! ? Colors.green : Colors.red,
content: Text((result
? 'Temporary files removed with success.'
: 'Failed to clean temporary files')),
),
);
});
}
void _selectFolder() {
FilePicker.platform.getDirectoryPath().then((value) {
setState(() => _directoryPath = value);
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: const Text('File Picker example app'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: DropdownButton<FileType>(
hint: const Text('LOAD PATH FROM'),
value: _pickingType,
items: <DropdownMenuItem<FileType>>[
DropdownMenuItem(
child: const Text('FROM AUDIO'),
value: FileType.audio,
),
DropdownMenuItem(
child: const Text('FROM IMAGE'),
value: FileType.image,
),
DropdownMenuItem(
child: const Text('FROM VIDEO'),
value: FileType.video,
),
DropdownMenuItem(
child: const Text('FROM MEDIA'),
value: FileType.media,
),
DropdownMenuItem(
child: const Text('FROM ANY'),
value: FileType.any,
),
DropdownMenuItem(
child: const Text('CUSTOM FORMAT'),
value: FileType.custom,
),
],
onChanged: (value) => setState(() {
_pickingType = value!;
if (_pickingType != FileType.custom) {
_controller.text = _extension = '';
}
})),
),
ConstrainedBox(
constraints: const BoxConstraints.tightFor(width: 100.0),
child: _pickingType == FileType.custom
? TextFormField(
maxLength: 15,
autovalidateMode: AutovalidateMode.always,
controller: _controller,
decoration:
InputDecoration(labelText: 'File extension'),
keyboardType: TextInputType.text,
textCapitalization: TextCapitalization.none,
)
: const SizedBox(),
),
ConstrainedBox(
constraints: const BoxConstraints.tightFor(width: 200.0),
child: SwitchListTile.adaptive(
title:
Text('Pick multiple files', textAlign: TextAlign.right),
onChanged: (bool value) =>
setState(() => _multiPick = value),
value: _multiPick,
),
),
Padding(
padding: const EdgeInsets.only(top: 50.0, bottom: 20.0),
child: Column(
children: <Widget>[
ElevatedButton(
onPressed: () => _openFileExplorer(),
child: const Text("Open file picker"),
),
ElevatedButton(
onPressed: () => _selectFolder(),
child: const Text("Pick folder"),
),
ElevatedButton(
onPressed: () => _clearCachedFiles(),
child: const Text("Clear temporary files"),
),
],
),
),
Builder(
builder: (BuildContext context) => _loadingPath
? Padding(
padding: const EdgeInsets.only(bottom: 10.0),
child: const CircularProgressIndicator(),
)
: _directoryPath != null
? ListTile(
title: const Text('Directory path'),
subtitle: Text(_directoryPath!),
)
: _paths != null
? Container(
padding: const EdgeInsets.only(bottom: 30.0),
height:
MediaQuery.of(context).size.height * 0.50,
child: Scrollbar(
child: ListView.separated(
itemCount:
_paths != null && _paths!.isNotEmpty
? _paths!.length
: 1,
itemBuilder:
(BuildContext context, int index) {
final bool isMultiPath =
_paths != null && _paths!.isNotEmpty;
final String name = 'File $index: ' +
(isMultiPath
? _paths!
.map((e) => e.name)
.toList()[index]
: _fileName ?? '...');
final path = _paths!
.map((e) => e.path)
.toList()[index]
.toString();
return ListTile(
title: Text(
name,
),
subtitle: Text(path),
);
},
separatorBuilder:
(BuildContext context, int index) =>
const Divider(),
)),
)
: const SizedBox(),
),
],
),
),
)),
),
);
}
}
Reference
Find download link below:
No. | Link |
---|---|
1. | Download full code |
2. | Browse code |