この Codelab は、Kotlin での高度な Android 開発コースの一部です。Codelab を順番に進めていくと、このコースを最大限に活用できますが、これは必須ではありません。すべてのコース Codelab は Kotlin での Codelab の高度な Codelab のランディング ページに掲載されています。
はじめに
Android アプリを作成する場合、ユーザーのログインをサポートすることには多くの利点があります。アプリ内でユーザー自身に ID の作成を許可することで、アプリ内でのエンゲージメントをさらに促進できます。
カスタマイズ アカウントを使用すると、ユーザーは別のデバイス(ウェブや新しいスマートフォンなど)でアプリを使用している場合に、アプリ内エクスペリエンスのカスタマイズ、他のユーザーとの交流、データの保持と転送を行うことができます。
この Codelab では、FirebaseUI ライブラリを使用してアプリのログインをサポートする基本的な方法について学習します。とりわけ、FirebaseUI ライブラリにより、ログインフローを構築し、ユーザー アカウントを管理する作業を簡単に行えるようになります。
前提となる知識
- Android アプリの作成方法の基礎
- LiveData と ViewModel
学習内容
- プロジェクトに Firebase を追加する方法
- Android アプリのログインをサポートする方法
- アプリの現在の認証ステータスを確認する方法
- ユーザーのログアウト方法
演習内容
- Firebase コンソールを使用して、アプリに Firebase を統合します。
- ログイン機能を実装します。
- ログイン ユーザー向けにアプリをカスタマイズします。
- ユーザーのログアウトを実装します。
LiveData と ViewModel の詳細
この Codelab のアプリについては、LiveData と ViewModel に関する基本的な知識が必要です。これらのコンセプトの簡単な概要が必要な場合は、LiveData と ViewModel の概要を確認してください。
また、この Codelab の一環として学習する、Android アプリの基本的なトピックについて学ぶ「Kotlin による Android アプリの開発」コースの受講も可能です。このコースは、Udacity コースと Codelab コースの両方として利用できます。
この Codelab では、Android のおもしろい情報を表示するアプリを作成します。さらに重要なのは、アプリにログイン/ログアウト ボタンが表示されることです。ユーザーがアプリにログインすると、表示される Android データには、カスタマイズの手段としてユーザーに挨拶する内容が含まれています。
次のいずれかの方法でサンプルアプリをダウンロードします。
または、次のコマンドを使用して GitHub リポジトリのクローンを作成し、リポジトリの start
ブランチに切り替えます。
$ git clone https://github.com/googlecodelabs/android-kotlin-login
重要: Firebase を使用するためにアプリを統合するため、スターター アプリのビルドと実行にはセットアップが必要です。これは Codelab の次のステップで行います。
ステップ 1: Firebase プロジェクトを作成する
Android アプリに Firebase を追加する前に、Android アプリに接続するための Firebase プロジェクトを作成します。
- Firebase コンソールで [プロジェクトを追加] をクリックします。
- [Project name] を選択または入力します。プロジェクトには任意の名前を付けることができますが、作成中のアプリに関連する名前を選んでください。
- [続行] をクリックします。
- Google アナリティクスの設定をスキップし、[後で] オプションを選択することもできます。
- [プロジェクトを作成] をクリックして、Firebase プロジェクトの設定を完了します。
ステップ 2: アプリを Firebase に登録する
Firebase プロジェクトが作成されたので、Android アプリを追加できます。
- Firebase コンソールの [プロジェクトの概要] ページの中央にある Android アイコンをクリックして設定ワークフローを起動します。
- アプリのアプリケーション ID を [Android パッケージ名] に入力します。アプリが使用している ID を入力してください。この値は、アプリを Firebase プロジェクトに登録した後で追加、変更することはできません。
- アプリケーション ID はパッケージ名とも呼ばれます。
- モジュール(アプリレベル)の Gradle ファイルでこのアプリケーション ID を見つけます。通常は
app/build.gradle
です(例: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 ライブラリを追加する必要があります。
build.gradle (Module:app)
ファイルに次の依存関係を追加して、アプリで SDK を使用できるようにします。firebase-auth
SDK を使用すると、アプリケーションの認証済みユーザーを管理できます。
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 が含まれます。(受講者は、フォローアップ Codelab で LoginFragment
と SettingsFragment
を使用します)。
- コードについてよく理解します。特に、以下の点に注意してください。
FirebaseUserLiveData
は、アプリに関連付けられている現在の Firebase ユーザーを監視するために実装するクラスです。FirebaseAuth
インスタンスをエントリ ポイントとして使用し、後のステップでこのユーザー情報を取得します。MainFragment
はLoginViewModel
に関連付けられています。LoginViewModel
は、FirebaseUserLiveData
を利用してauthenticationState
変数を作成するために実装するクラスです。MainFragment
では、このauthenticationState
変数を使用して値をモニタリングすることで、それに応じて UI を更新できます。
このステップでは、Firebase コンソールを使用して、アプリがサポートする認証方法を設定します。この Codelab では、ユーザーが自分のメールアドレスまたは Google アカウントでログインできるようにします。
- Firebase コンソールに移動します。(注: [Firebase を追加] ワークフローを開いている場合は、左上の [X] をクリックしてコンソールに戻ります。
- まだプロジェクトに参加していない場合は、プロジェクトを選択します。
- 左側のナビゲーションを開き、[Develop & & Authentication] を選択します。
- 上部のナビゲーション バーにある [Sign-in method] タブを選択します。
- [Email/Password] 行をクリックします。
- ポップアップで [有効] スイッチを切り替え、[保存] をクリックします。
- 同様に、[Google] 行をクリックします。
- [有効] スイッチを切り替えて、[プロジェクトのサポートメール] を入力し、[保存] をクリックします。
このタスクでは、ユーザー向けにログイン機能を実装します。
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 アカウントを使用してログインできるようになりました。
- ログイン後に 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
に [Logout] と表示されます。
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
は [Login] を表示し、クリック時にログイン画面を起動します。また、メッセージをカスタマイズしないようにする必要があります。
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] と表示されます。
このタスクでは、ログアウト機能を実装します。
このアプリではユーザーがログインできるため、ログアウトする方法も提示する必要があります。ユーザーを 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 ライブラリの機能と、このライブラリが提供するその他の機能の使用方法について詳しくは、以下のリソースをご覧ください。
ログインに関するその他のベスト プラクティスについて詳しくは、以下のリソースをご覧ください。
Codelab:
Android デベロッパー ドキュメント:
動画:
このコースの他の Codelab へのリンクについては、Kotlin Codelab の高度な Codelab のランディング ページをご覧ください。