`print()`로 로그를 출력하면 다음과 같은 경고 메세지가 뜬다. 지금까지는 이 메세지를 그냥 무시해 왔는데 앱을 배포하기 위해서는 릴리즈 모드에서 로그가 출력되지 않도록 할 필요성을 느꼈다. 프로덕션 코드에서는 print() 호출을 피해라DO avoid `print` calls in production code.For production code, consider using a logging framework. If you are using Flutter, you can use `debugPrint` or surround `print` calls with a check for `kDebugMode`다트 공식문서에서 프로덕션 코드에서는 `print()`를 피하라는 경고와 함께, 로그를 출력할 다른 방..
앱 실행 중에 마지막 스택에서 뒤로 가기 버튼을 누르면 "뒤로 가기를 한 번 더 누르시면 종료됩니다"라는 내용의 스낵바가 뜨는 기능을 구현해 보자. PopSope 위젯 추가하기DateTime? backPressedTime;@overrideWidget build(BuildContext context) { return PopScope( canPop: false, onPopInvoked: (bool didPop) { if (didPop) { return; } DateTime nowTime = DateTime.now(); if (backPressedTime == null || nowTime.differ..
프로덕션 앱 심사 거절무려 3번의 리젝 끝에 드디어 정식으로 앱이 출시되었다.플레이스토어 심사 거절 사례와 해결 방법을 공유한다. 한 번 게시 검토를 신청하면 답변까지 보통 4일이 걸린다.나는 첫 게시 신청을 한 게 11월 15일이었고, 세 번의 리젝 끝에 프로덕션 앱이 출시된 게 11월 24일이었다. 리젝 사유는 이메일로 받기도 하고, 구글 플레이 콘솔 `정책 상태` 항목에서도 확인할 수 있다.리젝 사유는 인앱 경험 스크린샷까지 첨부해서 친절하게 알려주는 편이다. 첫 번째 리젝: 혼동을 야기하는 주장 정책 위반2024년 11월 15일 밤 11시에 처음으로 프로덕션 게시 신청을 했는데2024년 11월 19일 오전 9시에 리젝 메일을 받았다. 앱에 혼동을 야기하는 주장 관련 정책을 준수하지 않는 콘텐츠가..
[Flutter] S3 버킷에 업로드한 파일 삭제하기단일 객체 삭제 방법은 상단의 글을 참고하고, 이번에는 여러 객체를 한 번에 삭제하는 방법을 알아보자. Lambda 함수 생성import { S3Client, DeleteObjectsCommand } from "@aws-sdk/client-s3";const s3Client = new S3Client({ region: 'ap-northeast-2' });export const handler = async (event) => { // body에 JSON.parse 하면 에러 발생함 const { objectKeys } = event.body; if (!objectKeys) { return { statusCod..
화면을 아래로 당겨서 새로고침하는 기능을 구현해 보자. RefreshIndicatorreturn Scaffold( appBar: AppBar( title: const Text('교정 타임라인'), ), body: RefreshIndicator( onRefresh: () async { timelineController.refreshTimelineData(); }, child: const Column(), ),);`Scaffold`의 `body`의 최상위에 `RefreshIndecator` 위젯을 추가하고, `onRefresh`에 새로고침 했을 때 실행되길 원하는 코드를 추가한다. RefreshIndicator와 RefreshIndicator.adaptive의 차이점Re..
플러터에서 S3에 올린 오브젝트를 삭제하는 방법을 소개한다. [Flutter] S3 Presigned URL 발급받기 | AWS Lambda & API GatewayAWS Lambda랑 API Gateway를 설정하는 자세한 절차에 대해서는 이미 게시물을 올렸기 때문에 이번 글에서는 코드 위주로 간단하게 설명한다. Lambda 함수 생성import { DeleteObjectCommand, S3Client } from "@aws-sdk/client-s3";const s3Client = new S3Client({ region: 'ap-northeast-2' });export const handler = async (event) => { const bucketName = "YOUR_BUCKET_NAME"..
[Flutter] S3 Presigned URL 발급받기 | AWS Lambda & API GatewayPresigned URL을 발급 반는 과정은 이전 게시글에서 확인할 수 있다. 이제 Presigned URL을 사용해서 최종적으로 S3 버킷에 이미지를 업로드해 보자! image_picker로 이미지 선택하기final ImagePicker picker = ImagePicker(); // ImagePicker 초기화XFile? image; // 사용자가 선택한 이미지String contentType = ''; // 이미지 파일의 타입bool isImageUpdated = false; // 이미지 업로드 여부Future getImage(ImageSource imageSource) async { final..
플러터에서 Amazon S3 버킷에 이미지 업로드하는 기능 구현하기현재 진행 중인 개인 프로젝트에서 BaaS로 슈퍼베이스를 사용하고 있는데 Storage의 경우에는 무료로 제공하는 용량이 너무 적었다. 그래서 요금이 비교적 저렴한 Amazon S3에 이미지를 업로드하고, 이미지 URL을 얻어서 슈퍼베이스의 데이터베이스에 저장하는 방법을 선택했다. 처음에는 Amazon S3 관련 플러터 패키지를 사용할 계획이었는데 관련 패키지들은 업데이트가 몇 년 전으로 너무 오래돼서 지금도 정상적으로 작동할지 걱정이 되었다. 그래서 검색하다가 알게 된 게 AWS Amplify였다. AWS Amplify도 파이어베이스나 슈퍼베이스 같이 Auth, Database, Storage 등의 풀스택 개발을 제공하는 서비스이다. 처..
API 호출 최적화에 대한 고민기존에는 탭에 들어갈 때마다 `initState()`에서 api를 호출해서 데이터를 가져오는 구조였다.그래서 탭에 들어갈 때마다 로딩스피너가 돌아가다가 데이터가 뜨는 것을 볼 수 있다. 그런데 교정일기 앱은 사용자가 데이터를 추가하는 경우가 아니면 데이터를 업데이트할 필요가 없기 때문에불필요한 api 호출을 줄이기 위해 리팩토링을 진행했다. 일단 `AutomaticKeepAliveClientMixin`을 적용해서 탭을 이동해도 상태가 그대로 유지되도록 했다.최초 1회만 데이터를 받으면 탭을 이동해도 상태가 그대로 유지되기 때문에 무한대로 api를 호출하던 횟수를 홈 탭 2회 + 타임라인 탭 1회 + 앨범 탭 1회, 총 4회로 줄일 수 있었다.[Flutter] 탭 이동해도 상..
구글플레이에서 개인 개발자가 앱을 출시하기 위해서 꼭 거쳐야 하는 비공개 테스트 앱 심사를 통과하고 정식 앱 출시 권한을 얻었다! 비공개 테스트 앱 출시비공개 테스트 앱을 출시하는 데도 심사가 필요한데 정식 앱 출시보다는 깐깐하지 않은지 나는 한 번에 통과됐다. 2024년 10월 24일 오전 1시에 검토 신청을 보내고,2024년 10월 26일 저녁 7시에 앱 게시가 완료되었다. 20명의 테스터를 모집하기 위해서는 개발자 품앗이 카페를 이용했다. 카페에 테스터 모집글을 올리면 댓글로 이메일을 교환해서 서로 테스터로 등록하고, 앱을 설치했다는 인증샷을 업로드한다. 나는 총 37명의 테스터를 모집했는데 제대로 카운트가 안 되는 것인지 아니면 테스터들이 앱을 설치 후 삭제했기 때문인지 14일 기간의 마지막 날..