具備登入功能的 Android 條件式導覽功能

本程式碼研究室是 Kotlin 進階課程的一部分。只要您按部就班完成程式碼研究室,就能發揮本課程的最大效益。不過,您不一定要這麼做。所有課程程式碼研究室清單均列於進階 Android 版的 Kotlin 程式碼研究室到達網頁中。


這個程式碼研究室的建構基礎是在 Firebase 上透過 Android 實作登入程序。雖然您可以在上個程式碼研究室中下載這個程式碼研究室的範例程式碼,但還是建議您完成使用 FirebaseUI 在 Android 上導入登入程式碼研究室的步驟。

引言

如果您的應用程式支援登入,這是常見用途,僅保留已登入帳戶的使用者部分應用程式。舉例來說,您可以保留已登入使用者的「設定」畫面。

在這種情況下,您可以使用條件式導覽,根據使用者的驗證狀態將使用者導向合適的畫面。

在本程式碼研究室中,您將以現有的應用程式為基礎,新增設定畫面,讓使用者必須登入帳戶才能存取設定畫面。您會使用 Android 裝置導覽元件執行這項工作。

須知事項

課程內容

  • 如何根據使用者是否登入,前往正確的應用程式畫面。

執行步驟

  • 成功處理使用者成功登入之後,將他們導向正確的畫面。
  • 禁止使用者在不登入「設定」畫面中存取 (而非登入) 畫面。

在先前的程式碼研究室中,您開發了一個顯示 Android 知識的應用程式。您的應用程式也允許使用者登入及登出。在這個程式碼研究室中,您將為現有的應用程式新增設定畫面。使用者必須登入,才能查看設定畫面。

如果使用者未登入,那麼當他們嘗試存取設定畫面時,應用程式會將他們重新導向登入畫面。成功完成登入流程後,使用者就會回到您原先嘗試存取的設定畫面。

這個程式碼研究室的建構基礎是在 Firebase 上透過 Android 實作登入程序。雖然您可以在上個程式碼研究室中下載這個程式碼研究室的範例程式碼,但還是建議您完成使用 FirebaseUI 在 Android 上導入登入程式碼研究室的步驟。

您可以下載範例應用程式,您可以採取下列其中一種做法:

下載 Zip


... 或使用下列指令,透過指令列複製 GitHub 存放區,並切換至存放區的 start 分支版本:

$  git clone https://github.com/googlecodelabs/android-kotlin-login-navigation

在 Android Studio 中載入專案之後:

  1. 在模擬器或實體裝置上執行應用程式,以確保您的環境已正確設定,以便開始開發。

如果成功,主畫面應會顯示有趣的 Android 知識和左上角的登入按鈕。


啟動應用程式目前的功能:

  • 如果使用者未登入,請輕觸 [登入] 按鈕啟動登入流程,並允許使用者以電子郵件地址或 Google 帳戶登入。
  • 如果使用者已登入,按鈕就會變更為 [登出] 按鈕,讓使用者登出。

在這項工作中,系統會在主畫面中新增按鈕,讓使用者前往設定畫面。設定畫面可讓使用者選擇要在主畫面上顯示哪種趣味小知識。使用者可以選擇在設定畫面中,查看有關 Android 的資訊,或是對於加州的事實。

  1. 開啟 fragment_main.xml
  2. fragment_main.xml, 中,新增 ConstraintLayout 的「設定」按鈕,然後放置在畫面右上角。

<TextView
       android:id="@+id/settings_btn"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:layout_margin="@dimen/text_margin"
       android:background="@color/colorAccent"
       android:padding="10dp"
       android:text="@string/settings_btn"
       android:textColor="#ffffff"
       android:textSize="20sp"
       app:layout_constraintRight_toRightOf="parent"
       app:layout_constraintTop_toTopOf="parent"/>
  1. 開啟 nav_graph.xml
  2. 在「mainFragment」中新增動作。動作的idaction_mainFragment_to_customizeFragment,目的地為 customizeFragment

nav_graphic.xml

<fragment
       android:id="@+id/mainFragment"
       android:name="com.example.android.firebaseui_login_sample.MainFragment"
       android:label="MainFragment">
   <action
           android:id="@+id/action_mainFragment_to_settingsFragment"
           app:destination="@id/settingsFragment"/>
</fragment>
  1. 開啟 MainFragment.kt
  2. onViewCreated() 中,為 settings_btn 設定 onClickListener,以便使用者輕觸按鈕,前往 customizeFragment

MainFragment.kt

