この Codelab は、Kotlin を使った高度な Android 開発コースの一部です。Codelab を順番に進めると、このコースを最大限に活用できますが、これは必須ではありません。コースの Codelab はすべて、Kotlin を使った高度な Android 開発の Codelab ランディング ページに記載されています。
はじめに
Android アプリを構築する際に、ユーザーのログインをサポートすることで多くのメリットが得られます。ユーザーがアプリ内で ID を作成できるようにすることで、アプリの利用方法を増やすことができます。
パーソナライズされたアカウントを使用すると、ユーザーはアプリ内での操作をカスタマイズしたり、他のユーザーと交流したりできます。また、別のデバイス(ウェブや新しいスマートフォンなど)でアプリを使用している場合は、データを保持して転送することもできます。
この Codelab では、FirebaseUI ライブラリを使用してアプリのログインをサポートする基本的な方法を学びます。FirebaseUI ライブラリは、ログインフローを構築したいデベロッパーにとって使いやすく、ユーザー アカウントの管理作業を処理します。
前提となる知識
- Android アプリの作成方法の基礎
- LiveData と ViewModel
学習内容
- プロジェクトに Firebase を追加する方法
- Android アプリのログインをサポートする方法
- アプリの現在の認証ステータスを確認する方法
- ユーザーをログアウトさせる方法
演習内容
- Firebase コンソールを使用して、アプリに Firebase を統合します。
- ログイン機能を実装します。
- ログインしているユーザー向けにアプリでカスタマイズを追加します。
- ユーザーのログアウトを実装します。
LiveData と ViewModel について
この Codelab のアプリでは、LiveData と ViewModel の基本的な知識が必要です。これらのコンセプトの概要については、LiveData と ViewModel の概要をご覧ください。
また、Kotlin による Android アプリの開発コースを受講して、この Codelab の一部として取り組むことになる Android の基本的なトピックについて学ぶこともできます。このコースは、Udacity コースとコードラボ コースの両方で受講できます。
この Codelab では、Android に関する楽しい事実を表示するアプリを作成します。また、アプリには [ログイン/ログアウト] ボタンが表示されます。ユーザーがアプリにログインしている場合、表示される Android の豆知識には、パーソナライズされた挨拶が含まれます。

サンプルアプリを次のいずれかの方法でダウンロードします。
または、次のコマンドを使用して、コマンドラインから GitHub リポジトリのクローンを作成し、リポジトリの start ブランチに切り替えます。
$ git clone https://github.com/googlecodelabs/android-kotlin-login
重要: Firebase を使用するようにアプリを統合するため、スターター アプリをビルドして実行するには、いくつかの設定が必要です。これについては、Codelab の次のステップで対応します。
ステップ 1: Firebase プロジェクトを作成する
Android アプリに Firebase を追加する前に、Android アプリに接続するための Firebase プロジェクトを作成します。
- Firebase コンソールで [プロジェクトを追加] をクリックします。
- プロジェクト名を選択または入力します。プロジェクトには任意の名前を付けることができますが、作成するアプリに関連する名前を選択してください。
- [続行] をクリックします。
- Google アナリティクスの設定をスキップして、[今は設定しない] オプションを選択できます。
- [Create Project] をクリックして、Firebase プロジェクトの設定を完了します。
ステップ 2: アプリを Firebase に登録する
Firebase プロジェクトを作成したら、プロジェクトに Android アプリを追加できます。
- Firebase コンソールの [プロジェクトの概要] ページの中央にある Android アイコンをクリックして設定ワークフローを起動します。
- アプリのアプリケーション ID を [Android パッケージ名] フィールドに入力します。アプリを Firebase プロジェクトに登録した後で、この値を追加または変更することはできません。必ずアプリで使用している ID を入力してください。
- アプリケーション ID はパッケージ名と呼ばれることもあります。
- このアプリケーション ID はモジュール(アプリレベル)の Gradle ファイル(通常は
app/build.gradle)内に記載されています(アプリケーション ID の例:com.yourcompany.yourproject)。 - デバッグ用の署名証明書の SHA-1 を入力します。この鍵は、コマンドライン ターミナルで次のコマンドを入力して生成できます。
keytool -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v -storepass android
- [アプリの登録] をクリックします。
ステップ 3: Firebase 構成ファイルをプロジェクトに追加する
Firebase Android 構成ファイルをアプリに追加します。
- [google-services.json をダウンロード] をクリックして、Firebase Android 構成ファイル(
google-services.json)を取得します。
- Firebase Android 構成ファイルはいつでも再ダウンロードできます。
- 構成ファイルに余分な文字が追加されていないこと、
google-services.jsonという名前のみであることを確認します。
- 構成ファイルをアプリのモジュール(アプリレベル)ディレクトリに移動します。
ステップ 4: Firebase プロダクトを有効にするように Android プロジェクトを構成する
- アプリで Firebase プロダクトを有効にするには、Gradle ファイルに google-services プラグインを追加します。
- ルートレベル(プロジェクト レベル)の 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 の依存関係を追加する
この Codelab で Firebase を統合する主な理由は、ユーザーを作成して管理する方法を確保するためです。そのためには、ログインを実装できる Firebase ライブラリを追加する必要があります。
- アプリで SDK を使用できるように、
build.gradle (Module:app)ファイルに次の依存関係を追加します。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 については、フォローアップの Codelab で扱います)。

