ログインを伴う Android の条件付きナビゲーション

この Codelab は、Kotlin での高度な Android 開発コースの一部です。Codelab を順番に進めていくと、このコースを最大限に活用できますが、これは必須ではありません。すべてのコース Codelab は Kotlin での Codelab の高度な Codelab のランディング ページに掲載されています。


この Codelab は、FirebaseUI を使用して Android でログインを実装するに基づいています。この Codelab のスターター コードは、前の Codelab をまだダウンロードしていない場合はダウンロードできますが、先に FirebaseUI を使用した Android でのログインの実装の Codelab を完了しておくことをおすすめします。

はじめに

アプリがログインをサポートしている場合は、ログイン中のユーザーのみにアプリの一部を予約するユースケースが一般的です。たとえば、ログイン ユーザーに対してアプリの [設定] 画面を予約することができます。

そのような場合は、条件付きナビゲーションを使用し、ユーザーの認証状態に基づいて適切な画面に移動させることができます。

この Codelab では、既存のアプリの上に構築を行い、ユーザーがログインしたときにのみアクセスできる設定画面を追加します。このタスクでは Android のナビゲーション コンポーネントを使用します。

前提となる知識

学習内容

  • ユーザーがログインしているかどうかに応じて、アプリの適切な画面に移動する方法

演習内容

  • ユーザーがログインに成功した後、適切な画面に移動することを適切に処理します。
  • ユーザーがログインしていない場合は [Settings] 画面にアクセスできないようにし、代わりに [Login] 画面にリダイレクトします。

前の Codelab では、Android に関する事実を表示するアプリについて学習しました。ユーザーがアプリへのログインとログアウトも許可しています。この Codelab では、既存のアプリに設定画面を追加します。設定画面は、ユーザーがログインした場合にのみアクセスできます。

ユーザーがログインしていない場合、設定画面にアクセスしようとすると、ログイン画面にリダイレクトされます。ログインフローが完了すると、ユーザーは最初にアクセスしようとした設定画面に戻ります。

この Codelab は、FirebaseUI を使用して Android でログインを実装するに基づいています。この Codelab のスターター コードは、前の Codelab をまだダウンロードしていない場合はダウンロードできますが、先に FirebaseUI を使用した Android でのログインの実装の Codelab を完了しておくことをおすすめします。

次のいずれかの方法でサンプルアプリをダウンロードします。

ZIP をダウンロード


... または、次のコマンドを使用して GitHub リポジトリのクローンを作成し、リポの start ブランチに切り替えます。

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

Android Studio にプロジェクトが読み込まれたら、次の手順を実行します。

  1. エミュレータまたは実機でアプリを実行して、開発環境で環境の設定を開始できることを確認します。

正常に完了すると、ホーム画面に Android に関する面白い情報が表示され、左上にログインボタンが表示されます。


スターター アプリの現在の機能:

  • ユーザーがログインしていない場合、[Login] ボタンをタップするとログインフローが始まり、ユーザーはメールアドレスまたは Google アカウントでログインできるようになります。
  • ユーザーがログインしている場合は、ボタンが [ログアウト] ボタンに変わります。ユーザーがログアウトできるようにします。

このタスクでは、ユーザーが設定画面に移動するためのボタンをホーム画面に追加します。設定画面では、ホーム画面に表示する情報の種類を選択できます。設定画面では、Android に関する事実やカリフォルニアに関する事実を確認できます。

  1. fragment_main.xml を開きます。
  2. fragment_main.xml, で、ConstraintLayout にネストされている設定ボタンを追加し、画面の右上に配置します。

fragment_main.xml

<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_graph.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_btnonClickListener を設定して、ボタンをタップすると customizeFragment に移動できるようにします。

MainFragment.kt

binding.settingsBtn.setOnClickListener {
   val action = MainFragmentDirections.actionMainFragmentToSettingsFragment()
   findNavController().navigate(action)
}
  1. 未解決のエラーが表示された場合は、[Build] メニューからアプリを再コンパイルし、作成した新しいナビゲーション アクションを生成して使用します。
  2. アプリを再起動します。画面の右上に機能的な設定ボタンが表示されます。
  3. ボタンをクリックして、[設定] 画面を表示します。設定画面にある選択肢は 1 つだけです。ユーザーは、ホーム画面に表示する楽しい情報の種類を選択できます。
  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.kt で引き続き onViewCreated() の任意の場所(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. アプリを再度実行し、ログインが正常に完了したら、[Login] ページではなく [Settings] ページが表示されることを確認します。

すべての解答コードを含む完全なアプリは、この GitHub リポジトリ(https://github.com/googlecodelabs/android-kotlin-login-navigation)でご確認いただけます。

この Codelab では、ログインをサポートするアプリで優れたユーザー エクスペリエンスを実現するためのベスト プラクティスについて学びました。アプリの認証ステータスを監視することで、ユーザーがアクセスできる画面を特定し、必要に応じてログイン画面にリダイレクトできました。

Android のナビゲーションに関するおすすめの方法について詳しくは、以下のリソースをご覧ください。

Android デベロッパー ドキュメント:

Codelab:

このコースの他の Codelab へのリンクについては、Kotlin Codelab の高度な Codelab のランディング ページをご覧ください。