[Flutter/dart] Cloud FirestoreとFirebase_Storageを組み合わせてデータを管理する
概要
サーバレスのアプリでユーザの情報などを保存しておく場合、cloud firestoreを使うことが多いかと思います。ただし、firestoreに保存できるのはint、stringなどの値だけで、画像の保存はfirebase_storageを使用する必要があります。
今回は、この2つを合わせてユーザのデータ(int、String等のデータ & 画像)を管理する方法をご紹介します。
方法
概要:アップロード時
ユーザがローカル画像をアップロード → ローカルの画像パスを取得
適当な名前でstorageに画像を保存
ローカルの画像パスとstorageの画像パスをfirestoreに保存
概要:ダウンロード時
firestoreから画像のローカル、storageでの保存先のパスを取得
ローカルに画像が残っている場合はその画像パスを使用
ローカルに残っていない場合はstorageからダウンロード
画像をアップロード
よく使うのはImagePickerで画像をアップロードしてもらうことだと思います。
static Future<String> select_icon(BuildContext context) async{
static const String SELECT_ICON = "アイコンを選択";
static const List<String> SELECT_ICON_OPTIONS =
["写真から選択", "写真を撮影"];
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;
}
//カメラで撮影
else if (_select_type==CAMERA){
_img_src=ImageSource.camera;
}
//ギャラリーから選択
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;
}
}
ImagePickerで画像を取得する場合は、画像がローカルフォルダに保存されるので、そのパスを取得し、ローカルパスとして記憶しておきます。
Firebase Storageに画像を保存
公式 に従って以下のようなメソッドを作ります。
import 'dart:io' as io;
Future<void> uploadFile(String sourcePath, String uploadFileName) async{
final FirebaseStorage storage=FirebaseStorage.instance;
Reference ref=storage.ref().child("images"); //保存するフォルダ
io.File file=io.File(sourcePath);
UploadTask task=ref.child(uploadFileName).putFile(file);
try{
var snapshot=await task;
}
catch(FirebaseException){
//エラー処理
}
}
sourcePathには先に取得したローカルパス、uploadFileNameには一意になるような名前を入れます。
これでFirebase Storageに画像をアップロードできました。
画像のファイルパスを保存
最後に、上記のローカルの画像パスとstorageに保存したパスをfirestoreに(String型で)保存します。
例えばユーザ毎のコレクションがあり、各ユーザのデータに画像のパスを追加するメソッドは以下のようになります。(公式)(ドキュメントidを第1引数で与えます)
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)
);
}
画像のダウンロード
firestoreから、先に保存した画像のローカル、storageへの保存先パスをString型で取得します。
ローカルに画像が残っているならばわざわざstorageからダウンロードしなくてもいいので、まずはこれを確認します。
ローカルに画像が残っている場合はそのパスをImageなどに渡します。
ローカルに残っていなければstorageから画像をダウンロードし、そのパスをImageなどに渡します。
以下のメソッドはローカルパスかstorageのパスか適切な方を返します。
Future<String> _getImgs(String imgPathLocal, String imgPathRemote) async{
bool existLocal=await io.File(imgPathLocal).exists();
String imgPathUse="";
if (existLocal) {
//ローカルに存在する場合はローカルの画像を使う
imgPathUse=imgPathLocal;
}
else {
if ((imgPathRemote != "") && (imgPathRemote != null)) {
try {
//ローカルに存在しない場合はリモートのデータをダウンロード
imgPathUse = await FirebaseStorage.instance.ref().
child("images").child(imgPathRemote).getDownloadURL();
}
catch (FirebaseException) {
imgPathUse = "";
}
}
else{
imgPathUse="";
}
}
return imgPathUse;
}
最後に
まあSNSみたいなものを作るんだったらサーバを用意すると思いますが、サーバレスのアプリでもアイコン画像みたいなちょっとした画像をユーザに設定させたい場合もあるかと思います。そんな場合は是非参考にしてみてください。
ただし、あくまでも個人開発でしか運用していないのでご参考程度にお願いします。
最新記事
すべて表示やりたいこと TextFieldで入力フォームを作りたい。 例えば入力内容が金額の場合、3桁区切りで頭に¥を付けた表記にしたい。 ただしユーザにこれらを入力させるのではなく、ユーザはあくまで数字を入力するだけで、アプリ側で自動でフォーマットしたい。 方法...
現象 やってること iosシミュレータで画像をデバイスのローカルに保存 保存したパスをデータベースに保存 アプリ立ち上げ時にデータベースから画像パスを取得し、そのパスの画像を画面上に表示 起きている現象 iosシミュレータを再起動した場合、上記3で「ファイルパスが見つからな...
やりたいこと 初期値さえ決まればあとは不変な変数がある ただし、コンストラクタ起動時にはまだ決定できない このような変数について late finalで変数を定義 (何らかのタイミングで)初期化されたかどうかをチェックし、されていなければ値を入れる(チェックしないとfina...
Comments