1. 소개
최종 업데이트: 2022년 11월 16일
Firebase와 Jetpack Compose를 사용하여 Android 앱 빌드
이 Codelab에서는 Make It So라는 Android 앱을 빌드합니다. 이 앱의 UI는 네이티브 UI를 빌드하기 위한 Android의 최신 툴킷인 Jetpack Compose로 완전히 빌드되었습니다. 직관적이며 .xml 파일을 작성하여 활동, 프래그먼트 또는 뷰에 바인딩하는 것보다 코드가 더 적습니다.
Firebase와 Jetpack Compose가 함께 잘 작동하는지 이해하기 위한 첫 번째 단계는 최신 Android 아키텍처를 이해하는 것입니다. 좋은 아키텍처는 구성요소가 어떻게 구성되고 서로 통신하는지 명확하게 보여주므로 시스템을 쉽게 이해하고 개발하고 유지할 수 있습니다. Android 환경에서 권장되는 아키텍처는 Model - View - ViewModel입니다. 모델은 애플리케이션에서 데이터에 액세스하는 레이어를 나타냅니다. 뷰는 UI 레이어이며 비즈니스 로직에 관해 아무것도 알면 안 됩니다. ViewModel은 비즈니스 로직이 적용되는 곳이며, 때로는 ViewModel이 Model 레이어를 호출해야 합니다.
이 도움말을 읽고 Model - View - ViewModel이 Jetpack Compose로 빌드된 Android 앱에 적용되는 방식을 알아보세요. 그러면 코드베이스를 더 쉽게 이해하고 다음 단계를 더 쉽게 완료할 수 있습니다.
빌드할 항목
Make It So는 사용자가 할 일을 추가 및 수정하고, 플래그, 우선순위, 마감일을 추가하고, 할 일을 완료로 표시할 수 있는 간단한 할 일 목록 애플리케이션입니다. 아래 이미지는 이 애플리케이션의 두 가지 기본 페이지, 즉 작업 만들기 페이지와 생성된 작업 목록이 있는 기본 페이지를 보여줍니다.
이 앱에 없는 몇 가지 기능을 추가합니다.
- 이메일 및 비밀번호로 사용자 인증
- Firestore 컬렉션에 리스너를 추가하고 UI가 변경사항에 반응하도록 설정
- 커스텀 trace를 추가하여 앱에서 특정 코드의 성능 모니터링
- 원격 구성을 사용하여 기능 전환 버튼을 만들고 단계적 출시를 사용하여 기능 전환 실행
학습 내용
- 최신 Android 애플리케이션에서 Firebase 인증, Performance Monitoring, 원격 구성, Cloud Firestore를 사용하는 방법
- Firebase API를 MVVM 아키텍처에 맞게 조정하는 방법
- Compose UI에서 Firebase API로 변경한 사항을 반영하는 방법
필요한 사항
- Android 스튜디오 Flamingo+
- API 21 이상을 실행하는 Android Emulator
- Kotlin 프로그래밍 언어에 관한 지식
2. 샘플 앱 가져오기 및 Firebase 설정
샘플 앱의 코드 가져오기
명령줄에서 GitHub 저장소를 클론합니다.
git clone https://github.com/FirebaseExtended/make-it-so-android.git
Firebase 프로젝트 만들기
먼저 Firebase Console로 이동하여 '+ 프로젝트 추가' 버튼을 클릭하여 Firebase 프로젝트를 만듭니다(아래 참고).
화면의 단계에 따라 프로젝트 만들기를 완료합니다.
Firebase 프로젝트에 Android 앱 추가
Firebase 프로젝트에서 Android, iOS, 웹, Flutter, Unity용으로 다양한 앱을 등록할 수 있습니다.
다음과 같이 Android 옵션을 선택합니다.
이어서 다음 단계를 수행합니다.
- 패키지 이름으로
com.example.makeitso
를 입력하고 원하는 경우 닉네임을 입력합니다. 이 Codelab에서는 디버그 서명 인증서를 추가할 필요가 없습니다. - 다음을 클릭하여 앱을 등록하고 Firebase 구성 파일에 액세스합니다.
- google-services.json 다운로드를 클릭하여 구성 파일을 다운로드하고
make-it-so-android/app
디렉터리에 저장합니다. - 다음을 클릭합니다. Firebase SDK가 이미 샘플 프로젝트의
build.gradle
파일에 포함되어 있으므로 Next를 클릭하여 다음 단계로 건너뜁니다. - 콘솔로 이동을 클릭하여 완료합니다.
Make it So 앱이 제대로 작동하도록 하려면 코드로 이동하기 전에 콘솔에서 인증 제공업체를 사용 설정하고 Firestore 데이터베이스를 만드는 두 가지 작업을 수행해야 합니다.
인증 설정
먼저 사용자가 앱에 로그인할 수 있도록 인증을 사용 설정해 보겠습니다.
- Build(빌드) 메뉴에서 Authentication(인증)을 선택한 다음 Get Started(시작하기)를 클릭합니다.
- 로그인 방법 카드에서 이메일/비밀번호를 선택하여 사용 설정합니다.
- 그런 다음 새 제공업체 추가를 클릭하고 익명을 선택하여 사용 설정합니다.
Cloud Firestore 설정
그런 다음 Firestore를 설정합니다. Firestore를 사용하여 로그인한 사용자의 할 일을 저장합니다. 각 사용자는 데이터베이스의 컬렉션 내에서 자체 문서를 가져옵니다.
- Firebase Console의 왼쪽 패널에서 빌드를 펼친 다음 Firestore 데이터베이스를 선택합니다.
- 데이터베이스 만들기를 클릭합니다.
- 데이터베이스 ID는
(default)
로 설정된 채로 둡니다. - 데이터베이스의 위치를 선택한 다음 다음을 클릭합니다.
실제 앱의 경우 사용자와 가까운 위치를 선택해야 합니다. - 테스트 모드로 시작을 클릭합니다. 보안 규칙에 관한 면책 조항을 읽어봅니다.
이 섹션의 다음 단계에서는 데이터 보안을 위해 보안 규칙을 추가합니다. 데이터베이스에 대한 보안 규칙을 추가하지 않은 채 앱을 공개적으로 배포하거나 노출하지 마세요. - 만들기를 클릭합니다.
잠시 시간을 내어 Firestore 데이터베이스에 강력한 보안 규칙을 빌드해 보겠습니다.
- Firestore 대시보드를 열고 규칙 탭으로 이동합니다.
- 보안 규칙을 다음과 같이 업데이트합니다.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow create: if request.auth != null;
allow read, update, delete: if request.auth != null && resource.data.userId == request.auth.uid;
}
}
}
이 규칙은 기본적으로 앱의 로그인한 모든 사용자가 컬렉션 내에서 문서를 만들 수 있음을 나타냅니다. 그런 다음 문서가 생성되면 해당 문서를 만든 사용자만 해당 문서를 보고, 업데이트하거나, 삭제할 수 있습니다.
애플리케이션 실행
이제 애플리케이션을 실행할 준비가 되었습니다. Android 스튜디오에서 make-it-so-android/start
폴더를 열고 앱을 실행합니다 (Android Emulator 또는 실제 Android 기기를 사용하여 실행할 수 있음).
3. Firebase 인증
어떤 기능을 추가할 예정인가요?
현재 Make It So 샘플 앱에서는 사용자가 먼저 로그인하지 않고도 앱을 사용할 수 있습니다. 이를 위해 익명 인증을 사용합니다. 하지만 익명 계정을 사용하면 사용자가 다른 기기나 이후 세션에서도 자신의 데이터에 액세스할 수 없습니다. 익명 인증은 웜 온보딩 시 유용하지만 항상 사용자가 다른 로그인 형식으로 전환할 수 있는 옵션을 제공해야 합니다. 이를 염두에 두고 이 Codelab에서는 Make It So 앱에 이메일 및 비밀번호 인증을 추가합니다.
이제 코딩할 시간입니다.
사용자가 이메일과 비밀번호를 입력하여 계정을 만들면 Firebase 인증 API에 이메일 사용자 인증 정보를 요청한 다음 새 사용자 인증 정보를 익명 계정에 연결해야 합니다. Android 스튜디오에서 AccountServiceImpl.kt
파일을 열고 다음과 같이 linkAccount
함수를 업데이트합니다.
model/service/impl/AccountServiceImpl.kt
override suspend fun linkAccount(email: String, password: String) {
val credential = EmailAuthProvider.getCredential(email, password)
auth.currentUser!!.linkWithCredential(credential).await()
}
이제 SignUpViewModel.kt
를 열고 onSignUpClick
함수의 launchCatching
블록 내에서 서비스 linkAccount
함수를 호출합니다.
screens/sign_up/SignUpViewModel.kt
launchCatching {
accountService.linkAccount(email, password)
openAndPopUp(SETTINGS_SCREEN, SIGN_UP_SCREEN)
}
먼저 인증을 시도하고 호출이 성공하면 다음 화면 (SettingsScreen
)으로 이동합니다. launchCatching
블록 내에서 이러한 호출을 실행할 때 첫 번째 줄에서 오류가 발생하면 예외가 포착되어 처리되고 두 번째 줄에는 전혀 도달하지 않습니다.
SettingsScreen
가 다시 열리면 사용자는 이미 인증되었으므로 로그인 및 계정 만들기 옵션이 사라졌는지 확인해야 합니다. 이렇게 하려면 SettingsViewModel
가 현재 사용자의 상태(AccountService.kt
에서 사용 가능)를 리슨하여 계정이 익명인지 아닌지 확인하도록 하겠습니다. 이렇게 하려면 SettingsViewModel.kt
의 uiState
를 다음과 같이 업데이트합니다.
screens/settings/SettingsViewModel.kt
val uiState = accountService.currentUser.map {
SettingsUiState(it.isAnonymous)
}
마지막으로 해야 할 일은 SettingsViewModel
에서 내보낸 상태를 수집하도록 SettingsScreen.kt
의 uiState
를 업데이트하는 것입니다.
screens/settings/SettingsScreen.kt
val uiState by viewModel.uiState.collectAsState(
initial = SettingsUiState(false)
)
이제 사용자가 변경될 때마다 SettingsScreen
가 자체적으로 재구성되어 사용자의 새 인증 상태에 따라 옵션을 표시합니다.
테스트할 시간입니다
Make it So를 실행하고 화면 오른쪽 상단의 톱니바퀴 아이콘을 클릭하여 설정으로 이동합니다. 여기에서 계정 만들기 옵션을 클릭합니다.
유효한 이메일과 강력한 비밀번호를 입력하여 계정을 만듭니다. 설정이 완료되면 설정 페이지로 리디렉션되며, 여기에 로그아웃과 계정 삭제라는 두 가지 새로운 옵션이 표시됩니다. Firebase Console의 인증 대시보드에서 사용자 탭을 클릭하여 생성된 새 계정을 확인할 수 있습니다.
4. Cloud Firestore
어떤 기능을 추가하려고 하나요?
Cloud Firestore의 경우 Make it So에 표시된 작업을 나타내는 문서를 저장하는 Firestore 컬렉션에 리스너를 추가합니다. 이 리스너를 추가하면 이 컬렉션에 대한 모든 업데이트를 받게 됩니다.
코딩할 시간입니다.
StorageServiceImpl.kt
에서 사용 가능한 Flow
를 다음과 같이 업데이트합니다.
model/service/impl/StorageServiceImpl.kt
override val tasks: Flow<List<Task>>
get() =
auth.currentUser.flatMapLatest { user ->
firestore.collection(TASK_COLLECTION).whereEqualTo(USER_ID_FIELD, user.id).dataObjects()
}
이 코드는 user.id
에 따라 작업 컬렉션에 리스너를 추가합니다. 각 작업은 tasks
라는 컬렉션의 문서로 표현되며 각 작업에는 userId
라는 필드가 있습니다. currentUser
의 상태가 변경되면 (예: 로그아웃) 새 Flow
가 내보내집니다.
이제 TasksViewModel.kt
의 Flow
가 서비스에서와 동일하게 반영되도록 해야 합니다.
screens/tasks/TasksViewModel.kt
val tasks = storageService.tasks
마지막으로 UI를 나타내는 TasksScreens.kt
의 composable function
가 이 흐름을 인식하고 상태로 수집하도록 합니다. 상태가 변경될 때마다 구성 가능한 함수는 자동으로 재구성되어 사용자에게 최신 상태를 표시합니다. 다음을 TasksScreen composable function
에 추가합니다.
screens/tasks/TasksScreen.kt
val tasks = viewModel
.tasks
.collectAsStateWithLifecycle(emptyList())
구성 가능한 함수가 이러한 상태에 액세스할 수 있게 되면 LazyColumn
(화면에 목록을 표시하는 데 사용하는 구조체)를 다음과 같이 업데이트할 수 있습니다.
screens/tasks/TasksScreen.kt
LazyColumn {
items(tasks.value, key = { it.id }) { taskItem ->
TaskItem( [...] )
}
}
테스트할 시간입니다
제대로 작동하는지 테스트하려면 앱을 사용하여 새 작업을 추가합니다 (화면 오른쪽 하단의 추가 버튼 클릭). 작업 만들기를 완료하면 Firestore Console의 Firestore 컬렉션에 작업이 표시됩니다. 다른 기기에서 동일한 계정으로 Make it So에 로그인하면 할 일 항목을 수정하고 모든 기기에서 실시간으로 업데이트되는 것을 볼 수 있습니다.
5. Performance Monitoring
어떤 기능을 추가할 예정인가요?
성능이 매우 나쁘고 간단한 작업을 완료하는 데 시간이 너무 오래 걸리는 사용자는 앱 사용을 포기할 가능성이 매우 높기 때문에 성능에는 주의를 기울여야 합니다. 따라서 사용자가 앱에서 수행하는 특정 여정에 대한 몇 가지 측정항목을 수집하는 것이 유용한 경우도 있습니다. 이를 지원하기 위해 Firebase Performance Monitoring에서 커스텀 trace를 제공합니다. 다음 단계에 따라 Make it So에서 커스텀 트레이스를 추가하고 여러 코드의 성능을 측정합니다.
코딩할 시간입니다.
Performance.kt
파일을 열면 trace라는 인라인 함수가 표시됩니다. 이 함수는 Performance Monitoring API를 호출하여 커스텀 trace를 만들고 trace 이름을 매개변수로 전달합니다. 표시되는 다른 매개변수는 모니터링하려는 코드 블록입니다. 각 trace에 대해 수집되는 기본 측정항목은 완전히 실행되는 데 걸리는 시간입니다.
model/service/Performance.kt
inline fun <T> trace(name: String, block: Trace.() -> T): T = Trace.create(name).trace(block)
측정하는 데 중요하다고 생각되는 코드베이스의 부분을 선택하고 여기에 맞춤 트레이스를 추가할 수 있습니다. 다음은 이 Codelab의 앞부분 (AccountServiceImpl.kt
)에서 본 linkAccount
함수에 맞춤 트레이스를 추가하는 예입니다.
model/service/impl/AccountServiceImpl.kt
override suspend fun linkAccount(email: String, password: String): Unit =
trace(LINK_ACCOUNT_TRACE) {
val credential = EmailAuthProvider.getCredential(email, password)
auth.currentUser!!.linkWithCredential(credential).await()
}
이제 여러분의 차례입니다. Make it So 앱에 맞춤 트레이스를 추가하고 다음 섹션으로 이동하여 예상대로 작동하는지 테스트합니다.
테스트할 시간입니다.
커스텀 trace 추가를 완료한 후 앱을 실행하고 측정하려는 기능을 몇 번 사용해야 합니다. 그런 다음 Firebase Console에서 성능 대시보드로 이동합니다. 화면 하단에는 네트워크 요청, 맞춤 트레이스, 화면 렌더링이라는 세 가지 탭이 있습니다.
커스텀 trace 탭으로 이동하여 코드베이스에 추가한 trace가 표시되고 이러한 코드를 실행하는 데 일반적으로 걸리는 시간을 확인할 수 있는지 확인합니다.
6. 원격 구성
어떤 기능을 추가하려고 하나요?
원격 구성의 사용 사례는 다양합니다. 앱의 디자인을 원격으로 변경하는 것부터 다양한 사용자 세그먼트에 맞게 서로 다른 동작을 구성하는 것까지 다양합니다. 이 Codelab에서는 원격 구성을 사용하여 Make it So 앱에서 새 할 일 수정 기능을 표시하거나 숨기는 기능 전환 버튼을 만들어 보겠습니다.
코딩할 시간입니다.
먼저 Firebase Console에서 구성을 만들어야 합니다. 이렇게 하려면 원격 구성 대시보드로 이동하여 매개변수 추가 버튼을 클릭해야 합니다. 아래 이미지에 따라 입력란을 작성합니다.
모든 입력란을 작성한 후 저장 버튼과 게시를 차례로 클릭합니다. 이제 매개변수가 생성되어 코드베이스에서 사용할 수 있으므로 앱에 새 값을 가져오는 코드를 추가해야 합니다. ConfigurationServiceImpl.kt
파일을 열고 다음 두 함수의 구현을 업데이트합니다.
model/service/impl/ConfigurationServiceImpl.kt
override suspend fun fetchConfiguration(): Boolean {
return remoteConfig.fetchAndActivate().await()
}
override val isShowTaskEditButtonConfig: Boolean
get() = remoteConfig[SHOW_TASK_EDIT_BUTTON_KEY].asBoolean()
첫 번째 함수는 서버에서 값을 가져오고 앱이 시작되는 즉시 SplashViewModel.kt
에서 호출됩니다. 처음부터 모든 화면에서 최신 값을 사용할 수 있도록 하는 가장 좋은 방법입니다. 사용자가 작업을 진행하는 도중에 나중에 앱의 UI나 동작을 변경하면 사용자 환경이 좋지 않습니다.
두 번째 함수는 방금 콘솔에서 만든 매개변수에 대해 게시된 불리언 값을 반환합니다. loadTaskOptions
함수에 다음을 추가하여 TasksViewModel.kt
에서 이 정보를 가져와야 합니다.
screens/tasks/TasksViewModel.kt
fun loadTaskOptions() {
val hasEditOption = configurationService.isShowTaskEditButtonConfig
options.value = TaskActionOption.getOptions(hasEditOption)
}
첫 번째 줄의 값을 가져오고 이를 사용하여 두 번째 줄에는 작업 항목의 메뉴 옵션을 로드합니다. 값이 false
이면 메뉴에 수정 옵션이 포함되지 않습니다. 이제 옵션 목록을 만들었으므로 UI에서 올바르게 표시하도록 해야 합니다. Jetpack Compose로 앱을 빌드할 때는 TasksScreen
의 UI가 어떻게 표시되어야 하는지 선언하는 composable function
를 찾아야 합니다. 따라서 TasksScreen.kt
파일을 열고 LazyColum
를 업데이트하여 TasksViewModel.kt
에서 사용할 수 있는 옵션을 가리킵니다.
screens/tasks/TasksScreen.kt
val options by viewModel.options
LazyColumn {
items(tasks.value, key = { it.id }) { taskItem ->
TaskItem(
options = options,
[...]
)
}
}
TaskItem
는 단일 작업의 UI가 어떻게 표시되어야 하는지 선언하는 또 다른 composable function
입니다. 각 작업에는 사용자가 작업 끝에 있는 점 3개 아이콘을 클릭할 때 표시되는 옵션이 있는 메뉴가 있습니다.
테스트할 시간입니다
이제 앱을 실행할 준비가 되었습니다. Firebase Console을 사용하여 게시한 값이 앱의 동작과 일치하는지 확인합니다.
false
인 경우 점 3개 아이콘을 클릭하면 두 가지 옵션만 표시됩니다.true
인 경우 점 3개 아이콘을 클릭하면 세 가지 옵션이 표시됩니다.
Console에서 값을 몇 번 변경하고 앱을 다시 시작해 보세요. 원격 구성을 사용하여 앱에서 새 기능을 간편하게 출시할 수 있습니다.
7. 축하합니다
축하합니다. Firebase와 Jetpack Compose를 사용하여 Android 앱을 성공적으로 빌드했습니다.
UI용 Jetpack Compose로 완전히 빌드된 Android 앱에 Firebase 인증, Performance Monitoring, 원격 구성, Cloud Firestore를 추가하고 권장되는 MVVM 아키텍처에 맞게 조정했습니다.
추가 자료
- Firebase와 Compose를 사용하여 Android 앱 빌드
- Jetpack Compose 앱에 Firebase 인증 추가
- Jetpack Compose 앱에 Cloud Firestore 추가
- Firebase와 Compose로 빌드된 Android 앱에 코루틴 및 Flow 추가
- Jetpack Compose 앱에 Firebase Performance Monitoring 추가
- Jetpack Compose 앱에 Firebase 원격 구성 추가