`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..
[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] 탭 이동해도 상..
2주간 20명 대상 비공개 테스트 진행2023년 11월 13일 이후에 만든 개인 계정을 사용하는 개발자는 앱을 테스트해야 Google Play에 앱을 배포할 수 있습니다. 개발자는 이 요구사항을 충족할 때까지 Play Console의 특정 기능(예: 프로덕션(출시 > 프로덕션), 사전 등록(출시 > 테스트 > 사전 등록)을 사용할 수 없습니다. 새로운 개인 개발자 계정의 앱 테스트 요구사항구글 플레이 스토어에 조직이 아닌 개인 계정으로 앱을 출시하기 위해서는 반드시 비공개 테스트 과정을 거쳐야 한다. 비공개 테스트는 사전에 이메일을 등록한 사용자들만 앱을 다운 받아서 테스트해 볼 수 있다. 새로 만든 개인 개발자 계정이 있는 경우 최근 14일 이상 지속적으로 테스트에 참여하겠다고 선택한 상태인 20명 이..
수정 전수정 후수정 전의 앱은 각각의 탭에 들어갈 때마다 로딩 스피너가 돌아가면서 API 콜을 해서 데이터를 새로 불러왔다.하지만 교정일기 앱은 사용자가 데이터를 추가하는 경우가 아니라면 업데이트할 필요가 전혀 없다.따라서 불필요한 네트워크 통신을 줄이고, 더 빠른 사용자 경험을 제공하기 위해 최초 1회만 데이터를 불러오고, 그 이후에는 탭을 이동해도 기존에 불러온 데이터를 유지해서 보여주고 싶었다. 위젯의 상태 유지하기 AutomaticKeepAliveClientMixin플러터에서는 기본적으로 탭을 이동하면 보이지 않는 탭의 상태가 `dispose` 되어 메모리에서 제거된다.하지만 ` AutomaticKeepAliveClientMixin`을 사용하면 탭을 이동하더라도 위젯이 보존되며 상태를 유지할 수 ..