👌
Flutter x Firebaseで画像をアップロードしてみる
初めに
FirebaseのStorageに画像をアップロードする機能を作り、逆にFirebaseのStorageから画像を取得し表示する機能を作る
基本的にはFirestoreと同様
前提条件
- Androidエミュレータ、iOSシミュレータ、または実機でFlutterを実行できること
- Flutter上でFirebaseの操作ができること
実装環境
- Android Studio 2022.3.1
- Flutter 3.10 (Dart 3.0.0)
- Androidエミュレータ Nexus 6 API 33
- firebase_core: ^2.15.0
- cloud_firestore: ^4.8.4
インストールしたパッケージ
- firebase_storage: ^11.2.5
- image_picker: ^1.0.2
Firebase Storageを有効にする
- Firebaseのダッシュボードを表示する
- 左メニューの「プロダクトのカテゴリ」 -> 「構築」 -> 「Stroage」 を選択する
- 「始める」を押下する
- Storageで開始するモードを選択する。説明は以下。とりあえずStorageの参照・更新がしたいので開発環境モードにする(忘れずにセキュリティルールは変える)
- 本番環境モード: 基本的に外部(今回はアプリ)からの接続は拒絶する。許可したい場合はセキュリティルールの変更が必要
- 開発環境モード: 外部(今回はアプリ)からの接続を全て許可するが、30日間の制限をつける。30日後以降はセキュリティルールの変更が必要
- ロケーションを選択する。Firestoreの設定でロケーションを指定している場合は指定は不要
Firebase Storageの画像を表示する
- Firebaseのプラグインをアプリに追加する
flutter pub add firebase_storage
- 事前にStorageに画像をアップロードする(後述する画像アップロードでも可)
- 任意の画面にfirebase_storageをを追加する
import 'package:firebase_storage/firebase_storage.dart';
- Firebase Storageから画像を取得する
今回はとりあえず表示するため直接Imageを取得するようにした
Future<Image> download() async { // 非同期処理で取得する
final Reference ref = FirebaseStorage.instance.ref().child('sample.png');
String imageUrl = await ref.getDownloadURL();
return Image.network(imageUrl);
}
- Widgetには以下のように追加する
非同期で画像を取得して取得でき次第表示するため、FutureBuilderを使用
画像が取得でき無い場合はContainerでとりあえず回避(本来ならもっと正しく異常系処理する)
FutureBuilder(
future: download(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
return snapshot.data ?? Container();
},
)
Firebase Storageに画像をアップロードする
画像アップロードするPackageは何使ってもいいが、今回は今のところ一番メジャーなimage_pickerを使う
- image_pickerのプラグインをアプリに追加する
flutter pub add image_picker
- 任意の画面にimage_pickerをを追加する
import 'package:image_picker/image_picker.dart';
- Firebase Storageに画像をアップロード
Future upload() async {
// 画像をスマホのギャラリーから取得
final image = await ImagePicker().pickImage(source: ImageSource.gallery);
// 画像を取得できた場合はFirebaseStorageにアップロードする
if (image != null) {
final imageFile = File(image.path);
FirebaseStorage storage = FirebaseStorage.instance;
try {
await storage.ref('sample.png').putFile(imageFile);
} catch (e) {
print(e);
}
}
return;
}
- Widgetには以下のように追加する
ElevatedButton(
onPressed: () async {
await upload();
},
child: const Text('画像アップロード')),
まとめ
Firebase Storageの操作を簡単にまとめてみた
実際画像をダウンロードする際は画像名を指定できない場合が多いので、Firebase Firestoreに画像用のコレクションを作成し、そこから参照URLでストレージを指定できるようにするが、今回は必要最低限の実装でFirebase Storageを操作する方法をまとめた
ちなみに本ソースをそのまま1つの画面に実装して画像をアップロードしても画像は表示されない
これは画像アップロード後に画面の再描画処理が走っていないためで、そのためにはStatefulWidgetやRiverPodなどで状態管理を行い、再描画すればいいが今回はテーマが逸れるので割愛した
Discussion