- コードをよく理解してください。特に、次の点に注意してください。
FirebaseUserLiveDataは、アプリに関連付けられている現在の Firebase ユーザーを監視するために実装するクラスです。後の手順で、FirebaseAuthインスタンスをエントリ ポイントとして使用して、このユーザー情報を取得します。MainFragmentはLoginViewModelに関連付けられています。LoginViewModelは、FirebaseUserLiveDataを利用してauthenticationState変数を作成するために実装するクラスです。このauthenticationState変数を使用すると、MainFragmentは値を監視して、それに応じて UI を更新できます。
このステップでは、Firebase コンソールを使用して、アプリでサポートする認証方法を設定します。この Codelab では、ユーザーが指定したメールアドレスまたは Google アカウントでログインできるようにすることに焦点を当てます。
- Firebase コンソールに移動します。(注: Firebase の追加ワークフローがまだ開いている場合は、左上の X をクリックしてコンソールに戻ります。
- プロジェクトにまだ参加していない場合は、プロジェクトを選択します。
- 左側のナビゲーションを開き、[Develop] > [Authentication ] を選択します。

- 上部のナビゲーション バーにある [ログイン方法] タブを選択します。

- [メールアドレス/パスワード] 行をクリックします。
- ポップアップで、[有効] スイッチを切り替えて [保存] をクリックします。
- 同様に、[Google] 行をクリックします。
- [有効] スイッチを切り替え、[プロジェクトのサポートメール] を入力して、[保存] をクリックします。
このタスクでは、ユーザーのログイン機能を実装します。
MainFragment.ktを開きます。MainFragmentのレイアウトで、auth_buttonを確認します。現在、ユーザー入力の処理は設定されていません。onViewCreated(),で、auth_buttonにonClickListenerを追加して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}")
}
}
}これで、アプリでユーザーの登録とログインを処理できるようになりました。
- アプリを実行し、[ログイン] ボタンをタップするとログイン画面が表示されることを確認します。
- メールアドレスとパスワード、または Google アカウントでログインできるようになりました。
- ログイン後の UI には変更はありません(次のステップで UI の更新を実装します)。ただし、すべてが正しく機能していれば、登録フローを完了した後に
Successfully signed in user ${your name}!というログメッセージが表示されます。 - Firebase コンソールに移動し、[開発] > [認証] > [ユーザー] に移動して、アプリに登録ユーザーが 1 人いることを確認することもできます。
- ユーザーがアプリのアカウントを作成すると、そのアカウントはアプリ専用となり、ログイン機能に Firebase を使用するアプリには関連付けられません。
このタスクでは、認証状態に基づいて UI を更新する処理を実装します。ユーザーがログインしている場合は、名前を表示してホーム画面をカスタマイズできます。また、ユーザーがログインしている場合は、[Login] ボタンを [Logout] ボタンに更新します。
- すでに作成されている
FirebaseUserLiveData.ktクラスを開きます。まず、アプリ内の他のクラスがユーザーのログインまたはログアウトを認識できるようにする必要があります。ただし、LiveDataの値が更新されていないため、クラスはまだ何も行いません。 FirebaseAuthライブラリを使用しているため、FirebaseUI ライブラリの一部として実装されているFirebaseUser.AuthStateListenerコールバックを使用して、ログイン ユーザーの変更をリッスンできます。このコールバックは、ユーザーがアプリにログインまたはログアウトするたびにトリガーされます。FirebaseUserLiveData.ktはauthStateListener変数を定義します。この変数を使用して、LiveDataの値を格納します。authStateListener変数は、アプリケーションの状態に基づいて認証状態の変更を適切にリッスンできるようにするために作成されました。たとえば、ユーザーがアプリをバックグラウンドに移動した場合、メモリリークの可能性を防ぐために、アプリは認証状態の変化のリスニングを停止する必要があります。FirebaseUserLiveDataの値が現在の Firebase ユーザーに対応するようにauthStateListenerを更新します。
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 の豆知識に加えて、名前が表示されるようになります。[ログイン] ボタンも [ログアウト] に変わります。

このタスクでは、ログアウト機能を実装します。
アプリでユーザーがログインできる場合は、ログアウトする方法も提供する必要があります。次の例は、1 行のコードでユーザーをログアウトする方法を示しています。
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 で確認できます。
この Codelab では、以下のことを学びました。
- gradle ファイルに必要な依存関係を追加し、Firebase コンソールでプロジェクトを設定して、プロジェクトに Firebase を追加する方法。
- FirebaseUI ライブラリを使用してアプリのログインを実装し、ユーザーのログイン方法を指定する方法。ユーザーがアプリで作成したアカウントは、そのアプリ専用であり、ログイン機能に Firebase を使用するすべてのアプリで共有されるわけではありません。
LiveDataを使用してアプリの現在の認証ステータスをモニタリングする方法。- ユーザーをログアウトする方法。
この Codelab では、Android アプリのログインをサポートする方法の基本について説明しました。
この Codelab では、ユーザーがメールアドレスを使用して登録とログインを行えるようにしました。ただし、FirebaseUI ライブラリを使用すると、電話番号でのログインなどの他の認証方法もサポートできます。FirebaseUI ライブラリの機能と、提供されるその他の機能の活用方法について詳しくは、以下のリソースをご覧ください。
ログインに関するベスト プラクティスの詳細については、次のリソースをご覧ください。
Codelabs:
Android デベロッパー ドキュメント:
動画:
このコースの他の Codelab へのリンクについては、Kotlin を使った高度な Android 開発の Codelab のランディング ページをご覧ください。