앞서 설치한 firebase SDK에서 제공해주는 Image Storage 기능이다.
사실 이 기능은 back-end가 구축되어있다면 신경쓸 필요가 없는 부분이라 넘어가려했는데 기왕 firebase SDK 설치한거 auth 부터 storeage, notification 까지 한 번 뽕을 뽑아보자
우선 Storage를 시작하면 Rule를 바꿔줘야한다.
flutter pub add firebase_storage
flutter pub add image_picker
class UserImagePicker extends StatefulWidget {
const UserImagePicker({super.key, required this.onPickedImage});
final void Function(File pickedImage) onPickedImage;
State<UserImagePicker> createState() {
return _UserImagePickerState();
}
}
부모로 부터 function을 넘겨받아서 값을 전달해주고 해당 state로 인하여 UI(Circle Avartar)가 변경되어야하기 때문에 StatefulWidget으로 작성해주어야한다.
drop drilling을 위한 함수를 생성해준다.
class _UserImagePickerState extends State<UserImagePicker> {
File? _pickedImageFile;
void _pickImage() async {
final pickedImage = await ImagePicker()
.pickImage(source: ImageSource.camera, imageQuality: 50, maxWidth: 150);
if (pickedImage == null) {
return;
}
setState(() {
_pickedImageFile = File(pickedImage.path);
});
widget.onPickedImage(_pickedImageFile!);
}
Widget build(BuildContext context) {
return Column(
children: [
CircleAvatar(
radius: 40,
backgroundColor: Colors.grey,
foregroundImage:
_pickedImageFile != null ? FileImage(_pickedImageFile!) : null,
),
TextButton.icon(
onPressed: _pickImage,
icon: const Icon(Icons.image),
label: Text(
'Add Image',
style: TextStyle(color: Theme.of(context).colorScheme.primary),
),
),
],
);
}
}
CircleAvatar 를 이요해서 background color를 grey로 잡아주면 될 듯 하다. 그리고 foreground image를 주어 이미지 null이 아닐 때 background를 덮어버리면 될 듯 하다.
TextButton.icon() 메서드를 사용해서 Add Image 기능을 구현하면 될 듯 하다.
TextButton의 onPressed 속성값은 ImagePicker와 function을 사용한 drop drilling을 이용하면 될 듯 하다.
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (!_isLogin)
UserImagePicker(
onPickedImage: (pickedImage) {
_selectedImage = pickedImage;
},
),
TextFormField(
...
class _AuthScreenState extends State<AuthScreen> {
final _form = GlobalKey<FormState>();
var _isLogin = true;
var _enteredEmail = '';
var _enteredPassword = '';
File? _selectedImage;
var _isAuthenticating = false;
void _submit() async {
final isValid = _form.currentState!.validate();
if (!isValid || !_isLogin && _selectedImage == null) {
return;
}
_form.currentState!.save();
try {
setState(() {
_isAuthenticating = true;
});
if (_isLogin) {
final userCredentials = await _firebase.signInWithEmailAndPassword(
email: _enteredEmail, password: _enteredPassword);
} else {
final userCredentials = await _firebase.createUserWithEmailAndPassword(
email: _enteredEmail, password: _enteredPassword);
final storageRef = FirebaseStorage.instance
.ref() // <= 여기 ref
.child('user_images')
.child('${userCredentials.user!.uid}.jpg');
await storageRef.putFile(_selectedImage!);
final imageUrl = await storageRef.getDownloadURL();
print(imageUrl);
}
} on FirebaseAuthException catch (e) {
if (e.code == 'email-already-in-use') {
// 실제로는 각 error code 마다 에러 메시지를 작성해주면 좋겠지? 하지만 여기서는 생략!
}
ScaffoldMessenger.of(context).clearSnackBars();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(e.message ?? 'Authentication Fail'),
),
);
setState(() {
_isAuthenticating = false;
});
}
}
Widget build(BuildContext context) {
ref
는 firebase cloud storage의 ref객체이다..child()
매서드는 /
와 같은 개념이다.putFile()
fireBase에 실제로 저장하는 메서드이다.getDownloadURL()
cloud에 저장한 image의 주소를 저장하는 메서드이다.
그럼 일반적인 realtime database와는 무슨 차이인가? => 조금 더 elaborate하고 복잡하다.
그리고 만약 당신이 firebase console에서 fire store를 생성하였는데 혹시 자동을 google cloude console로 안내를 해주지 않는다면 다음과 같은 절차를 따르면 된다.
전환한다.
그리고 해당 firestore 역시 규칙에 request.auth != null로 로그인을 해야만 이용할 수 있도록 규칙을 수정해준다.
하지만 이렇게만 해두면 타 사용자의 chat 내용까지 모두 불러 읽어보기 때문에 여기서는 firebase fire store security rules
를 검색하여 추가적인 규칙을 더 넣어줘야한다.(back-end가 있다면 사실 모두 필요없지만...)
flutter pub add cloud_firestore
DEX 파일은 안드로이드 앱의 실행 가능한 코드와 리소스를 포함하고 있는 파일로, Dalvik 가상 머신이나 ART와 같은 실행 환경에서 사용되어 안드로이드 앱을 실행하는 데 필요한 정보를 담고 있다.
최적화: DEX 파일은 안드로이드 앱의 실행을 최적화하기 위해 최적화된 바이트 코드 형식이다. Dalvik 가상 머신은 DEX 파일을 더 효율적으로 실행할 수 있도록 설계되어 있다.
압축 및 분할: DEX 파일은 압축되어 있으며, 안드로이드 앱이 다양한 디바이스 및 환경에서 실행될 수 있도록 여러 개의 DEX 파일로 분할될 수 있다. 이렇게 분할된 DEX 파일들은 앱의 크기를 최적화하고, 다양한 Android 버전 및 기기에서 호환성을 유지하는데 도움을 준다.
실행: 안드로이드 앱이 실행될 때, DEX 파일은 안드로이드 시스템에 의해 로드되고 실행된다. 앱의 코드와 리소스는 DEX 파일에서 추출되어 실제로 실행되는 프로세스에 사용된다.
ART로의 전환: 안드로이드 5.0 (Lollipop) 버전부터는 Dalvik 가상 머신 대신 ART(Android Runtime)가 사용되며, ART는 AOT(Ahead-Of-Time) 컴파일을 통해 앱을 실행한다. ART는 DEX 파일을 미리 네이티브 기계 코드로 변환하여 실행 속도를 향상시킨다.
await FirebaseFirestore.instance
.collection('users')
.doc('userCredentials.user!.uid')
.set({
'username': _enteredUsername,
'email': _enteredEmail,
'image_url': imageUrl,
});
collection()
으로 콜렉션을 만든다.doc()
메서드로 생성해주고set()
함수로 Map 데이터를 넘겨주면 된다.