0️⃣ 드디어, Jetpack Compose다! Jetpack Compose를 공부하기만을 얼마나 고대해왔는지, 드디어 공부를 시작했다. 대부분의 선언형 UI가 비슷하듯이 Jetpack Compose도 예외는 아니다. 구글 공식 유튜브 강의를 들어 선언형 UI의 개요에 대해서 자세히 공부하고 Jetpack Compose에 대해서도 차차 알아가보겠다. 한글 자막도 잘 되어있으므로 꼭 한 번 시청하면 많은 도움이 될 것이다. 내가 앞으로 쓸 내용은 위 영상을 내가 이해한대로 정리한 요약본이다. 1️⃣ 선언형 UI에 대해서 선언형 UI가 정말로 대세다. Jetpack Compose를 대표해서, Swift UI, React(React Native), Flutter 등 모두 선언형 UI를 사용하고 있다. 기존 ..
Android
⛔ 문제사항 구글 배포를 하려고 aab 파일을 등록해놓고 보니 광고를 사용하지 않음에도 이러한 에러가 나왔다. 분명 우리 Manifest 파일에는 광고 권한을 기재하지 않았는데도 '예'로 응답하라고 한다!✅ 해결방안 Firebase crashlytics를 앱에 연동했거나, analytics를 연동했다면 광고 권한이 자동으로 들어간다고 한다. 우리는 Firebase를 적극적으로 활용한 경우이기 때문에 아무래도 광고 권한이 들어간 모양이다. '예'로 응답하고 아래 체크박스에서 애널리틱스로 체크해준 뒤 심사에 맡기면 된다. ❗출처참고 사이트 : https://minchanyoun.tistory.com/170 [Android] com.google.android.gms.permission.AD_ID 이슈 해결안녕..
⛔ 문제사항 Firebase Google Login을 통해 회원가입하는 로직을 구현했으니 이제는 회원탈퇴를 구현하던 때였다. 회원탈퇴 로직을 모두 만들고 테스트할 땐 잘 되다가 다음날 회원탈퇴 버튼을 누르니 제대로 동작하지 않으며Supplied auth credential is incorrect, malformed or has expired 이와 같은 에러가 발생했다. 나의 단짝친구 Gemini에게도 물어보고 Firebase 공식문서도 참고한 결과, 회원 정보를 삭제하는 것과 같이 민감한 정보를 다룰 때에는 재인증이 필요하다는 것이었다. 로그인 한지 5분이 지나면 이 시간이 경과하여 재인증을 무조건 해야하는 상황이 발생한다.✅ 해결방안우선 재인증 하는 로직을 구현한다.fun reAuthenticateWi..
0️⃣ 리팩토링하는 글이다. Android에서 Firebase Google Login 구현하기0️⃣ Firebase로 Google Login? 사실 많은 앱들에서 소셜 로그인을 지원한다. 나 같은 경우엔 이제 앱에 소셜 로그인 없이 자체 회원가입만 있다면 잘 이용하지 않게 되는 것 같다. 특히, 자체 회원가kkevido.tistory.com 위 게시글에서 이어지는 내용이다. 기본 세팅은 모두 생략하고 코드를 어떻게 리팩토링 하는지 차근차근 작성할 것이다. 우선, 내가 따른 구조는 튜터님께서 손수 짜주신 구조로 팀원들과 함께 응용했다. 근데 너무 어렵다. 아직도 익숙해지지가 않은 것 같지만, 이번 리팩토링을 통해 조금 감을 익혀가는 중이므로 기록을 통해 세세하게 적어보겠다.1️⃣ 기존 SignInActiv..
⛔ 문제사항Firebase Google Login을 연동하던 중의 연장선이다. 힘겹게 Google Login 로직을 다 작성하고 이제 성공하나! 싶었는데 무엇 하나 쉽게 되지 않는다더니 정말로 에러가 발생해버렸다. com.google.android.gms.common.api.ApiException: 10 이런 에러가 발생했는데, 내 소중한 짝꿍 Gemini에게 물어보니 다양한 원인이 있다고 친절하게 설명해줬다. 내가 추측한 문제로는 단연 SHA-1 키의 불일치 문제였다. Firebase Console에서 우리 프로젝트의 SHA 인증서 지문에서는 SHA 키가 2개 등록 되어있었기 때문이다. 밑에 노란색으로 경고 표시가 뜬 SHA-1 키가 내가 구글 로그인을 연동하며 추가한 것이고, 위에 멀쩡한 키는 팀장 ..
0️⃣ Firebase로 Google Login? 사실 많은 앱들에서 소셜 로그인을 지원한다. 나 같은 경우엔 이제 앱에 소셜 로그인 없이 자체 회원가입만 있다면 잘 이용하지 않게 되는 것 같다. 특히, 자체 회원가입을 하더라도 소셜 계정 연동이 없다면 더더욱! 그만큼 소셜 로그인이 앱의 필수 기능으로 자리잡은 만큼 꼭 구현해보고 싶었던 기능이다. (그동안 소셜 로그인을 한 번도 연동해본 적이 없다는 것이 더욱 충격적) 이번 프로젝트에서는 서버 없이 FireStore로만 작업했기 때문에 Firebase Google Login 구현이라고 보면 된다. 차근차근 해보자. 1️⃣ Firebase Setting먼저 Firebase 세팅을 해주면 된다. 우리 팀의 리더 친구가 세팅 해주었다! 하지만 세팅 자체가 어..
0️⃣ Context를 사용 못 해Singleton 패턴에서는 context를 사용할 수가 없다.생명 주기 불일치단위 테스트의 어려움의존성 주입 어려움대표적으로 이러한 이유가 있지만 그럼에도 Context가 필요한 상황은 반드시 온다.더군다나, 나는 Hilt로 DI를 구성해놓은 코드였기 때문에 context를 불러와야할지 잘 몰랐었지만 오히려 Hilt를 사용하고 있어서 Context를 사용하기 더 쉬웠다.@Module@InstallIn(SingletonComponent::class)object YoutubeApiModule { private const val cacheSize = 100 * 1024 * 1024 // 100 MB private const val YOUTUBE_BASE_URL =..
0️⃣ CustomDialog!사실 Dialog를 띄워 화면에 알림을 주는 일은 이제는 도저히 뺄 수 없는 필수 기능이다. 할 줄 안다고 생각했는데도 막상 다시 하니 또 버벅거리며 한참을 헤매서 세세하게 기록해보려고 한다.1️⃣ dialog.xml 핵심 포인트는 가장 최상단 부모 태그의 width, height값을 match_parent로 주는 것이다.2️⃣ DialogFragmentclass TwoButtonDialogFragment( private val title: String, private val onClickConfirm: () -> Unit) : DialogFragment() { ..
⛔ 문제사항 여행 채널 추천 카테고리를 보면 5개 밖에 출력되지 않은 현상을 볼 수 있다. 내가 의도한 것은 총 6개의 채널이 추천되며 그리드뷰가 꽉 채워지는 것이었는데 다른 화면을 이동하거나, 앱을 재실행하여 해당 Fragment가 다시 그려질 때마다 채널이 2개부터 6개까지 그려지는 개수가 그때그때 다르다는 것이었다. 그러나 아래 스크린샷과 같이 로그캣을 찍어보면 itemList의 총 개수는 6개로 잘 넘어오는 것을 알 수 있었다. 당시 코드다. channelList는 LiveData로 관리하고 있고, channel을 가져오는 api는 async await을 통해 비동기적으로 받아오고 있었다.class HomeViewModel( private val channelRepository: Chann..
0️⃣ 4대 구성요소?안드로이드 앱의 필수 구성요소를 흔히들 4대 컴포넌트라고 부르는데, 각 구성요소는 시스템이나 사용자가 앱에 들어올 수 있는 진입점이다.액티비티서비스브로드캐스트 수신자콘텐츠 제공자이렇게 총 4가지의 구성요소로 이루어져있으며, 각 구성요소는 독립적으로 존재하여 생명주기를 가지고 있기 때문에 고유의 기능을 수행할 수 있으며, 인텐트를 통해 서로 상호작용할 수 있다.1️⃣ Activity (액티비티)액티비티는 사용자 인터페이스를 나타내는 단일 화면으로 주로 사용자와의 상호작용을 담당한다.class MainActivity : AppCompatActivity() {}2️⃣ Service (서비스)서비스는 백그라운드에서 실행되는 구성요소로 앱이 종료되어도 백그라운드에서 처리되는 기능들을 말한다..
⛔ 문제사항RecyclerView로 표현하고 있던 Item들 중에서 하나를 remove 하는 로직을 동작하자 이러한 에러가 나타났다.✅ 해결방안이는 Apapter에서 관리하는 데이터와 ViewHolder게 그리는 View가 일치하지 않아 발생하는 문제다.그냥 notifyDataSetChanged() 해주면 쉽게 해결되는 문제였다! 하지만 구글링을 좀 더 하다보면 스크롤을 빠르게 내린다거나 둥, 스크롤 관련된 문제로 많이 나타나는 것처럼 보였는데 대부분 LinearLayoutManager를 Wrapper로 감싸주는 방법을 많이 사용했다. 나 같은 경우엔 단순히 데이터가 바뀌었다고 notify 해주기만 하면 됐기 때문에 손쉽게 해결할 수 있었다.
0️⃣ 왜? 사실 Fragment, TabLayout, RecyclerView는 뗄레야 뗄 수 없는 존재다. 정말 많은 앱에서 이러한 구조로 구현하고 있을테니 이 기회에 확실하게 복습하고 넘어가면 좋다. ViewPager도 함께 쓰면 좋겠지만 우선은 제외하고 설명하겠다. 다른 좋은 포스팅들도 많으니 꼭 함께 참고할 것.1️⃣ MainActivityFragment와 TabLayout 같이 사용하는 핵심 부분! XML 파일은 생략하겠다.class MainActivity : AppCompatActivity() { private val binding: ActivityMainBinding by lazy { ActivityMainBinding.inflate(layoutInflater) } private ..