這個程式碼研究室是「Android Kotlin 進階功能」課程的一部分。如果您按部就班完成每一堂程式碼研究室課程,就能充分體驗到本課程的價值,但這不是強制要求。如要查看所有課程程式碼研究室,請前往 Android Kotlin 進階功能程式碼研究室登陸頁面。
簡介
建構 Android 應用程式時,支援使用者登入功能可帶來許多好處。允許使用者在應用程式中建立身分,就能提供更多與應用程式互動的方式。
有了個人化帳戶,使用者就能自訂應用程式內體驗、與其他使用者互動,以及在其他裝置 (例如網頁或新手機) 上使用應用程式時,保留及轉移資料。
在本程式碼研究室中,您將瞭解如何使用 FirebaseUI 程式庫,為應用程式提供登入支援服務。FirebaseUI 程式庫可讓開發人員輕鬆建構登入流程,並代為管理使用者帳戶。
必備知識
- 如何建構 Android 應用程式的基礎知識
- LiveData 和 ViewModel
課程內容
- 如何將 Firebase 新增至專案
- 如何支援 Android 應用程式的登入功能
- 如何觀察應用程式目前的驗證狀態
- 如何登出使用者
學習內容
- 使用 Firebase 控制台將 Firebase 整合至應用程式。
- 實作登入功能。
- 為已登入的使用者在應用程式中新增自訂項目。
- 實作使用者登出功能。
進一步瞭解 LiveData 和 ViewModel
如要使用本程式碼研究室中的應用程式,您必須瞭解 LiveData 和 ViewModel 的基本概念。如要簡要瞭解這些概念,請參閱 LiveData 和 ViewModel 總覽。
您也可以完成「使用 Kotlin 開發 Android 應用程式」課程,瞭解本程式碼研究室中會遇到的 Android 基礎主題。這門課程提供 Udacity 課程和 程式碼研究室課程。
在本程式碼研究室中,您將建構一個顯示有趣 Android 知識的應用程式。更重要的是,應用程式會顯示「登入/登出」按鈕。使用者登入應用程式後,系統顯示的任何 Android 知識都會包含對使用者的問候語,增添個人化體驗。

下載範例應用程式,方法如下:
... 或使用下列指令從指令列複製 GitHub 存放區,然後切換至存放區的 start 分支:
$ git clone https://github.com/googlecodelabs/android-kotlin-login
重要事項:由於您要整合應用程式來使用 Firebase,因此必須先設定入門應用程式,才能建構及執行該應用程式。您將在本程式碼研究室的下一個步驟中執行這項操作。
步驟 1:建立 Firebase 專案
將 Firebase 加入 Android 應用程式前,請先建立要連結至該 Android 應用程式的 Firebase 專案。
- 在 Firebase 控制台中,按一下「新增專案」。
- 選取或輸入專案名稱。您可以為專案命名,但建議選擇與您建構的應用程式相關的名稱。
- 按一下「繼續」。
- 您可以略過設定 Google Analytics,然後選擇「暫時不要」選項。
- 按一下「建立專案」,完成 Firebase 專案設定。
步驟 2:向 Firebase 註冊應用程式
建立 Firebase 專案後,即可加入 Android 應用程式。
- 在 Firebase 控制台的專案總覽頁面中間,按一下「Android」Android圖示來啟動設定工作流程。
- 在「Android 套件名稱」欄位中,輸入應用程式的應用程式 ID。請務必輸入應用程式使用的 ID,因為向 Firebase 專案註冊應用程式後,就無法新增或修改這個值。
- 應用程式 ID 有時也稱為套件名稱。
- 在模組 (應用程式層級) Gradle 檔案中找出這個應用程式 ID,通常是
app/build.gradle(ID 範例:com.yourcompany.yourproject)。 - 輸入偵錯簽署憑證 SHA-1。您可以在指令列終端機中輸入下列指令,產生這項金鑰。
keytool -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v -storepass android
- 按一下 [Register app] (註冊應用程式)。
步驟 3:將 Firebase 設定檔新增至專案
將 Firebase Android 設定檔新增至應用程式:
- 按一下「Download google-services.json」,取得 Firebase Android 設定檔 (
google-services.json)。
- 您隨時可以再次下載 Firebase Android 設定檔。
- 請確認設定檔名稱未附加額外字元,且只能命名為
google-services.json
- 將設定檔移到應用程式的模組 (應用程式層級) 目錄中。
步驟 4:設定 Android 專案,啟用 Firebase 產品
- 如要在應用程式中啟用 Firebase 產品,請將 google-services 外掛程式新增至 Gradle 檔案。
- 在根層級 (專案層級) 的 Gradle 檔案 (
build.gradle) 中,新增規則來加入 Google 服務外掛程式。同時確認您有 Google 的 Maven 存放區。
build.gradle
buildscript {
repositories {
// Check that you have the following line (if not, add it):
google() // Google's Maven repository
}
dependencies {
// ...
// Add the following line:
classpath 'com.google.gms:google-services:4.3.0' // Google Services plugin
}
}
allprojects {
// ...
repositories {
// Check that you have the following line (if not, add it):
google() // Google's Maven repository
// ...
}
}- 在模組 (應用程式層級) Gradle 檔案 (通常是
app/build.gradle) 的底部新增一行。
app/build.gradle
apply plugin: 'com.android.application'
android {
// ...
}
// Add the following line to the bottom of the file:
apply plugin: 'com.google.gms.google-services' // Google Play services Gradle plugin步驟 4:新增 Firebase 依附元件
在本程式碼研究室中,整合 Firebase 的主要目的是建立及管理使用者。為此,您需要新增 Firebase 程式庫,才能實作登入功能。
- 在
build.gradle (Module:app)檔案中新增下列依附元件,即可在應用程式中使用 SDK。您可以使用firebase-authSDK 管理應用程式的已驗證使用者。
app/build.gradle:
implementation 'com.firebaseui:firebase-ui-auth:5.0.0'- 將專案與 Gradle 檔案同步,確保應用程式可使用所有依附元件。如果系統未提示,請在 Android Studio 中依序選取「File」>「Sync Project with Gradle Files」,或從工具列選取。
步驟 5:執行應用程式並檢查程式碼
- 在模擬器或實體裝置上執行應用程式,確認環境已設定完成,可以開始開發。
如果成功,主畫面應會顯示有趣的 Android 知識,且左上角會顯示登入按鈕。輕觸登入按鈕目前不會執行任何動作。
整體來說,這款應用程式是具有多個片段的單一活動應用程式。MainFragment 包含下方畫面顯示的所有 UI。(您會在後續的程式碼研究室中處理 LoginFragment 和 SettingsFragment)。

