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

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


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

はじめに

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

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

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

前提となる知識

学習内容

  • ログインしているかどうかによって、アプリの適切な画面にユーザーを誘導する方法。

演習内容

  • ログインに成功したユーザーを適切な画面に移動させる処理を適切に行います。
  • ログインしていないユーザーが [設定] 画面にアクセスできないようにし、代わりに [ログイン] 画面にリダイレクトします。

前の 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 の楽しい事実と、左上にログイン ボタンが表示されます。


スターター アプリの現在の機能は次のとおりです。

  • ユーザーがログインしていない場合、[ログイン] ボタンをタップするとログイン フローが開始され、ユーザーはメールアドレスまたは 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. 未解決のエラーが表示された場合は、[ビルド] メニューからアプリを再コンパイルして、作成した新しいナビゲーション アクションを生成して使用します。
  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. アプリを再度実行し、ログインに成功すると、[ログイン] ページではなく [設定] ページに移動することを確認します。

すべてのソリューション コードを含む完全なアプリは、GitHub リポジトリ(https://github.com/googlecodelabs/android-kotlin-login-navigation)で確認できます。

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

Android のナビゲーションに関するベスト プラクティスについて詳しくは、次のリソースをご覧ください。

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

Codelabs:

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