本記事について
本記事はシリーズ連載記事の第4回になります。
今回はAWSのS3に入れた画像データをダウンロードして表示させたり、アプリからS3に画像アップロードさせるような仕様を実装する方法をご紹介しようと思います。
バージョン
S3とFlutterを接続する方法
FlutterではAmplifyを利用してS3に接続する方法が公式としても推奨されており、Amplifyを使う方法を紹介しているネット記事も多くありますが、S3のアクセスキーとシークレットキーだけを使ってシンプルにS3にアクセスしたいというだけだとAmplifyを使うのは少し大掛かりな感じなのと、今回はCognitoの認証機能も使用しないため、今回はシンプルに使える minio_new というライブラリを使用しようと思います。
S3に入れた画像をダウンロードして表示する
まずはminio_newをアプリに入れましょう。
$ flutter pub add minio_new
を実行すると、pubspec.yamlにminio_newが追加されます。
pubspec.yaml
dependencies: minio_new: ^1.0.2
S3のIAMやアクセスキーとシークレットキーの発行等の設定部分についてはこの記事では割愛させて頂きますが、ここではS3のバケットの直下にmofmofのロゴ画像「logo.png」を入れた形とします。
minioのS3へ接続するための初期化処理が下記です。regionは東京リージョンの場合を設定しています。必要なパッケージもインポートしています。
import 'package:flutter/material.dart'; import 'package:minio_new/minio.dart'; import 'dart:typed_data'; final minio = Minio( endPoint: 's3-ap-northeast-1.amazonaws.com', region: 'ap-northeast-1', accessKey: 'アクセスキー', secretKey: 'シークレットキー', );
そして、S3に接続して画像を取得する処理が下記です。
Future<Image> getImage() async { final stream = await minio.getObject('バケット名', 'logo.png'); List<int> memory = []; await for (var value in stream) { memory.addAll(value); } return Image.memory(Uint8List.fromList(memory)); }
初期化したminioのgetObjectメソッドでS3からデータをダウンロードします。ただ、S3からダウンロードしたデータのままでは Image
Widgetで表示させることが出来ないため、Uint8Listというデータの型に変更をかけています。この処理を入れることで、 Image
Widgetで画像表示をさせることが出来るようになります。
今回は上記の処理を lib/image_from_s3.dart というファイルを新規作成して実装しました。 lib/image_from_s3.dart の全体が下記になります。
lib/image_from_s3.dart
import 'package:flutter/material.dart'; import 'package:minio_new/minio.dart'; import 'dart:typed_data'; class ImageFromS3 extends StatelessWidget { ImageFromS3({super.key}); final minio = Minio( endPoint: 's3-ap-northeast-1.amazonaws.com', region: 'ap-northeast-1', accessKey: 'アクセスキー', secretKey: 'シークレットキー', ); Future<Image> getImage() async { final stream = await minio.getObject('バケット名', 'logo.png'); List<int> memory = []; await for (var value in stream) { memory.addAll(value); } return Image.memory(Uint8List.fromList(memory)); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('タイトル')), body: Center( child: FutureBuilder( future: getImage(), builder: (BuildContext context, AsyncSnapshot<Image> snapshot) { if (snapshot.hasData) { return Center(child: snapshot.data); } else { return const Center( child: Text('データが取得できていません'), ); } }, ), ), ); } }
lib/main.dart に lib/image_from_s3.dart をインポートしてシミュレータで表示させてみると、
上記のようにS3に入れたロゴ画像をアプリで表示させることが出来ました。
S3に画像をアップロードする
ローカルで持っている画像をS3にアップロードする処理を実装してみましょう。ローカルで画像を使えるようにするには、pubspec.yamlの flutter:
の項目のところに assets:
を設定する必要があります。
pubspec.yaml
flutter: assets: - images/
上記のように記載すると、imagesディレクトリの中のファイルが全てローカルで使用可能になります。デフォルトの状態ではディレクトリは存在しませんので、Flutterアプリのディレクトリ直下に images
ディレクトリを新規に作成します。そして作成したディレクトリに画像を入れます。ここでは logo2.png
という名前で画像を入れる形にします。
ここから具体的な実装のコード箇所になりますが、minioの初期化処理はダウンロードの時と同じです。
import 'package:flutter/material.dart'; import 'package:minio_new/minio.dart'; import 'dart:typed_data'; final minio = Minio( endPoint: 's3-ap-northeast-1.amazonaws.com', region: 'ap-northeast-1', accessKey: 'アクセスキー', secretKey: 'シークレットキー', );
そして、S3にファイルをアップロードする処理が下記になります。
void uploadImage() async { final byteData = await rootBundle.load('images/logo2.png'); Stream<Uint8List> imageBytes = Stream.value(byteData.buffer .asUint8List(byteData.offsetInBytes, byteData.lengthInBytes)); await minio.putObject( 'バケット名', 'logo2.png', imageBytes, ); }
ローカルで持っているimagesディレクトリ内のlogo2.pngというファイルを取得します。それをUint8ListのStreamという型に変換した上でminioのputObjectメソッドに渡しています。putObjectに渡せる型がUint8ListのStreamで指定されているため、このような形で処理をしている流れになります。
今回は lib/image_to_s3.dart というファイルを新規作成して上記の処理を実装して、それを lib/main.dart にインポートしました。
lib/image_to_s3.dart の全体が下記になります。
lib/image_to_s3.dart
import 'package:flutter/material.dart'; import 'package:minio_new/minio.dart'; import 'package:flutter/services.dart'; class ImageToS3 extends StatelessWidget { ImageToS3({super.key}); final minio = Minio( endPoint: 's3-ap-northeast-1.amazonaws.com', region: 'ap-northeast-1', accessKey: 'アクセスキー', secretKey: 'シークレットキー', ); void uploadImage() async { final byteData = await rootBundle.load('images/logo2.png'); Stream<Uint8List> imageBytes = Stream.value(byteData.buffer .asUint8List(byteData.offsetInBytes, byteData.lengthInBytes)); await minio.putObject( 'バケット名', 'logo2.png', imageBytes, ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('タイトル')), body: Center( child: GestureDetector( onTap: () { uploadImage(); }, child: const Text('タップしてアップロード'), ), ), ); } }
こちらをシミュレータで表示させて、「タップしてアップロード」のところをタップすると、S3のバケットにファイルがアップロードされることが確認できます。
最後に
今回はS3を使った画像アップロードとダウンロードのご紹介をさせて頂きました。元の画像データをそのままの形式で使うことが出来ずデータ形式の変更をしないといけないのは少し面倒かつややこしいところではあるのですが、画像データの形式の調整さえ上手く出来ればそれ以外の部分については使い方は分かりやすいかなと思います。