- 熟悉程式碼。請特別注意以下事項:
FirebaseUserLiveData是您要實作的類別,用來觀察與應用程式相關聯的目前 Firebase 使用者。您會在後續步驟中使用FirebaseAuth例項做為進入點,取得這項使用者資訊。MainFragment與LoginViewModel相關聯。LoginViewModel是您要實作的類別,以便使用FirebaseUserLiveData建立authenticationState變數。使用這個authenticationState變數時,MainFragment就能觀察該值,並據此更新 UI。
在這個步驟中,您將使用 Firebase 控制台設定應用程式要支援的驗證方法。在本程式碼研究室中,您將著重於讓使用者透過提供的電子郵件地址或 Google 帳戶登入。
- 前往 Firebase 控制台。(注意:如果仍在「新增 Firebase」工作流程中,請按一下左上角的「X」X,返回控制台。
- 如果尚未進入專案,請選取專案。
- 開啟左側導覽面板,然後選取「Develop」>「Authentication」 。

- 選取頂端導覽列的「登入方式」分頁標籤。

- 按一下「電子郵件/密碼」列。
- 在彈出式視窗中切換「Enabled」(啟用狀態),然後按一下「Save」(儲存)。
- 同樣地,點選「Google」列。
- 切換「Enabled」(啟用狀態),輸入「Project support email」(專案支援電子郵件地址),然後按一下「Save」(儲存)。
在這項工作中,您將為使用者實作登入功能。
- 開啟
MainFragment.kt。 - 在
MainFragment的版面配置中,請注意auth_button。目前尚未設定處理任何使用者輸入內容。 - 在
onViewCreated(),中,將onClickListener新增至auth_button,以呼叫launchSignInFlow()。
MainFragment.kt
binding.authButton.setOnClickListener { launchSignInFlow() }- 在
MainFragment.kt中尋找launchSignInFlow()方法。目前包含TODO。 - 完成
launchSignInFlow()函式,如下所示。
MainFragment.kt
private fun launchSignInFlow() {
// Give users the option to sign in / register with their email or Google account.
// If users choose to register with their email,
// they will need to create a password as well.
val providers = arrayListOf(
AuthUI.IdpConfig.EmailBuilder().build(), AuthUI.IdpConfig.GoogleBuilder().build()
// This is where you can provide more ways for users to register and
// sign in.
)
// Create and launch sign-in intent.
// We listen to the response of this activity with the
// SIGN_IN_REQUEST_CODE
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(providers)
.build(),
MainFragment.SIGN_IN_REQUEST_CODE
)
}使用者可以透過電子郵件地址或 Google 帳戶註冊及登入。如果使用者選擇以電子郵件地址註冊,他們建立的電子郵件地址和密碼組合只適用於您的應用程式。也就是說,他們可以使用該組合登入您的應用程式,但無法使用相同憑證登入任何其他 Firebase 支援的應用程式。
- 在
MainFragment.kt中,您可以實作onActivityResult()方法,監聽登入程序的結果,如下所示。由於您是透過SIGN_IN_REQUEST_CODE啟動登入程序,因此也可以篩選SIGN_IN_REQUEST_CODE傳回onActivityResult()的時間,監聽登入程序的結果。首先,請加入一些記錄陳述式,瞭解使用者是否已成功登入。
MainFragment.kt
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == SIGN_IN_REQUEST_CODE) {
val response = IdpResponse.fromResultIntent(data)
if (resultCode == Activity.RESULT_OK) {
// User successfully signed in
Log.i(TAG, "Successfully signed in user ${FirebaseAuth.getInstance().currentUser?.displayName}!")
} else {
// Sign in failed. If response is null the user canceled the
// sign-in flow using the back button. Otherwise check
// response.getError().getErrorCode() and handle the error.
Log.i(TAG, "Sign in unsuccessful ${response?.error?.errorCode}")
}
}
}您的應用程式現在應該可以處理使用者註冊和登入作業!
- 執行應用程式,然後確認輕觸「Login」按鈕會顯示登入畫面。
- 現在可以使用電子郵件地址和密碼登入,也可以使用 Google 帳戶登入。
- 登入後,使用者介面不會有任何變化 (您會在下一個步驟中實作更新使用者介面),但如果一切正常運作,完成註冊流程後,您應該會看到
Successfully signed in user ${your name}!記錄訊息。 - 您也可以前往 Firebase 控制台,依序點選「開發」>「驗證」>「使用者」,確認應用程式現在有一位已註冊使用者。
- 請注意,使用者為您的應用程式建立帳戶時,該帳戶只會與您的應用程式連結,不會與任何使用 Firebase 登入功能的應用程式連結。
在這項工作中,您將實作根據驗證狀態更新 UI 的功能。使用者登入後,您可以顯示他們的名稱,打造個人化的主畫面。使用者登入後,您也會將「登入」按鈕更新為「登出」按鈕。
- 開啟已為您建立的
FirebaseUserLiveData.kt類別。首先,您必須提供方法,讓應用程式中的其他類別瞭解使用者何時登入或登出。不過,由於LiveData的值尚未更新,因此這個類別目前不會執行任何動作。 - 由於您使用的是
FirebaseAuth程式庫,因此可以透過FirebaseUser.AuthStateListener回呼監聽登入使用者的變更,而這項回呼已在 FirebaseUI 程式庫中為您實作。每當使用者登入或登出應用程式時,系統就會觸發這個回呼。 - 請注意,
FirebaseUserLiveData.kt會定義authStateListener變數。您將使用這個變數儲存LiveData的值。建立authStateListener變數後,您就能根據應用程式的狀態,正確開始及停止監聽授權狀態的變更。舉例來說,如果使用者將應用程式放到背景,應用程式應停止監聽驗證狀態變更,以免發生潛在的記憶體洩漏問題。 - 更新
authStateListener,讓FirebaseUserLiveData的值對應目前的 Firebase 使用者。
FirebaseUserLiveData.kt
private val authStateListener = FirebaseAuth.AuthStateListener { firebaseAuth ->
value = firebaseAuth.currentUser
}- 開啟
LoginViewModel.kt。 - 在
LoginViewModel.kt中,根據您剛實作的FirebaseUserLiveData物件建立authenticationState變數。建立這個authenticationState變數後,其他類別現在可以透過LoginViewModel查詢使用者是否已登入。
LoginViewModel.kt
val authenticationState = FirebaseUserLiveData().map { user ->
if (user != null) {
AuthenticationState.AUTHENTICATED
} else {
AuthenticationState.UNAUTHENTICATED
}
}- 開啟「
MainFragment.kt.」 - 在
MainFragment.kt的observeAuthenticationState()中,您可以使用剛在LoginViewModel中新增的authenticationState變數,並相應地變更 UI。如有已登入的使用者,authButton應顯示「登出」。
MainFragment.kt
private fun observeAuthenticationState() {
val factToDisplay = viewModel.getFactToDisplay(requireContext())
viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
when (authenticationState) {
LoginViewModel.AuthenticationState.AUTHENTICATED -> {
binding.authButton.text = getString(R.string.logout_button_text)
binding.authButton.setOnClickListener {
// TODO implement logging out user in next step
}
// TODO 2. If the user is logged in,
// you can customize the welcome message they see by
// utilizing the getFactWithPersonalization() function provided
}
else -> {
// TODO 3. Lastly, if there is no logged-in user,
// auth_button should display Login and
// launch the sign in screen when clicked.
}
}
})
}- 如果使用者已登入,您也可以利用
MainFragment中提供的getFactWithPersonalization()函式,自訂使用者看到的歡迎訊息。
MainFragment.kt
binding.welcomeText.text = getFactWithPersonalization(factToDisplay)- 最後,如果沒有登入的使用者 (當
authenticationState不是LoginViewModel.AuthenticationState.AUTHENTICATED時),auth_button應顯示「登入」,並在點選時啟動登入畫面。顯示的訊息也不應經過個人化處理。
MainFragment.kt
binding.authButton.text = getString(R.string.login_button_text)
binding.authButton.setOnClickListener { launchSignInFlow() }
binding.welcomeText.text = factToDisplay完成所有步驟後,最終的 observeAuthenticationState() 方法應類似下列程式碼。
MainFragment.kt
private fun observeAuthenticationState() {
val factToDisplay = viewModel.getFactToDisplay(requireContext())
viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
// TODO 1. Use the authenticationState variable you just added
// in LoginViewModel and change the UI accordingly.
when (authenticationState) {
// TODO 2. If the user is logged in,
// you can customize the welcome message they see by
// utilizing the getFactWithPersonalization() function provided
LoginViewModel.AuthenticationState.AUTHENTICATED -> {
binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
binding.authButton.text = getString(R.string.logout_button_text)
binding.authButton.setOnClickListener {
// TODO implement logging out user in next step
}
}
else -> {
// TODO 3. Lastly, if there is no logged-in user,
// auth_button should display Login and
// launch the sign in screen when clicked.
binding.welcomeText.text = factToDisplay
binding.authButton.text = getString(R.string.login_button_text)
binding.authButton.setOnClickListener {
launchSignInFlow()
}
}
}
})
}- 執行應用程式。UI 應會根據使用者是否登入而更新。如果一切正常且您已登入,主畫面現在應該會顯示您的名字,並提供 Android 相關資訊。「Login」按鈕現在也應會顯示「Logout」。

