[Flutter/dart] Manage your data with a combination of Cloud Firestore and Firebase_Storage
Overview
If you want to save user information etc. in a serverless application, you probably use cloud fire store. However, only values such as int and string can be saved in firestore, and you need to use firebase_storage to save images.
This time, I will introduce how to manage user data (images & data such as int, String, etc.) by combining these two.
Method
Overview: upploading
User uploads local image → Get local image path
Save the image in storage with a suitable name
Save local image path and storage image path to firestore
Overview: downloading
Get the local image path and path of storage destination from the firestore
If the image remains in local directory, use that image path
Download from storage if the image does not left in local directory
Upload image
I think that you often use ImagePicker to upload images.
static Future<String> select_icon(BuildContext context) async{
static const String SELECT_ICON = "select icon";
static const List<String> SELECT_ICON_OPTIONS =
["select from gallery", "take picture"];
static const int GALLERY = 0;
static const int CAMERA = 1;
var _select_type=await showDialog(
context: context,
builder: (BuildContext context){
return SimpleDialog(
title: Text(SELECT_ICON),
children: SELECT_ICON_OPTIONS.asMap().entries.map((e) {
return SimpleDialogOption(
child: ListTile(
title: Text(e.value),
),
onPressed: ()=>Navigator.of(context).pop(e.key),
);
}).toList(),
) ;
});
final picker=ImagePicker();
var _img_src;
if (_select_type==null){
return null;
}
//take picture by camera
else if (_select_type==CAMERA){
_img_src=ImageSource.camera;
}
//select from gallery
else if (_select_type==GALLERY){
_img_src=ImageSource.gallery;
}
final pickedFile = await picker.getImage(source: _img_src);
if (pickedFile==null){
return null;
}
else{
return pickedFile.path;
}
}
When you get an image with ImagePicker, the image is saved in the local folder, so get the path and save it as the local path.
Save image in Firebase Storage
Create the following method according to the official site.
import 'dart:io' as io;
Future<void> uploadFile(String sourcePath, String uploadFileName) async{
final FirebaseStorage storage=FirebaseStorage.instance;
Reference ref=storage.ref().child("images"); //save folder
io.File file=io.File(sourcePath);
UploadTask task=ref.child(uploadFileName).putFile(file);
try{
var snapshot=await task;
}
catch(FirebaseException){
//error handling
}
}
Enter the local path obtained earlier in sourcePath and a unique name in uploadFileName.
You have now uploaded your image to Firebase Storage.
Save image file path
Finally, save the above local image path and the path saved in storage to firestore (in String type).
For example, if there is a collection for each user, the method to add the image path to each user's data is as follows. (Official) (The document id is given as the first argument)
Future<void> addFilePath(String userId, String localPath,
String remotePath){
CollectionReference users =
FirebaseFirestore.instance.collection('users');
await users.doc(userId)
.set(
{
'localPath': localPath,
'remotePath': remotePath,
},
SetOptions(merge: true)
);
}
Download image
From the firestore, get the local path and the save destination path to the storage of the previously saved image as a String type.
If you have images left locally, you don't have to download them from storage, so check this first.
If the image remains locally, pass the path to Image etc.
If it doesn't remain locally, download the image from storage and pass the path to Image etc.
The following method returns the local path or the storage path, whichever is appropriate.
Future<String> _getImgs(String imgPathLocal, String imgPathRemote) async{
bool existLocal=await io.File(imgPathLocal).exists();
String imgPathUse="";
if (existLocal) {
//Use local image if it exists locally
imgPathUse=imgPathLocal;
}
else {
if ((imgPathRemote != "") && (imgPathRemote != null)) {
try {
//Download remote data if it does not exist locally
imgPathUse = await FirebaseStorage.instance.ref().
child("images").child(imgPathRemote).getDownloadURL();
}
catch (FirebaseException) {
imgPathUse = "";
}
}
else{
imgPathUse="";
}
}
return imgPathUse;
}
Lastly
If you want to make something like SNS, you will prepare a server, but even with a serverless application, you may want to let the user set a small image such as an icon image. In such a case, please refer to it.
However, since it is operated only by personal development, please use it as a reference.
Recent Posts
See AllWhat want to do I want to create an input form using TextField. For example, if the input content is a monetary amount, I would like to...
What want to do There is a variable that remain unchanged once the initial value is determined. However, it cannot be determined yet when...
What want to do As the title suggests. Place two widgets in one line on the screen One in the center of the screen and the other on the...
Comments