👌

Flutter x Firebaseで画像をアップロードしてみる

2023/08/14に公開

初めに

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を有効にする

  1. Firebaseのダッシュボードを表示する
  2. 左メニューの「プロダクトのカテゴリ」 -> 「構築」 -> 「Stroage」 を選択する
  3. 「始める」を押下する
  4. Storageで開始するモードを選択する。説明は以下。とりあえずStorageの参照・更新がしたいので開発環境モードにする(忘れずにセキュリティルールは変える)
    • 本番環境モード: 基本的に外部(今回はアプリ)からの接続は拒絶する。許可したい場合はセキュリティルールの変更が必要
    • 開発環境モード: 外部(今回はアプリ)からの接続を全て許可するが、30日間の制限をつける。30日後以降はセキュリティルールの変更が必要
  5. ロケーションを選択する。Firestoreの設定でロケーションを指定している場合は指定は不要

Firebase Storageの画像を表示する

  1. Firebaseのプラグインをアプリに追加する flutter pub add firebase_storage
  2. 事前にStorageに画像をアップロードする(後述する画像アップロードでも可)
  3. 任意の画面にfirebase_storageをを追加する
import 'package:firebase_storage/firebase_storage.dart';
  1. 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);
}
  1. Widgetには以下のように追加する
    非同期で画像を取得して取得でき次第表示するため、FutureBuilderを使用
    画像が取得でき無い場合はContainerでとりあえず回避(本来ならもっと正しく異常系処理する)
FutureBuilder(
  future: download(),
  builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
    return snapshot.data ?? Container();
  },
)

Firebase Storageに画像をアップロードする

画像アップロードするPackageは何使ってもいいが、今回は今のところ一番メジャーなimage_pickerを使う

  1. image_pickerのプラグインをアプリに追加する flutter pub add image_picker
  2. 任意の画面にimage_pickerをを追加する
import 'package:image_picker/image_picker.dart';
  1. 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;
}
  1. Widgetには以下のように追加する
ElevatedButton(
  onPressed: () async {
    await upload();
  },
  child: const Text('画像アップロード')),

まとめ

Firebase Storageの操作を簡単にまとめてみた
実際画像をダウンロードする際は画像名を指定できない場合が多いので、Firebase Firestoreに画像用のコレクションを作成し、そこから参照URLでストレージを指定できるようにするが、今回は必要最低限の実装でFirebase Storageを操作する方法をまとめた

ちなみに本ソースをそのまま1つの画面に実装して画像をアップロードしても画像は表示されない
これは画像アップロード後に画面の再描画処理が走っていないためで、そのためにはStatefulWidgetRiverPodなどで状態管理を行い、再描画すればいいが今回はテーマが逸れるので割愛した

Discussion