ます。
1. Flutterプロジェクトの作成と必要なパッケージのインストール
まずはFlutterプロジェクトを作成し、以下の2つのパッケージをインストールしてください。
flutter pub add supabase
flutter pub add image_picker
Supabaseはデータベースとの通信を行うために使用します。image_pickerはユーザーが自分の端末から画像を選択できるようにするために使用します。
2. Supabaseの初期化とログイン処理の実装
まずはSupabaseとの通信を行うための初期化と、ログイン処理の実装を行います。以下のコードをmain.dartに追加してください。
import 'package:flutter/material.dart';
import 'package:supabase/supabase.dart';
const supabaseUrl = 'SUPABASE_URL';
const supabaseAnonKey = 'SUPABASE_ANON_KEY';
const supabase = SupabaseClient(supabaseUrl, supabaseAnonKey);
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
final response = await supabase.auth.signIn(
email: 'EMAIL',
password: 'PASSWORD'
);
if (response.error != null) {
print(response.error!.message);
return;
}
runApp(App());
}
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Profile Image Upload',
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
SUPABASE_URLとSUPABASE_ANON_KEYには、SupabaseのURLとAnonymous Keyをそれぞれ設定してください。また、EMAILとPASSWORDはSupabaseで登録したユーザーアカウントの情報に置き換えてください。ログイン処理が成功した場合、Appウィジェットを起動します。Appウィジェットは今回作るアプリのルートウィジェットとなります。
3. 画像選択機能の実装
ユーザーが自分の端末から画像を選択できるように、以下のように画像選択機能を実装します。
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State {
final _picker = ImagePicker();
File? _image;
Future _pickImage(ImageSource source) async {
final pickedImage = await _picker.pickImage(source: source);
if (pickedImage != null) {
final imageFile = File(pickedImage.path);
setState(() {
_image = imageFile;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Profile Image Upload'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (_image != null)
Image.file(_image!, width: 300.0),
SizedBox(height: 16.0),
ElevatedButton.icon(
onPressed: () => _pickImage(ImageSource.gallery),
icon: Icon(Icons.photo_library),
label: Text('Select Image'),
),
],
),
),
);
}
}
_pickImage()メソッドで画像を選択した後、選択した画像を_stateful widget_内の_image変数に格納しています。選択した画像は、Image.file()ウィジェットを使って表示されます。
4. 画像をストレージにアップロードする処理の実装
次に、選択した画像をストレージにアップロードする処理を実装します。以下のように_stateful widget_の_HomePageStateクラスにuploadImage()メソッドを追加します。
class _HomePageState extends State {
...
Future _uploadImage() async {
if (_image == null) return;
final storageResponse = await supabase.storage
.from('PROFILE_IMAGES')
.upload('profile.png', _image!.readAsBytesSync(), cacheControl: '3600')
.onError((error, stackTrace) {
print('Error uploading image: $error');
return;
});
if (storageResponse.error == null) {
print('Image uploaded successfully!');
// TODO: Update user profile with photo_url
}
}
...
}
ここでは、Supabaseのストレージに_IMAGE-URL_という名前のフォルダを作成し、そこにアップロードします。アップロードには、Supabaseの_storage_ライブラリを使用します。アップロードが成功した場合、コンソールに「Image uploaded successfully!」と表示されます。
5. ユーザーのプロフィール情報を更新する処理の実装
最後に、ユーザーのプロフィール情報を更新する処理を実装します。ここでは、Supabaseの_auth_ライブラリを使用します。以下のようにsetState()メソッドを用いて、ウィジェットを再描画し、アップロードした画像を表示します。
class _HomePageState extends State {
...
Future _updateProfile(String imageUrl) async {
final user = supabase.auth.currentUser;
if (user == null) return;
final response = await supabase.from('profiles')
.update({'photo_url': imageUrl})
.eq('id', user.id)
.execute();
if (response.error == null) {
print('Profile updated successfully!');
setState(() => user.userMetadata.photoUrl = imageUrl);
}
}
...
}
また、以下のように ElevatedButton を追加して、ボタンを押したときに_updateProfile() メソッドが呼び出されるようにしてください。
ElevatedButton.icon(
onPressed: () async {
await _uploadImage();
await _updateProfile('$_supabaseUrl/storage/v1/object/PROFILE_IMAGES/profile.png');
},
icon: Icon(Icons.upload),
label: Text('Upload Image'),
),
6. 完成したコード
最終的に完成したコードは、以下のようになります。
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:supabase/supabase.dart';
const supabaseUrl = 'SUPABASE_URL';
const supabaseAnonKey = 'SUPABASE_ANON_KEY';
const supabase = SupabaseClient(supabaseUrl, supabaseAnonKey);
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
final response = await supabase.auth.signIn(
email: 'EMAIL',
password: 'PASSWORD'
);
if (response.error != null) {
print(response.error!.message);
return;
}
runApp(App());
}
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Profile Image Upload',
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State {
final _picker = ImagePicker();
File? _image;
Future _pickImage(ImageSource source) async {
final pickedImage = await _picker.pickImage(source: source);
if (pickedImage != null) {
final imageFile = File(pickedImage.path);
setState(() {
_image = imageFile;
});
}
}
Future _uploadImage() async {
if (_image == null) return;
final storageResponse = await supabase.storage
.from('PROFILE_IMAGES')
.upload('profile.png', _image!.readAsBytesSync(), cacheControl: '3600')
.onError((error, stackTrace) {
print('Error uploading image: $error');
return;
});
if (storageResponse.error == null) {
print('Image uploaded successfully!');
// TODO: Update user profile with photo_url
}
}
Future _updateProfile(String imageUrl) async {
final user = supabase.auth.currentUser;
if (user == null) return;
final response = await supabase.from('profiles')
.update({'photo_url': imageUrl})
.eq('id', user.id)
.execute();
if (response.error == null) {
print('Profile updated successfully!');
setState(() => user.userMetadata.photoUrl = imageUrl);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Profile Image Upload'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (_image != null)
Image.file(_image!, width: 300.0),
SizedBox(height: 16.0),
ElevatedButton.icon(
onPressed: () => _pickImage(ImageSource.gallery),
icon: Icon(Icons.photo_library),
label: Text('Select Image'),
),
SizedBox(height: 16.0),
ElevatedButton.icon(
onPressed: () async {
await _uploadImage();
await _updateProfile('$_supabaseUrl/storage/v1/object/PROFILE_IMAGES/profile.png');
},
icon: Icon(Icons.upload),
label: Text('Upload Image'),
),
],
),
),
);
}
}
コメント