LoginSignup
2
2

【Flutter x Supabase】 画像のアップロードのやり方+おまけつき

Last updated at Posted at 2023-12-12

スクリーンショット 2023-12-01 12.12.50(2).png

この記事は、株式会社ゆめみの23卒 Advent Calendar 2023のアドベントカレンダーになります!!
色々な種類の記事が投稿されるので、お楽しみに🤗

こんにちは。いせりゅーです。今回は、Flutter x Supabaseで画像のアップロードする方法に加えて、必要そうな記載を書いてみました。(あくまでも一例です)

Supabaseを学習し始めてからまもないため、間違えた実装を記載するかも知れません。その場合はコメントなどで教えていただけると幸いです🙇

1、カメラかカメラロールか選択するSheetを出す。
2、ImagePickerで写真を取得する
3、画像をアップロードする。

こんな感じで進めていきます〜〜!!

カメラorカメラロールか選択するSheetを出す。

写真をアップロードする場合において、「カメラ」か「カメラロール」の2種類で画像をアップロードすることが多いと思います。
これの表現方法はいくらでもありますが、今回は、Sheetを出す形にしてみました。iOS風にしたかったためshowCupertinoModalPopupを使用してみました。

  void onTapImage() {
    showCupertinoModalPopup(
      context: context,
      builder: (context) => CupertinoActionSheet(
        actions: [
          CupertinoActionSheetAction(
            isDefaultAction: true,
            onPressed: () {
              Navigator.pop(context);
              camera();
            },
            child: const Text(
              'カメラ',
              style: TextStyle(
                fontWeight: FontWeight.bold,
                color: Colors.black,
              ),
            ),
          ),
          CupertinoActionSheetAction(
            onPressed: () {
              Navigator.pop(context);
              album();
            },
            child: const Text(
              'アルバム',
              style: TextStyle(
                fontWeight: FontWeight.bold,
                color: Colors.black,
              ),
            ),
          ),
          CupertinoActionSheetAction(
            isDestructiveAction: true,
            onPressed: () =>  Navigator.pop(context),
            child: const Text('閉じる'),
          ),
        ],
      ),
    );
  }

  void camera() {
  
  }

  void album() {
  
  }
  

ImagePickerで写真を取得する

次に画像を取得する処理を記載します。今回は、image_pickerを導入しました。

Androidのセットアップ

android/app/src/main/AndroidManifest.xml

<uses-permission android:name="android.permission.CAMERA" />

android/app/build.gradle

defaultConfig {
  applicationIdSuffix appIdSuffix
  // minSdkVersion 19
  minSdkVersion 21
  targetSdkVersion flutter.targetSdkVersion
  versionCode flutterVersionCode.toInteger()
  versionName flutterVersionName
  resValue "string", "app_name", appName
}

iOSのセットアップ

ios/Runner/Info.plist
<key>NSPhotoLibraryUsageDescription</key>
<string>写真の投稿のために許可が必要になります</string>
<key>NSCameraUsageDescription</key>
<string>写真の投稿のために許可が必要になります</string>

画像を取得する

final picker = ImagePicker();
String uploadImage = '';

 // カメラからの画像を取得する
 Future<void> camera() async {
    try {
      final image = await ImagePicker().pickImage(source: ImageSource.camera);
      if (image == null) {
        return;
      }
      imageBytes = await image.readAsBytes();
      uploadImage = image.name;
      print('画像の添付が成功しました');
    } on PlatformException catch (error) {
      print(error);
    }
  }

  Future<void> album() async {
    try {
      final image = await ImagePicker().pickImage(source: ImageSource.gallery);
      if (image == null) {
        return;
      }
      imageBytes = await image.readAsBytes();
      uploadImage = image.name;
      print('画像の添付が成功しました');
    } on PlatformException catch (e) {
      state = state.copyWith(status: e.message!);
    }
  }

画像をアップロードする。

では、Supabaseに画像をアップロードしていこうと思います。
その前にSupabase側で設定が必要そうですね。こちらを参考にしてみてください(今回は割愛させていただきます)
今回は、画像のPathをid/画像のパスにしてみました。理由としては、どのユーザーが投稿したかをわかりやすくするためでした。(もっといい方法があれば知りたい😇)

final supabase = Supabase.instance.client;![スクリーンショット 2023-12-01 12.12.502.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/672609/4d213fd7-f6ff-a7c5-444c-7bf7eb0f5bfa.png)


Future<void> upload() async {
    loading.state = true;
    final user = supabase.auth.currentUser?.id;
    try {
      await supabase.storage.from('food').uploadBinary('/$user/$uploadImage', imageBytes);
    } on PostgrestException catch (error) {
      print(error);
    }
  }

ソースコード

  final picker = ImagePicker();
  String uploadImage = '';
  final supabase = Supabase.instance.client;

  void onTapImage() {
    showCupertinoModalPopup(
      context: context,
      builder: (context) => CupertinoActionSheet(
        actions: [
          CupertinoActionSheetAction(
            isDefaultAction: true,
            onPressed: () {
              Navigator.pop(context);
              camera();
            },
            child: const Text(
              'カメラ',
              style: TextStyle(
                fontWeight: FontWeight.bold,
                color: Colors.black,
              ),
            ),
          ),
          CupertinoActionSheetAction(
            onPressed: () {
              Navigator.pop(context);
              album();
            },
            child: const Text(
              'アルバム',
              style: TextStyle(
                fontWeight: FontWeight.bold,
                color: Colors.black,
              ),
            ),
          ),
          CupertinoActionSheetAction(
            isDestructiveAction: true,
            onPressed: () =>  Navigator.pop(context),
            child: const Text('閉じる'),
          ),
        ],
      ),
    );
  }

 Future<void> camera() async {
    try {
      final image = await ImagePicker().pickImage(source: ImageSource.camera);
      if (image == null) {
        return;
      }
      imageBytes = await image.readAsBytes();
      uploadImage = image.name;
      print('画像の添付が成功しました');
    } on PlatformException catch (error) {
      print(error);
    }
  }

  Future<void> album() async {
    try {
      final image = await ImagePicker().pickImage(source: ImageSource.gallery);
      if (image == null) {
        return;
      }
      imageBytes = await image.readAsBytes();
      uploadImage = image.name;
      print('画像の添付が成功しました');
    } on PlatformException catch (e) {
      state = state.copyWith(status: e.message!);
    }
  }

  Future<void> upload() async {
    loading.state = true;
    final user = supabase.auth.currentUser?.id;
    try {
      await supabase.storage.from('food').uploadBinary('/$user/$uploadImage', imageBytes);
    } on PostgrestException catch (error) {
      print(error);
    }
  }

最後に

自分もまだまだ学習中ですが、Supabaseのいいところが毎日見つかってきてとてもいいですね。個人的にはこれからの発展に期待したいですね😁

ちょっとした宣伝

株式会社ゆめみの23卒のメンバーでアドベントカレンダーを作成しています。
新卒のフレッシュな記事がたくさん投稿予定なので、少しでも興味があれば購読いただけると幸いです!!

YUMEMI New Grad Advent Calendar 2023

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2