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…
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: ^ 1.1 . 1 |
#2 Http Package
http: "0.11.3+17" |
#3 Firebase Storage
firebase_storage: ^ 2.0 . 0 |
Add DropDown
Lets add a DropDown in the UI to select multiple fiel types.
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
Lets open the Device’s File explorer and get the Files.
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, ), ), ); } |
Complete Code
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, ), ), ], ), ), ); }, ); } } |
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(“/”))
check if the split() method was called on a “null” object.
It was such a great tutorial, i’ve watched it on youtube.