在這項工作中,您將實作登出功能。
由於應用程式允許使用者登入,因此也應提供登出方式。以下範例說明如何使用一行程式碼登出使用者:
AuthUI.getInstance().signOut(requireContext())- 開啟
MainFragment.kt。 - 在
MainFragment.kt的observeAuthenticationState()中新增登出邏輯,確保auth_button函式在使用者登入時正常運作。這個方法的最終結果如下所示。
MainFragment.kt
private fun observeAuthenticationState() {
val factToDisplay = viewModel.getFactToDisplay(requireContext())
viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
when (authenticationState) {
LoginViewModel.AuthenticationState.AUTHENTICATED -> {
binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
binding.authButton.text = getString(R.string.logout_button_text)
binding.authButton.setOnClickListener {
AuthUI.getInstance().signOut(requireContext())
}
}
else -> {
binding.welcomeText.text = factToDisplay
binding.authButton.text = getString(R.string.login_button_text)
binding.authButton.setOnClickListener {
launchSignInFlow()
}
}
}
})
}- 執行應用程式。
- 輕觸「登出」按鈕,確認使用者已登出,且按鈕狀態變更為「登入」。

您可以在這裡找到完成的應用程式最終版本:https://github.com/googlecodelabs/android-kotlin-login。
在本程式碼研究室中,您已瞭解以下內容:
- 瞭解如何在 Gradle 檔案中新增必要依附元件,並在 Firebase 主控台中設定專案,將 Firebase 新增至專案。
- 如何使用 FirebaseUI 程式庫為應用程式導入登入功能,並指定允許使用者登入的方式。請注意,使用者在您應用程式中建立的任何帳戶,都只適用於該應用程式,不會與使用 Firebase 登入功能的所有應用程式共用。
- 如何使用
LiveData觀察應用程式目前的驗證狀態。 - 如何登出使用者。
本程式碼研究室介紹了如何為 Android 應用程式提供登入支援的基本概念。
在本程式碼研究室中,您允許使用者以電子郵件地址註冊及登入。不過,您也可以使用 FirebaseUI 程式庫支援其他驗證方法,例如透過電話號碼登入。如要進一步瞭解 FirebaseUI 程式庫的功能,以及如何運用程式庫提供的其他功能,請參閱下列資源:
如要進一步瞭解登入相關最佳做法,請參閱下列資源:
Codelabs:
Android 開發人員說明文件:
影片:
如要查看本課程其他程式碼研究室的連結,請參閱 Android Kotlin 進階功能程式碼研究室登陸頁面。