Firebase Storage – Uploading and Downloading files & Multi File Picker in Flutter

By | June 22, 2019

Firebase Storage


Watch Video Tutorial
 

 


This demo shows how to upload files to firebase Storage.
For this demo we will upload only images to firebase Storage.
Also I am doing any sign in to Google, this is completely anonymous.


Let’s start…


Firebase Storage - Upload and Download Files

Firebase Storage – Upload and Download Files


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.

[java]
file_picker: ^1.1.1
[/java]

#2 Http Package

[java]
http: "0.11.3+17"
[/java]

#3 Firebase Storage

[java]
firebase_storage: ^2.0.0
[/java]


Add DropDown

Lets add a DropDown in the UI to select multiple fiel types.

[java]

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;
}),
);
}

[/java]


Open the File explorer

Lets open the Device’s File explorer and get the Files.
We will also check if the disk is mounted.

[java]

// 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;
}
[/java]


Upload files to Firebase

Here we have uploadToFirebase method that loops through the files array and upload each to the Firebase Console.
[java]
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);
});
}
[/java]


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.

[java]
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,
),
),
);
}
[/java]


Complete Code

[java]
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’;

@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,
),
),
],
),
),
);
},
);
}
}
[/java]

3 thoughts on “Firebase Storage – Uploading and Downloading files & Multi File Picker in Flutter

  1. kishan Kumar singh

    Shows error when pressing bottom back button from file explorer widget.
    code line = line 49: String fileName = _path.split(‘/’).last;
    error= NoSuchMethodError: The method ‘split’ was called on null. Receiver: null Tried calling: split(“/”))

    Reply
  2. Kadir

    It was such a great tutorial, i’ve watched it on youtube.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *