LoginSignup
0
2

More than 1 year has passed since last update.

AWS S3で追加した画像をFlutterで表示する方法

Last updated at Posted at 2022-10-04

はじめに

S3で追加した画像をFlutterで表示する方法がわからず苦労したので、
解決方法を記事にしたいと思います。

今回の記事では、S3にアクセスするのにminioというパッケージを使用しています。

Flutterで、AWS のサービス・リソースにアクセスするときに使うライブラリは、公式にはamplify使用するのがスタンダードみたいで、S3へのアクセスにはamplify_storage_s3を使用するみたいですが、
amplifyの事前準備が面倒に思えたのでminioを使ってます。

また解説はFlutterの環境設定とコードのみとなります。
S3での画像追加方法については割愛しますのでご了承ください。

目次

  1. 設定
  2. S3にアクセスするためのコードを実装
  3. S3から画像を取得し、表示するコードを実装

設定

こちらの記事を参照しました。
一部重複するところがありますがご了承ください。

1 pubspec.yamlにパッケージを追加

以下のパッケージを追加してください
minio
 → S3にアクセスするために使う
flutter_dotenv
 → S3アクセスに必要な情報を定義したenvファイルを読み込むために使用する

2 envファイルを読み込むためにassetsを編集する

pubsbec.yaml
  assets:
    - .env.dev // この行を追加

3 envファイルを作成する

プロジェクト直下(pubspec.yamlと同階層)に.env.devを作成する

内容は下記参照。

.env.dev
END_POINT=s3-ap-northeast-1.amazonaws.com
REGION=ap-northeast-1
ACCESS_KEY=アクセスキー
SECRET_KEY=シークレットキー
BUCKET=バケット名
  • アクセスキー
    S3にアクセスできるIAMユーザーのアクセスキー
    わからない場合、またはない場合は下記の手順で作成してください

    1. AWSのコンソールにログイン
    2. サービス一覧からIAMに移動
    3. S3にアクセスできるIAMユーザーを表示
    4. 認証情報を確認
    5. アクセスキーの作成
    6. csvをダウンロード ※外部に公開しないよう厳重に管理
  • シークレットキー
    上記で作成したアクセスキーのCSVに載ってます

  • バケット名
    オブジェクト(画像ファイル)を追加したバケットの名前

4 envファイルをGit管理から外す

※ソースをGit管理している人は.gitignoreに下記を追加してください
ソースをPushする際には、作成したenvファイルがコミットに含まれていないか確認お願いします
認証情報が外部に漏れる可能性があるため、Gitには上げない方がいいと思います

.gitignore
.env.dev
.env

S3にアクセスするためのコードを実装

1 envファイルを読み込み

flutter_dotenvをインポートし、void main()のメソッド内のrunAppの前に以下の一行を追加してください。

main.dart
import 'package:flutter_dotenv/flutter_dotenv.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // 下記の一行を追加
  await dotenv.load(fileName: ".env.dev");
  runApp(const ProviderScope(child: MyApp()));
}

2 S3を操作するMinioを取得するコードを実装

Minioを取得するシングルトンのクラスとして実装してみました。

S3.dart
class S3 {
  Minio? _minio;
  S3._();

  static final instance = S3._();
  Minio getMinio(){
      _minio ??= Minio(
        endPoint: dotenv.env['END_POINT']!,
        region: dotenv.env['REGION']!,
        accessKey: dotenv.env['ACCESS_KEY']!,
        secretKey: dotenv.env['SECRET_KEY']!,
        useSSL: true,
      );
    return _minio!;
  }
}

S3から画像を取得し、表示するコードを実装

本記事の肝の部分です。

1 S3から画像を取得し表示するWidget

Widget化してみましたので、適宜カスタマイズしてお使いください。
デバッグはあまりしてないので、不具合等あるかもしれませんがご了承ください。
あと、main.dartのインポート部分は、S3にアクセスするためのコードを実装2 S3を操作するMinioを取得するコードを実装で作成したクラスを定義したファイルをインポートしてください。(私は横着してmain.dartに実装してます)

使い方は、画像表示したい箇所でImageFromS3(bucketName: 'バケット名', objectName: 'オブジェクト名')を呼んでください。

image_from_s3.dart
import 'dart:typed_data';
import 'package:flutter/material.dart';
// S3クラスを定義したファイルをインポート
import '../main.dart';

class ImageFromS3 extends StatelessWidget {
  final String bucketName;
  final String objectName;
  const ImageFromS3({Key? key, required this.bucketName, required this.objectName}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
        future: getImage(),
        builder: (BuildContext context, AsyncSnapshot<Image> snapshot) {
          if (snapshot.connectionState != ConnectionState.done) {
            return const CircularProgressIndicator();
          }

          if (snapshot.hasError) {
            return Text(snapshot.error.toString());
          }

          if (snapshot.hasData) {
            return Container(child: snapshot.data!,);
          } else {
            return const Text("データが存在しません");
          }

        },
    );
  }

  Future<Image> getImage() async {
    final minio = S3.instance.getMinio();
    final stream = await minio.getObject(bucketName, objectName);
    List<int> memory = [];
    await for (var value in stream) {
      memory.addAll(value);
    }
    return Image.memory(Uint8List.fromList(memory));
  }
}

2 画像を取得し、表示する部分の解説

画像を取得し、Imageウィジェット化している部分は上記コードのgetImageメソッドです。

まず以下のコードでS3からオブジェクトを取得しています

    final minio = S3.instance.getMinio();
    final stream = await minio.getObject(bucketName, objectName);

この部分は他の記事でも解説があり、少し調べればたどり着けました。

続いて、取得したオブジェクトをImageウィジェット化するコードが以下です。
(私はこの部分の実装がわからず苦労しました)

    List<int> memory = [];
    await for (var value in stream) {
      memory.addAll(value);
    }
    return Image.memory(Uint8List.fromList(memory));

まず、minio.getObjectメソッドでバイトデータのMinioByteStreamが返ってくるので、
バイトデータからImageウィジェットを作成するために、Imageウィジェットを作成するメソッドの一つであるImage.memoryを使えば画像を表示できるのでは?と当りを付けました。

ただ、MinioByteStreamをどうやってバイトデータに変換すればいいのかわからず、Streamについて調べたところ、
await forを使えば、Streamの終了を待てるという記事(dart の stream を理解して async* と yield を正しく使う)があったので、
試しに実装してみたところうまく表示できました。

少しでもご参考になりましたら、いいね押していただけると励みになります( `・∀・´)ノヨロシク

0
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
0
2