binding.settingsBtn.setOnClickListener {
   val action = MainFragmentDirections.actionMainFragmentToSettingsFragment()
   findNavController().navigate(action)
}
  1. 如果您看到未解決的錯誤,請透過 [建構作業] 選單重新編譯應用程式,以產生並使用您所建立的新導覽動作。
  2. 重新啟動應用程式。現在,右上角的「設定」按鈕應該恢復正常運作。
  3. 按一下即可前往 [設定] 畫面的按鈕。「設定」畫面只有一個選項,可讓使用者選擇自己想顯示在主畫面上的趣聞。
  4. 按一下 Android 裝置的 [返回] 按鈕,回到主螢幕。

在這項工作中,您會加入程式碼,讓使用者在未登入的情況下嘗試進入登入畫面。

  1. 開啟 SettingsFragment.kt
  2. onViewCreated() 中,觀察 authenticationState 並將使用者重新導向至 LoginFragment (如果未經驗證)。

SettingsFragment.kt

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
   super.onViewCreated(view, savedInstanceState)
   val navController = findNavController()
   viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
       when (authenticationState) {
           LoginViewModel.AuthenticationState.AUTHENTICATED -> Log.i(TAG, "Authenticated")
           // If the user is not logged in, they should not be able to set any preferences,
           // so navigate them to the login fragment
           LoginViewModel.AuthenticationState.UNAUTHENTICATED -> navController.navigate(
               R.id.loginFragment
           )
           else -> Log.e(
               TAG, "New $authenticationState state that doesn't require any UI change"
           )
       }
   })
}

當使用者嘗試存取設定畫面時,應用程式會將使用者導向登入畫面,因此應用程式也必須在登入畫面處理返回按鈕的行為。如果應用程式未自訂處理返回按鈕的行為,使用者會一直處於無限的循環,嘗試返回設定畫面,然後再重新導向到登入畫面。

  1. 開啟 LoginFragment.kt
  2. onViewCreated() 中,將使用者帶回 MainFragment,以便處理返回按鈕動作。

LoginFragment.kt

// If the user presses the back button, bring them back to the home screen
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
   navController.popBackStack(R.id.mainFragment, false)
}
  1. 重新啟動您的應用程式,並確認如果您未登入,則嘗試存取設定畫面後,系統會將您重新導向至登入流程。

雖然您已成功將使用者重新導向到登入頁面,但您並未處理使用者成功登入後所採取的動作,因此登入要求會顯示為沒有作用。您會在下一個步驟中修正這個問題。

您目前已經成功設定應用程式,在未登入的情況下嘗試存取設定畫面,讓使用者被重新導向至登入畫面。

不過,完成登入流程後,您會再次返回登入畫面。不過,這種使用者體驗和體驗不會造成混淆。

為了提供理想的使用者體驗,應用程式會在使用者成功登入後,再返回設定畫面。

  1. 仍在 LoginFragment.ktonViewCreated() 中,觀察 authenticationState,並會在使用者成功通過驗證後返回至 SettingsFragment

LoginFragment.kt

// Observe the authentication state so we can know if the user has logged in successfully.
// If the user has logged in successfully, bring them back to the settings screen.
// If the user did not log in successfully, display an error message.
viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
   when (authenticationState) {
      // Since our login flow is only one screen instead of multiple 
      // screens, we can utilize popBackStack(). If our login flow 
      // consisted of multiple screens, we would have to call 
      // popBackStack() multiple times.
       LoginViewModel.AuthenticationState.AUTHENTICATED -> navController.popBackStack()
       else -> Log.e(
           TAG,
           "Authentication state that doesn't require any UI change $authenticationState"
       )
   }
})
  1. 再次執行應用程式,並確認您成功登入後,系統會將您帶往「Settings」(設定) 頁面,而非「Login」(登入) 頁面。

您可以在這個 GitHub 存放區 https://github.com/googlecodelabs/android-kotlin-login-navigation 中,查看所有包含完整解決方案程式碼的應用程式。

在本程式碼研究室中,您已瞭解各種最佳做法,瞭解如何在支援登入的應用程式中建立良好的使用者體驗。藉由觀察應用程式的驗證狀態,您就能判斷使用者可以存取哪些畫面,並在必要時將他們重新導向至登入畫面。

如要進一步瞭解 Android 導航的最佳做法,請參考下列資源:

Android 開發人員說明文件:

程式碼研究室:

如要瞭解本課程中其他程式碼研究室的連結,請參閱 Kotlin 的進階 Android 程式碼研究室到達網頁。