Skip to content

✏️ 기술 블로그

JunJangE edited this page Apr 2, 2024 · 21 revisions

조준장 기술 블로그

Android View에서 Jetpack Compose로 마이그레이션 해보자!

Android View에서 Jetpack Compose로 마이그레이션 해보자!

이전에 개발한 행운복권 앱은 Android View를 사용하여 UI를 개발했다. 그러나 UI 개발을 더 쉽게 하고 코드의 가독성과 유지보수성을 향상시키기 위해 Jetpack Compose로의 마이그레이션을 진행하게 되었다.

Android View

image

로또 볼을 Android View를 사용하여 구현할 때는 여러 개의 XML 파일을 만들어야 했고, 각각의 색상이 다른 경우에는 그만큼 파일을 추가해야 했다. 또한, View를 재사용하기 위해서는 필요에 따라 속성 값 변경이 필요한 번거로움이 있었다.

Jetpack Compose

@Composable
fun LottoBall(
    lottoType: LottoType,
    lottoColor: Color,
    lottoTitle: String,
) {
    Surface(
        modifier = Modifier.size(30.dp),
        border = if (lottoType == LottoType.LOTTO720) BorderStroke(
            width = 4.dp,
            color = lottoColor
        ) else null,
        shape = CircleShape
    ) {
        Box(
            modifier = Modifier
                .fillMaxSize()
                .background(color = if (lottoType == LottoType.LOTTO720) LottoTheme.colors.white else lottoColor)
        ) {
            Text(
                modifier = Modifier.align(Alignment.Center),
                text = lottoTitle,
                textAlign = TextAlign.Center,
                style = LottoTheme.typography.body3.copy(
                    fontWeight = FontWeight.Bold,
                    color = if (lottoType == LottoType.LOTTO720) LottoTheme.colors.black else LottoTheme.colors.white
                ),
            )
        }
    }
}

위처럼 Compose를 통해 UI를 Kotlin 코드로 구현함으로써, 한 두 줄의 코드 변경으로 다양한 UI를 손쉽게 만들 수 있다. XML 파일의 추가 없이 코드 작성이 가능하므로 불필요한 번거로움이 없어져 구현이 간편해졌다. 따라서 위 코드를 활용하여 모든 로또 볼을 만들 수 있다.

이처럼 UI 개발을 더 쉽게 하고 코드의 가독성과 유지보수성을 향상시키기 위해 Jetpack Compose로의 마이그레이션을 진행하게 되었다. 이로써 앱의 디자인, 상태 관리, 이벤트 핸들링 등을 개선하여 더 나은 사용자 경험을 제공할 수 있게 되었다. Jetpack Compose는 XML을 사용하지 않고 Kotlin 기반의 DSL을 활용하여 선언적으로 UI를 정의하는데, 이러한 변경을 통해 더 직관적이고 간결한 코드를 통해 효율적이고 풍부한 UI를 구현할 수 있다.

모듈화를 해보자!

모듈화를 해보자!

행운복권 앱은 Clean Architecture를 지향하여 의존 관계를 용이하게 관리하고 비즈니스 로직을 외부 프레임워크 및 라이브러리와 분리하기 위해 멀티 모듈을 도입했다. 전체 구조는 다음과 같이 총 8개의 모듈로 구성되어 있다.

  • app: 사용자 인터페이스 및 앱의 실행 흐름을 담당하는 모듈
  • presentation: UI 레이어에서 사용되는 비즈니스 로직과 관련된 코드를 포함하는 모듈
  • domain: 비즈니스 로직 및 도메인 모델을 정의하는 모듈
  • data: 데이터 소스와의 상호 작용을 처리하며, 데이터를 가져오고 저장하는 데 사용되는 모듈
  • bridSrc: 여러 플랫폼 간에 코드를 공유하기 위한 모듈
  • core-feature: 핵심 기능에 해당하는 모듈(OCR)
  • kakao: 카카오 관련 기능을 제공하는 모듈(kakao login)
  • firebase: Firebase와 관련된 기능을 제공하는 모듈(fcm)

