この Codelab について
1. はじめに
最終更新日: 2022 年 11 月 16 日
Firebase と Jetpack Compose を使用して Android アプリを構築する
この Codelab では、Make It So という Android アプリを作成します。このアプリの UI は、ネイティブ UI を作成するための Android の最新のツールキットである Jetpack Compose で完全に作成されています。直感的に操作でき、.xml ファイルを記述してアクティビティ、フラグメント、ビューにバインドするよりもコードの量が少なくなります。
Firebase と Jetpack Compose の連携の仕組みを理解する第一歩は、最新の Android アーキテクチャを理解することです。優れたアーキテクチャは、コンポーネントの構成と相互の通信方法を明確にするため、システムを理解しやすく、開発しやすく、保守しやすくします。Android の世界では、推奨アーキテクチャは Model - View - ViewModel と呼ばれます。モデルは、アプリケーション内のデータにアクセスするレイヤを表します。View は UI レイヤであり、ビジネス ロジックについて何も知るべきではありません。ViewModel はビジネス ロジックが適用される場所であり、場合によっては ViewModel が Model レイヤを呼び出す必要があります。
Model - View - ViewModel が Jetpack Compose で構築された Android アプリにどのように適用されるかを理解するために、こちらの記事を読むことを強くおすすめします。そうすることで、コードベースを理解しやすくなり、次のステップを簡単に完了できるようになります。
作成するアプリの概要
Make It So は、ユーザーがタスクの追加と編集、フラグ、優先度、期限の追加、タスクの完了マーク付けを行えるシンプルな ToDo リスト アプリケーションです。下の画像は、このアプリの 2 つのメインページ(タスク作成ページと、作成されたタスクのリストが表示されるメインページ)を示しています。
このアプリに欠けている機能をいくつか追加します。
- メールアドレスとパスワードを使用してユーザーを認証する
- Firestore コレクションにリスナーを追加し、UI が変更に対応するようにする
- カスタム トレースを追加して、アプリ内の特定のコードのパフォーマンスをモニタリングする
- Remote Config を使用して機能切り替えを作成し、段階的ロールアウトを使用してリリースする
学習内容
- 最新の Android アプリで Firebase Authentication、Performance Monitoring、Remote Config、Cloud Firestore を使用する方法
- Firebase API を MVVM アーキテクチャに適合させる方法
- Firebase API で行った変更を Compose UI に反映する方法
必要なもの
- Android Studio Flamingo 以降
- API 21 以降を搭載した Android Emulator
- Kotlin プログラミング言語に精通していること
2. サンプルアプリを入手して Firebase を設定する
サンプルアプリのコードを取得する
コマンドラインから GitHub リポジトリのクローンを作成します。
git clone https://github.com/FirebaseExtended/make-it-so-android.git
Firebase プロジェクトを作成する
まず、Firebase コンソールに移動し、下の図のように [+ プロジェクトを追加] ボタンをクリックして Firebase プロジェクトを作成します。
画面上の手順に沿ってプロジェクトの作成を完了します。
Firebase プロジェクトに Android アプリを追加する
Firebase プロジェクトでは、Android、iOS、ウェブ、Flutter、Unity 向けにさまざまなアプリを登録できます。
次のように、[Android] オプションを選択します。
続いて、次の手順を実行します。
- パッケージ名として「
com.example.makeitso
」を入力し、必要に応じてニックネームを入力します。この Codelab では、デバッグ用の署名証明書を追加する必要はありません。 - [次へ] をクリックしてアプリを登録し、Firebase 構成ファイルにアクセスします。
- [google-services.json をダウンロード] をクリックして構成ファイルをダウンロードし、
make-it-so-android/app
ディレクトリに保存します。 - [次へ] をクリックします。Firebase SDK はサンプル プロジェクトの
build.gradle
ファイルにすでに含まれているため、[次へ] をクリックして 次のステップに進みます。 - [コンソールに進む] をクリックして終了します。
Make it So アプリを正しく動作させるには、コードに進む前に、コンソールで認証プロバイダを有効にして Firestore データベースを作成する必要があります。
認証を設定する
まず、ユーザーがアプリにログインできるように、認証を有効にします。
- [ビルド] メニューから [認証] を選択し、[始める] をクリックします。
- [ログイン方法] カードで [メール/パスワード] を選択して有効にします。
- 次に、[新しいプロバイダを追加] をクリックし、[匿名] を選択して有効にします。
Cloud Firestore を設定する
次に、Firestore を設定します。Firestore を使用して、ログインしたユーザーのタスクを保存します。各ユーザーは、データベースのコレクション内に独自のドキュメントを取得します。
- Firebase コンソールの左側のパネルで、[ビルド] を展開し、[Firestore データベース] を選択します。
- [データベースを作成] をクリックします。
- [データベース ID] は
(default)
に設定したままにします。 - データベースの場所を選択し、[次へ] をクリックします。
実際のアプリでは、ユーザーに近い場所を選択します。 - [テストモードで開始] をクリックします。セキュリティ ルールに関する免責条項を確認します。
このセクションの次の手順では、データを保護するためのセキュリティ ルールを追加します。データベースのセキュリティ ルールを追加せずに、アプリを配布または公開しないでください。 - [作成] をクリックします。
Firestore データベースに堅牢なセキュリティ ルールを構築しましょう。
- Firestore ダッシュボードを開き、[ルール] タブに移動します。
- セキュリティ ルールを次のように更新します。
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /tasks/{document} {
allow create: if request.auth != null;
allow read, update, delete: if request.auth != null
&& resource.data.userId == request.auth.uid
&& request.data.userId == resource.data.userId;
}
}
}
これらのルールは基本的に、アプリにログインしているユーザーであれば、どのコレクション内でも自分のドキュメントを作成できることを意味します。作成後は、そのドキュメントを作成したユーザーのみが、そのドキュメントを表示、更新、削除できます。
アプリケーションを実行する
これで、アプリケーションを実行する準備が整いました。Android Studio で make-it-so-android/start
フォルダを開き、アプリを実行します(Android エミュレータまたは実際の Android デバイスを使用できます)。
3. Firebase Authentication
どの機能を追加しますか?
現在の Make It So サンプルアプリでは、ユーザーは最初にログインしなくてもアプリの使用を開始できます。このために匿名認証を使用します。ただし、匿名アカウントでは、他のデバイスや今後のセッションでデータにアクセスすることはできません。匿名認証はウォーム オンボーディングに便利ですが、ユーザーが別のログイン形式に切り替えられるオプションを常に提供する必要があります。この Codelab では、Make It So アプリにメールアドレスとパスワードによる認証を追加します。
コードを作成しましょう。
ユーザーがメールアドレスとパスワードを入力してアカウントを作成したら、すぐに Firebase Authentication API にメール認証情報をリクエストし、新しい認証情報を匿名アカウントにリンクする必要があります。Android Studio で AccountServiceImpl.kt
ファイルを開き、linkAccount
関数を次のように更新します。
model/service/impl/AccountServiceImpl.kt
override suspend fun linkAccount(email: String, password: String) {
val credential = EmailAuthProvider.getCredential(email, password)
auth.currentUser!!.linkWithCredential(credential).await()
}
SignUpViewModel.kt
を開き、onSignUpClick
関数の launchCatching
ブロック内でサービス linkAccount
関数を呼び出します。
screens/sign_up/SignUpViewModel.kt
launchCatching {
accountService.linkAccount(email, password)
openAndPopUp(SETTINGS_SCREEN, SIGN_UP_SCREEN)
}
まず認証を試み、呼び出しが成功すると次の画面(SettingsScreen
)に進みます。これらの呼び出しは launchCatching
ブロック内で実行されるため、1 行目でエラーが発生すると例外がキャッチされて処理され、2 行目には到達しません。
SettingsScreen
が再度開かれたら、ユーザーはすでに認証されているため、[ログイン] と [アカウントを作成] のオプションが消えていることを確認する必要があります。そのため、SettingsViewModel
が現在のユーザーのステータス(AccountService.kt
で利用可能)をリッスンして、アカウントが匿名かどうかを確認するようにします。これを行うには、SettingsViewModel.kt
の uiState
を次のように更新します。
screens/settings/SettingsViewModel.kt
val uiState = accountService.currentUser.map {
SettingsUiState(it.isAnonymous)
}
最後に、SettingsScreen.kt
の uiState
を更新して、SettingsViewModel
によって出力された状態を収集します。
screens/settings/SettingsScreen.kt
val uiState by viewModel.uiState.collectAsState(
initial = SettingsUiState(false)
)
ユーザーが変更されるたびに、SettingsScreen
が再コンポーズされ、ユーザーの新しい認証状態に応じてオプションが表示されます。
テストしてみましょう
Make it So を実行し、画面右上の歯車アイコンをクリックして設定に移動します。ここで、アカウント作成オプションをクリックします。
有効なメールアドレスと安全なパスワードを入力して、アカウントを作成します。この方法で、設定ページにリダイレクトされ、アカウントからログアウトしてアカウントを削除するための 2 つの新しいオプションが表示されます。[Users] タブをクリックすると、Firebase コンソールの [Authentication] ダッシュボードで作成された新しいアカウントを確認できます。
4. Cloud Firestore
どの機能を追加しますか?
Cloud Firestore の場合は、Make it So に表示されるタスクを表すドキュメントを保存する Firestore コレクションにリスナーを追加します。このリスナーを追加すると、このコレクションに加えられたすべての更新を受け取ります。
コードを作成しましょう。
StorageServiceImpl.kt
で使用可能な Flow
を次のように更新します。
model/service/impl/StorageServiceImpl.kt
override val tasks: Flow<List<Task>>
get() =
auth.currentUser.flatMapLatest { user ->
firestore.collection(TASK_COLLECTION).whereEqualTo(USER_ID_FIELD, user.id).dataObjects()
}
このコードは、user.id
に基づいてタスク コレクションにリスナーを追加しています。各タスクは、tasks
という名前のコレクション内のドキュメントで表されます。各ドキュメントには userId
という名前のフィールドがあります。currentUser
のステータスが変更された場合(ログアウトなど)、新しい Flow
が生成されます。
次に、TasksViewModel.kt
の Flow
がサービスと同じになるようにします。
screens/tasks/TasksViewModel.kt
val tasks = storageService.tasks
最後に、UI を表す TasksScreens.kt
の composable function
がこのフローを認識し、状態として収集するようにします。状態が変化するたびに、コンポーズ可能な関数は自動的に再コンポーズされ、最新の状態がユーザーに表示されます。TasksScreen composable function
に以下を追加します。
screens/tasks/TasksScreen.kt
val tasks = viewModel
.tasks
.collectAsStateWithLifecycle(emptyList())
コンポーズ可能な関数がこれらの状態にアクセスできるようになったら、LazyColumn
(画面にリストを表示するために使用する構造)を次のように更新します。
screens/tasks/TasksScreen.kt
LazyColumn {
items(tasks.value, key = { it.id }) { taskItem ->
TaskItem( [...] )
}
}
テストしてみましょう
動作を確認するには、アプリを使用して新しいタスクを追加します(画面右下の追加ボタンをクリックします)。タスクの作成が完了すると、Firestore コンソールの Firestore コレクションに表示されます。同じアカウントで他のデバイスの Make it So にログインすると、すべてのデバイスでリアルタイムに更新されるタスクを編集できます。
5. Performance Monitoring
どの機能を追加しますか?
パフォーマンスは非常に重要な要素です。パフォーマンスが良くなく、簡単なタスクを完了するのに時間がかかりすぎると、ユーザーはアプリの使用を諦めてしまう可能性が高くなります。そのため、アプリ内でユーザーがたどる特定のジャーニーに関する指標を収集すると便利な場合があります。Firebase Performance Monitoring には、そのためのカスタム トレースが用意されています。次の手順に沿って、カスタム トレースを追加し、Make it So のさまざまなコードのパフォーマンスを測定します。
コードを作成しましょう。
Performance.kt
ファイルを開くと、trace というインライン関数が表示されます。この関数は、Performance Monitoring API を呼び出してカスタム トレースを作成し、トレース名をパラメータとして渡します。表示されるもう 1 つのパラメータは、モニタリングするコードブロックです。各トレースで収集されるデフォルトの指標は、完全に実行されるまでの時間です。
model/service/Performance.kt
inline fun <T> trace(name: String, block: Trace.() -> T): T = Trace.create(name).trace(block)
測定するうえで重要と思われるコードベースの部分を選択し、カスタム トレースを追加できます。この Codelab で、先ほど(AccountServiceImpl.kt
で)確認した linkAccount
関数にカスタム トレースを追加する例を次に示します。
model/service/impl/AccountServiceImpl.kt
override suspend fun linkAccount(email: String, password: String): Unit =
trace(LINK_ACCOUNT_TRACE) {
val credential = EmailAuthProvider.getCredential(email, password)
auth.currentUser!!.linkWithCredential(credential).await()
}
それでは、実際に試してみましょう。Make it So アプリにカスタム トレースを追加し、次のセクションに進んで、想定どおりに動作するかどうかをテストします。
テストしてみましょう
カスタム トレースの追加が完了したら、アプリを実行し、測定する機能を数回使用します。Firebase コンソールに移動し、パフォーマンス ダッシュボードにアクセスします。画面の下部には、[ネットワーク リクエスト]、[カスタム トレース]、[画面のレンダリング] の 3 つのタブが表示されます。
[カスタム トレース] タブに移動し、コードベースに追加したトレースが表示されていることと、これらのコードの実行に通常かかる時間を確認できることを確認します。
6. Remote Config
どの機能を追加しますか?
Remote Config には、アプリの外観をリモートで変更したり、ユーザー セグメントごとに異なる動作を構成したりするなど、さまざまなユースケースがあります。この Codelab では、Remote Config を使用して、Make it So アプリで新しいタスクの編集機能をオンまたはオフにする機能切り替えを作成します。
コードを作成しましょう。
まず、Firebase コンソールで構成を作成する必要があります。これを行うには、Remote Config ダッシュボードに移動し、[パラメータを追加] ボタンをクリックします。下の図に従ってフィールドに入力します。
すべてのフィールドに入力したら、[保存] ボタンをクリックし、[公開] をクリックします。パラメータが作成され、コードベースで使用できるようになったので、新しい値を取得するコードをアプリに追加する必要があります。ConfigurationServiceImpl.kt
ファイルを開き、次の 2 つの関数の実装を更新します。
model/service/impl/ConfigurationServiceImpl.kt
override suspend fun fetchConfiguration(): Boolean {
return remoteConfig.fetchAndActivate().await()
}
override val isShowTaskEditButtonConfig: Boolean
get() = remoteConfig[SHOW_TASK_EDIT_BUTTON_KEY].asBoolean()
最初の関数はサーバーから値を取得し、アプリの起動直後に SplashViewModel.kt
で呼び出されます。これにより、すべての画面で最初から最新の値が利用できるようになります。ユーザーが何かをしている最中に UI やアプリの動作を変更すると、ユーザー エクスペリエンスが低下します。
2 番目の関数は、コンソールで作成したパラメータに公開されたブール値を返しています。また、TasksViewModel.kt
でこの情報を取得する必要があります。そのため、loadTaskOptions
関数に次のコードを追加します。
screens/tasks/TasksViewModel.kt
fun loadTaskOptions() {
val hasEditOption = configurationService.isShowTaskEditButtonConfig
options.value = TaskActionOption.getOptions(hasEditOption)
}
1 行目で値を取得し、2 行目でその値を使用してタスク アイテムのメニュー オプションを読み込んでいます。値が false
の場合、メニューに編集オプションは表示されません。オプションのリストを取得したら、UI に正しく表示する必要があります。Jetpack Compose でアプリをビルドする際は、TasksScreen
の UI の外観を宣言する composable function
を探す必要があります。TasksScreen.kt
ファイルを開き、TasksViewModel.kt
で使用可能なオプションを指すように LazyColum
を更新します。
screens/tasks/TasksScreen.kt
val options by viewModel.options
LazyColumn {
items(tasks.value, key = { it.id }) { taskItem ->
TaskItem(
options = options,
[...]
)
}
}
TaskItem
は、単一のタスクの UI をどのように表示するかを宣言する別の composable function
です。各タスクには、タスクの右端にあるその他アイコンをクリックすると表示されるオプション メニューがあります。
テストしてみましょう
これで、アプリを実行する準備が整いました。Firebase コンソールを使用して公開した値がアプリの動作と一致していることを確認します。
false
の場合は、その他アイコンをクリックしたときに 2 つのオプションのみが表示されます。true
の場合は、その他アイコンをクリックすると 3 つのオプションが表示されます。
コンソールで値を数回変更してアプリを再起動してみてください。Remote Config を使用すると、アプリで新機能を簡単にリリースできます。
7. 完了
お疲れさまでした。これで、Firebase と Jetpack Compose を使用して Android アプリを作成することができました。
UI に Jetpack Compose を使用して完全に構築された Android アプリに、Firebase Authentication、Performance Monitoring、Remote Config、Cloud Firestore を追加し、推奨される MVVM アーキテクチャに適合させました。
参考資料
- Firebase と Compose を使用して Android アプリを構築する
- Jetpack Compose アプリに Firebase Authentication を追加する
- Jetpack Compose アプリに Cloud Firestore を追加する
- Firebase と Compose で構築された Android アプリにコルーチンとフローを追加する
- Firebase Performance Monitoring を Jetpack Compose アプリに追加する
- Jetpack Compose アプリに Firebase Remote Config を追加する