Firebase Storage — Uploading and Downloading files & Multi File Picker in Flutter | by Vipin Vijayan | ITNEXT
Mục lục bài viết
Firebase Storage — Uploading and Downloading files & Multi File Picker in Flutter
This demo shows how to upload files to firebase Storage.
For this demo we will upload only images to firebase Storage.
Let’s start…
Watch Video Tutorial
Add Dependencies
we need three plugins for this example
#1 Multiple File Picker
This plugins helps us to select multiple images from the file explorer or gallery.
file_picker: ^2.1.6
#2 Http Package
http: ^0.12.2
#3 Firebase Storage
firebase_storage: ^7.0.0
Add DropDown
Let’s add a DropDown in the UI to select multiple file types.
Here we are adding Audio, Video, Image and other.
dropDown() {
return DropdownButton(
hint: new Text('Select'),
value: _pickType,
items: <DropdownMenuItem>[
new DropdownMenuItem(
child: new Text('Audio'),
value: FileType.AUDIO,
),
new DropdownMenuItem(
child: new Text('Image'),
value: FileType.IMAGE,
),
new DropdownMenuItem(
child: new Text('Video'),
value: FileType.VIDEO,
),
new DropdownMenuItem(
child: new Text('Any'),
value: FileType.ANY,
),
],
onChanged: (value) => setState(() {
_pickType = value;
}),
);
}
Open the File explorer
Let’s open the Device’s File explorer and get the Files.
Make sure to add the Gallery Permission in iOS and Storage access permission in Android.
Android:
Place the below code in the AndroidManifest.xml in your Android project outside the application tag.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
iOS:
Open your iOS project info.plist file and add the below entries.
Limited Photos
<key>PHPhotoLibraryPreventAutomaticLimitedAccessAlert</key>
<true/>
Camera<key>NSCameraUsageDescription</key>
<string>$(PRODUCT_NAME) camera description.</string>
Photos<key>NSPhotoLibraryUsageDescription</key>
<string>$(PRODUCT_NAME)photos description.</string>
Below code will open up the File Explorer.
We will also check if the disk is mounted.
// Necessary variables
String _path;
Map<String, String> _paths;
String _extension;
FileType _pickType;
bool _multiPick = false;
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
List<StorageUploadTask> _tasks = <StorageUploadTask>[];
void openFileExplorer() async {
try {
_path = null;
if (_multiPick) {
_paths = await FilePicker.getMultiFilePath(
type: _pickType, fileExtension: _extension);
} else {
_path = await FilePicker.getFilePath(
type: _pickType, fileExtension: _extension);
}
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
}
if (!mounted) return;
}
Upload files to Firebase
Here we have uploadToFirebase method that loops through the files array and upload each to the Firebase Console.
uploadToFirebase() {
if (_multiPick) {
_paths.forEach((fileName, filePath) => {upload(fileName, filePath)});
} else {
String fileName = _path.split('/').last;
String filePath = _path;
upload(fileName, filePath);
}
}
upload(fileName, filePath) {
_extension = fileName.toString().split('.').last;
StorageReference storageRef =
FirebaseStorage.instance.ref().child(fileName);
final StorageUploadTask uploadTask = storageRef.putFile(
File(filePath),
StorageMetadata(
contentType: '$_pickType/$_extension',
),
);
setState(() {
_tasks.add(uploadTask);
});
}
Download Files from Firebase
Below code will to download the file from the firebase Storage with the help of ‘StorageReference’. We are creating a temporary file and writing the downloaded bytes to that file. Then we will show the image in a SnackBar.
Future<void> downloadFile(StorageReference ref) async {
final String url = await ref.getDownloadURL();
final http.Response downloadData = await http.get(url);
final Directory systemTempDir = Directory.systemTemp;
final File tempFile = File('${systemTempDir.path}/tmp.jpg');
if (tempFile.existsSync()) {
await tempFile.delete();
}
await tempFile.create();
final StorageFileDownloadTask task = ref.writeToFile(tempFile);
final int byteCount = (await task.future).totalByteCount;
var bodyBytes = downloadData.bodyBytes;
final String name = await ref.getName();
final String path = await ref.getPath();
print(
'Success!\nDownloaded $name \nUrl: $url'
'\npath: $path \nBytes Count :: $byteCount',
);
_scaffoldKey.currentState.showSnackBar(
SnackBar(
backgroundColor: Colors.white,
content: Image.memory(
bodyBytes,
fit: BoxFit.fill,
),
),
);
}
That’s it.
Here is the complete code.
import 'dart:io';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
class UploadMultipleImageDemo extends StatefulWidget {
UploadMultipleImageDemo() : super();
final String title = 'Firebase Storage';
@override
UploadMultipleImageDemoState createState() => UploadMultipleImageDemoState();
}
class UploadMultipleImageDemoState extends State<UploadMultipleImageDemo> {
//
String _path;
Map<String, String> _paths;
String _extension;
FileType _pickType;
bool _multiPick = false;
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
List<StorageUploadTask> _tasks = <StorageUploadTask>[];
void openFileExplorer() async {
try {
_path = null;
if (_multiPick) {
_paths = await FilePicker.getMultiFilePath(
type: _pickType, fileExtension: _extension);
} else {
_path = await FilePicker.getFilePath(
type: _pickType, fileExtension: _extension);
}
uploadToFirebase();
} on PlatformException catch (e) {
print("Unsupported operation" + e.toString());
}
if (!mounted) return;
}
uploadToFirebase() {
if (_multiPick) {
_paths.forEach((fileName, filePath) => {upload(fileName, filePath)});
} else {
String fileName = _path.split('/').last;
String filePath = _path;
upload(fileName, filePath);
}
}
upload(fileName, filePath) {
_extension = fileName.toString().split('.').last;
StorageReference storageRef =
FirebaseStorage.instance.ref().child(fileName);
final StorageUploadTask uploadTask = storageRef.putFile(
File(filePath),
StorageMetadata(
contentType: '$_pickType/$_extension',
),
);
setState(() {
_tasks.add(uploadTask);
});
}
dropDown() {
return DropdownButton(
hint: new Text('Select'),
value: _pickType,
items: <DropdownMenuItem>[
new DropdownMenuItem(
child: new Text('Audio'),
value: FileType.AUDIO,
),
new DropdownMenuItem(
child: new Text('Image'),
value: FileType.IMAGE,
),
new DropdownMenuItem(
child: new Text('Video'),
value: FileType.VIDEO,
),
new DropdownMenuItem(
child: new Text('Any'),
value: FileType.ANY,
),
],
onChanged: (value) => setState(() {
_pickType = value;
}),
);
}
String _bytesTransferred(StorageTaskSnapshot snapshot) {
return '${snapshot.bytesTransferred}/${snapshot.totalByteCount}';
}
@override
Widget build(BuildContext context) {
final List<Widget> children = <Widget>[];
_tasks.forEach((StorageUploadTask task) {
final Widget tile = UploadTaskListTile(
task: task,
onDismissed: () => setState(() => _tasks.remove(task)),
onDownload: () => downloadFile(task.lastSnapshot.ref),
);
children.add(tile);
});
return new MaterialApp(
home: new Scaffold(
key: _scaffoldKey,
appBar: new AppBar(
title: Text(widget.title),
),
body: new Container(
padding: EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
dropDown(),
SwitchListTile.adaptive(
title: Text('Pick multiple files', textAlign: TextAlign.left),
onChanged: (bool value) => setState(() => _multiPick = value),
value: _multiPick,
),
OutlineButton(
onPressed: () => openFileExplorer(),
child: new Text("Open file picker"),
),
SizedBox(
height: 20.0,
),
Flexible(
child: ListView(
children: children,
),
),
],
),
),
),
);
}
Future<void> downloadFile(StorageReference ref) async {
final String url = await ref.getDownloadURL();
final http.Response downloadData = await http.get(url);
final Directory systemTempDir = Directory.systemTemp;
final File tempFile = File('${systemTempDir.path}/tmp.jpg');
if (tempFile.existsSync()) {
await tempFile.delete();
}
await tempFile.create();
final StorageFileDownloadTask task = ref.writeToFile(tempFile);
final int byteCount = (await task.future).totalByteCount;
var bodyBytes = downloadData.bodyBytes;
final String name = await ref.getName();
final String path = await ref.getPath();
print(
'Success!\nDownloaded $name \nUrl: $url'
'\npath: $path \nBytes Count :: $byteCount',
);
_scaffoldKey.currentState.showSnackBar(
SnackBar(
backgroundColor: Colors.white,
content: Image.memory(
bodyBytes,
fit: BoxFit.fill,
),
),
);
}
}
class UploadTaskListTile extends StatelessWidget {
const UploadTaskListTile(
{Key key, this.task, this.onDismissed, this.onDownload})
: super(key: key);
final StorageUploadTask task;
final VoidCallback onDismissed;
final VoidCallback onDownload;
String get status {
String result;
if (task.isComplete) {
if (task.isSuccessful) {
result = 'Complete';
} else if (task.isCanceled) {
result = 'Canceled';
} else {
result = 'Failed ERROR: ${task.lastSnapshot.error}';
}
} else if (task.isInProgress) {
result = 'Uploading';
} else if (task.isPaused) {
result = 'Paused';
}
return result;
}
String _bytesTransferred(StorageTaskSnapshot snapshot) {
return '${snapshot.bytesTransferred}/${snapshot.totalByteCount}';
}
@override
Widget build(BuildContext context) {
return StreamBuilder<StorageTaskEvent>(
stream: task.events,
builder: (BuildContext context,
AsyncSnapshot<StorageTaskEvent> asyncSnapshot) {
Widget subtitle;
if (asyncSnapshot.hasData) {
final StorageTaskEvent event = asyncSnapshot.data;
final StorageTaskSnapshot snapshot = event.snapshot;
subtitle = Text('$status: ${_bytesTransferred(snapshot)} bytes sent');
} else {
subtitle = const Text('Starting...');
}
return Dismissible(
key: Key(task.hashCode.toString()),
onDismissed: (_) => onDismissed(),
child: ListTile(
title: Text('Upload Task #${task.hashCode}'),
subtitle: subtitle,
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Offstage(
offstage: !task.isInProgress,
child: IconButton(
icon: const Icon(Icons.pause),
onPressed: () => task.pause(),
),
),
Offstage(
offstage: !task.isPaused,
child: IconButton(
icon: const Icon(Icons.file_upload),
onPressed: () => task.resume(),
),
),
Offstage(
offstage: task.isComplete,
child: IconButton(
icon: const Icon(Icons.cancel),
onPressed: () => task.cancel(),
),
),
Offstage(
offstage: !(task.isComplete && task.isSuccessful),
child: IconButton(
icon: const Icon(Icons.file_download),
onPressed: onDownload,
),
),
],
),
),
);
},
);
}
}import 'package:flutter/material.dart';import 'dart:io';import 'package:firebase_storage/firebase_storage.dart';import 'package:file_picker/file_picker.dart';import 'package:flutter/services.dart';import 'package:http/http.dart' as http;class UploadMultipleImageDemo extends StatefulWidget {UploadMultipleImageDemo() : super();final String title = 'Firebase Storage';UploadMultipleImageDemoState createState() => UploadMultipleImageDemoState();class UploadMultipleImageDemoState extends State {//String _path;Map _paths;String _extension;FileType _pickType;bool _multiPick = false;GlobalKey _scaffoldKey = GlobalKey();List _tasks = [];void openFileExplorer() async {try {_path = null;if (_multiPick) {_paths = await FilePicker.getMultiFilePath(type: _pickType, fileExtension: _extension);} else {_path = await FilePicker.getFilePath(type: _pickType, fileExtension: _extension);uploadToFirebase();} on PlatformException catch (e) {print("Unsupported operation" + e.toString());if (!mounted) return;uploadToFirebase() {if (_multiPick) {_paths.forEach((fileName, filePath) => {upload(fileName, filePath)});} else {String fileName = _path.split('/').last;String filePath = _path;upload(fileName, filePath);upload(fileName, filePath) {_extension = fileName.toString().split('.').last;StorageReference storageRef =FirebaseStorage.instance.ref().child(fileName);final StorageUploadTask uploadTask = storageRef.putFile(File(filePath),StorageMetadata(contentType: '$_pickType/$_extension',),);setState(() {_tasks.add(uploadTask);});dropDown() {return DropdownButton(hint: new Text('Select'),value: _pickType,items: [new DropdownMenuItem(child: new Text('Audio'),value: FileType.AUDIO,),new DropdownMenuItem(child: new Text('Image'),value: FileType.IMAGE,),new DropdownMenuItem(child: new Text('Video'),value: FileType.VIDEO,),new DropdownMenuItem(child: new Text('Any'),value: FileType.ANY,),],onChanged: (value) => setState(() {_pickType = value;}),);String _bytesTransferred(StorageTaskSnapshot snapshot) {return '${snapshot.bytesTransferred}/${snapshot.totalByteCount}';Widget build(BuildContext context) {final List children = [];_tasks.forEach((StorageUploadTask task) {final Widget tile = UploadTaskListTile(task: task,onDismissed: () => setState(() => _tasks.remove(task)),onDownload: () => downloadFile(task.lastSnapshot.ref),);children.add(tile);});return new MaterialApp(home: new Scaffold(key: _scaffoldKey,appBar: new AppBar(title: Text(widget.title),),body: new Container(padding: EdgeInsets.all(20.0),child: Column(crossAxisAlignment: CrossAxisAlignment.start,mainAxisAlignment: MainAxisAlignment.start,children: [dropDown(),SwitchListTile.adaptive(title: Text('Pick multiple files', textAlign: TextAlign.left),onChanged: (bool value) => setState(() => _multiPick = value),value: _multiPick,),OutlineButton(onPressed: () => openFileExplorer(),child: new Text("Open file picker"),),SizedBox(height: 20.0,),Flexible(child: ListView(children: children,),),],),),),);Future downloadFile(StorageReference ref) async {final String url = await ref.getDownloadURL();final http.Response downloadData = await http.get(url);final Directory systemTempDir = Directory.systemTemp;final File tempFile = File('${systemTempDir.path}/tmp.jpg');if (tempFile.existsSync()) {await tempFile.delete();await tempFile.create();final StorageFileDownloadTask task = ref.writeToFile(tempFile);final int byteCount = (await task.future).totalByteCount;var bodyBytes = downloadData.bodyBytes;final String name = await ref.getName();final String path = await ref.getPath();print('Success!\nDownloaded $name \nUrl: $url''\npath: $path \nBytes Count :: $byteCount',);_scaffoldKey.currentState.showSnackBar(SnackBar(backgroundColor: Colors.white,content: Image.memory(bodyBytes,fit: BoxFit.fill,),),);class UploadTaskListTile extends StatelessWidget {const UploadTaskListTile({Key key, this.task, this.onDismissed, this.onDownload}): super(key: key);final StorageUploadTask task;final VoidCallback onDismissed;final VoidCallback onDownload;String get status {String result;if (task.isComplete) {if (task.isSuccessful) {result = 'Complete';} else if (task.isCanceled) {result = 'Canceled';} else {result = 'Failed ERROR: ${task.lastSnapshot.error}';} else if (task.isInProgress) {result = 'Uploading';} else if (task.isPaused) {result = 'Paused';return result;String _bytesTransferred(StorageTaskSnapshot snapshot) {return '${snapshot.bytesTransferred}/${snapshot.totalByteCount}';Widget build(BuildContext context) {return StreamBuilder(stream: task.events,builder: (BuildContext context,AsyncSnapshot asyncSnapshot) {Widget subtitle;if (asyncSnapshot.hasData) {final StorageTaskEvent event = asyncSnapshot.data;final StorageTaskSnapshot snapshot = event.snapshot;subtitle = Text('$status: ${_bytesTransferred(snapshot)} bytes sent');} else {subtitle = const Text('Starting...');return Dismissible(key: Key(task.hashCode.toString()),onDismissed: (_) => onDismissed(),child: ListTile(title: Text('Upload Task #${task.hashCode}'),subtitle: subtitle,trailing: Row(mainAxisSize: MainAxisSize.min,children: [Offstage(offstage: !task.isInProgress,child: IconButton(icon: const Icon(Icons.pause),onPressed: () => task.pause(),),),Offstage(offstage: !task.isPaused,child: IconButton(icon: const Icon(Icons.file_upload),onPressed: () => task.resume(),),),Offstage(offstage: task.isComplete,child: IconButton(icon: const Icon(Icons.cancel),onPressed: () => task.cancel(),),),Offstage(offstage: !(task.isComplete && task.isSuccessful),child: IconButton(icon: const Icon(Icons.file_download),onPressed: onDownload,),),],),),);},);
Please leave your valuable comments below this article.
Hit Clap if you find this useful.