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.