😎

FirebaseStorageへの画像アップロード

2024/06/01に公開

はじめに

Flutterを使用して、FirebaseStrageへ画像をアップロードする方法です。
より詳細な内容は公式ページにまとまっています。

https://firebase.google.com/docs/storage/flutter/upload-files?hl=ja&_gl=1

まずはimage_pickerをパッケージ追加する

今回は、ユーザが画像ライブラリから選択した画像をアップロードする、という挙動を実現しようと思います。
そのため、image_pickerを利用します。

pubspec.yaml
name: testapp
description: "A new Flutter project."
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev

# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1

environment:
  sdk: '>=3.3.0 <4.0.0'

# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.6
  google_fonts: ^6.2.1
  firebase_core: ^2.30.1
  cloud_firestore: ^4.15.9
  intl: ^0.19.0
  flutter_chat_ui: ^1.6.12
  firebase_auth: ^4.19.5
  glassmorphism: ^3.0.0
  bordered_text: ^2.0.0
  awesome_dialog: ^3.2.0
  firebase_storage: ^11.7.5
  image_picker_web: ^3.1.1
  image_picker: ^1.1.1 # ← こいつ!!!!!!!!!!!!!!!!!!!!!!!

ユーザに画像を選択させる

先ほど導入したimage_pickerを利用して、ユーザに画像を選択させます。
選択した画像情報は、imageに格納されます。

/// 画像ファイルのアップロード
Future<void> _uploadImage() async {
    try{
        final ImagePicker picker = ImagePicker();
        // ユーザーに画像を選択させ、画像情報を取得する
        final XFile? image = await picker.pickImage(source: ImageSource.gallery);
        if (image == null) {
            return;
        }
    } catch(e){
        if (kDebugMode) {
            print(e);
        }
        if (kDebugMode) {
            print(FirebaseAuth.instance.currentUser!);
        }
    }

Firebase Storageにアップロードする

Firebase Storageに選択したファイルをアップロードします。
取得した画像情報を引数に指定してあげて、
await FirebaseStorage.instance.ref(fileName).putFile(File(image.path));でアップロードできます。
今回はファイル名が一意になるように、fileNameには「ユーザID + yyyyMMddHHmmss」にしています。

/// 画像ファイルのアップロード
Future<void> _uploadImage() async {
    try{
        final ImagePicker picker = ImagePicker();
        // ユーザーに画像を選択させ、画像情報を取得する
        final XFile? image = await picker.pickImage(source: ImageSource.gallery);
        if (image == null) {
            return;
        }

        String fileName = '${DateFormat('yyyyMMddHHmmss').format(
                                Timestamp.now().toDate())}_${userId}';

        // Firebase Storageにアップロード
        await FirebaseStorage.instance.ref(fileName)
                .putFile(File(image.path));

    } catch(e){
        if (kDebugMode) {
            print(e);
        }
        if (kDebugMode) {
            print(FirebaseAuth.instance.currentUser!);
        }
    }

アップロードした画像情報をFirestore Databaseに登録する

ここまでで、Firebase Storageには画像が保存されていますが、後々ダウンロードすることを考え、画像情報をFirestore Databaseに登録しておきます。
今回は画像ファイル名、画像のURLを保持しておくためのimagesというコレクションを用意しました。

/// 画像ファイルのアップロード
Future<void> _uploadImage() async {
    try{

        // ====================中略====================

        String fileName = '${DateFormat('yyyyMMddHHmmss').format(
                                Timestamp.now().toDate())}_${userId}';

        // Firebase Storageにアップロード
        await FirebaseStorage.instance.ref(fileName)
                .putFile(File(image.path));

        // Firebase Storageの参照を作成
        final Reference storageReference =
                FirebaseStorage.instance.ref(fileName);

        // 画像のURLを取得
        final String imageUrl = await storageReference.getDownloadURL();

        // DBに画像情報を登録
        final db = FirebaseFirestore.instance;

        final images = <String, dynamic>{
            "diary_id": diaryId,
            "user_id": userId,
            "name": fileName,
            "url": imageUrl,
            "delete_flg":0,
            "insert_date_time": Timestamp.now(),
            "update_date_time": Timestamp.now(),
        };

      // Add a new document with a generated ID
      db.collection("images").add(images);

    } catch(e){
        if (kDebugMode) {
            print(e);
        }
        if (kDebugMode) {
            print(FirebaseAuth.instance.currentUser!);
        }
    }

Discussion