┌───────────────────────────────────────────────────────────────────┐
|                               app                                 |
├───────────────────────────────────────────────────────────────────┤   
|                               buildSrc                            |
|===================================================================|   
|                               data                                |
├───────────────────────────────────────────────────────────────────┤
|     local     |     remote     |     firebase     |     kakao     |                    
├───────────────────────────────────────────────────────────────────┤
|                               domain                              | 
├───────────────────────────────────────────────────────────────────┤   
|                               presentation                        |
├───────────────────────────────────────────────────────────────────┤
|                               core-feature                        |
└───────────────────────────────────────────────────────────────────┘

프로젝트 내에서 비즈니스 로직을 수행하는 부분은 주로 도메인 레이어에 위치하며, 데이터는 local, remote, firebase, kakao 등 모듈을 통해 획득된다. 간단히 말하면, 데이터는 데이터 레이어에서 관리되고, 해당 데이터는 도메인 레이어에서 정의된 비즈니스 로직에 활용된다.

이러한 멀티 모듈 구조를 통해 각 모듈은 자체적인 역할에 집중하면서도 필요한 경우 의존성을 명시적으로 관리할 수 있게 되었다.

OCR를 적용해보자!
토큰을 재발급 받아봐요!

토큰을 재발급 받아봐요!

이전부터 JWT를 사용하여 서버와의 사용자 인증을 수행하고 API 호출을 진행했다. 그러나 Access Token이나 Refresh Token이 만료되었을 때의 예외처리는 진행한 경험이 없었고, 매번 프로젝트를 진행할 때마다 아쉬움이 남았었기 때문에 이번 프로젝트에서는 Token Refresh를 제데로 진행하였다.

토큰은 Local 모듈에서 SharedPreferences를 통해 관리했고 Data 모듈을 통해 접근할 수 있게 구현했다. 실질적으로 Token을 사용해야하는 Remote 모듈에서, Data 모듈을 통해 토큰을 가져와 사용할 수 있도록 구현했다.

그렇다면 토큰 에러가 발생하는 것을 어떻게 알고 토큰일 갱신 시켜줘야 할까???

Remote 모듈을 보게되면 Retrofit을 통해 서버와 통신을 진행하고, OkHttp의 Intercepter에서 authenticator가 인증이 필요한 HTTP 요청에 대한 인증을 담당하게 된다. 토큰 인증 에러가 발생하면 authenticator의 authenticate 메서드가 실행된다. authenticate 메서드 안에서는 Refresh Token을 통해 Refresh API를 호출하여 새로운 토큰을 요청하고, 토큰 갱신에 성공하면 다시 시도하던 요청에 새로운 토큰을 적용하여 다시 시도한다. 만약 Refresh Token이 SharedPreferences에 없거나 만료되었다면 authenticationListener의 onSessionExpired()를 실행시켜 App 모듈에서 로그인 페이지로 이동하고 사용자에게 다시 로그인할 수 있도록 유도한다.

이렇게 토큰 에러가 발생하면 토큰을 갱신하고 관련된 동작을 수행하여 사용자 경험을 향상시켜보았습니다.

OO까지 예외처리를 했어요!
회원 탈퇴를 못한다니?! 그럴 수는 없지!!

https://velog.io/@tkdwns0301/Kotlin-Google-AccessToken-%EB%B0%9C%EA%B8%89%EB%B0%9B%EA%B8%B0 https://velog.io/@chanu2/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B6%80%ED%8A%B8-%EC%86%8C%EC%85%9C-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EC%97%B0%EA%B2%B0-%EB%81%8A%EA%B8%B0-%ED%9A%8C%EC%9B%90%ED%83%88%ED%87%B4-%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84 https://velog.io/@mraz3068/Android-Google-Login-Access-%ED%86%A0%ED%81%B0-%EC%96%BB%EB%8A%94-%EB%B0%A9%EB%B2%95%EC%9D%84-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90