1. はじめに
最終更新日: 2022 年 11 月 16 日
Firebase と Jetpack Compose を使用して Android アプリを作成する
この Codelab では、Make It So という Android アプリを作成します。このアプリの UI は、ネイティブ UI を構築するための Android の最新のツールキットである Jetpack Compose で完全に構築されています。直感的で、.xml ファイルを作成してアクティビティ、Fragment、ビューにバインディングするよりもコードが少なくて済みます。
Firebase と Jetpack Compose の連携について理解するための最初のステップは、最新の Android アーキテクチャを理解することです。優れたアーキテクチャでは、コンポーネントがどのように編成され、相互に通信するかが明確になるため、システムを簡単に理解、開発、維持できます。Android の世界では、推奨アーキテクチャはモデル - ビュー - ViewModel と呼ばれます。モデルは、アプリケーション内のデータにアクセスするレイヤを表します。View は UI レイヤであり、ビジネス ロジックについては何も認識できません。ViewModel はビジネス ロジックを適用する場所です。この場合、ViewModel が Model レイヤを呼び出す必要があります。
こちらの記事で、Jetpack Compose でビルドされた Android アプリに Model - View - ViewModel がどのように適用されるかを理解することを強くおすすめします。コードベースを理解しやすくなり、次のステップを簡単に完了できるようになります。
作成するアプリの概要
Make It So: タスクの追加と編集、フラグ、優先度、期限の追加、タスクの完了のマークを付けることができるシンプルな ToDo リスト アプリケーションです。次の画像は、このアプリケーションの 2 つのメインページ(タスク作成ページと、作成されたタスクのリストを含むメインページ)を示しています。
このアプリにはない機能を追加します。
- メールアドレスとパスワードでユーザーを認証する
- Firestore コレクションにリスナーを追加し、UI が変更に反応するようにする
- カスタム トレースを追加して、アプリ内の特定のコードのパフォーマンスをモニタリングする
- Remote Config を使用して機能の切り替えを作成し、段階的な公開を使用してリリースする
ラボの内容
- 最新の Android アプリで Firebase Authentication、Performance Monitoring、Firebase 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、iOS、ウェブ、Flutter、Unity 用のさまざまなアプリを作成できます。以下に示すように、Android オプションを選択します。
続いて、次の手順を実行します。
- パッケージ名として
com.example.makeitso
を入力し、必要に応じてニックネームを入力します。この Codelab では、デバッグ用の署名証明書を追加する必要はありません。 - [次へ] をクリックしてアプリを登録し、Firebase 構成ファイルにアクセスします。
- [google-services.json をダウンロード] をクリックして、構成ファイルをダウンロードし、
make-it-so-android/app
ディレクトリに保存します。 - [次へ] をクリックします。Firebase SDK はサンプル プロジェクトの
build.gradle
ファイルにすでに含まれているため、[次へ] をクリックして [次のステップ] に進みます。 - [コンソールに進む] をクリックして終了します。
Make it So アプリを正常に動作させるには、コードに進む前にコンソールで 2 つの操作を行う必要があります。認証プロバイダを有効にし、Firestore データベースを作成します。まず、ユーザーがアプリにログインできるように認証を有効にします。
- [Build] メニューから [Authentication] を選択し、[Get Started] をクリックします。
- [ログイン方法] カードで [メール/パスワード] を選択して有効にします。
- 次に、[新しいプロバイダを追加] をクリックし、[匿名] を選択して有効にします。
次に、Firestore を設定します。Firestore を使用して、ログインしているユーザーのタスクを保存します。各ユーザーには、データベースのコレクション内に独自のドキュメントが割り当てられます。
- [構築] メニューから [Firestore] を選択し、[データベースを作成] をクリックします。
- [本番環境モードで開始する] を有効にしたまま、[次へ] をクリックします。
- プロンプトが表示されたら、Cloud Firestore データを保存するロケーションを選択します。本番環境用アプリを開発する場合は、テスト環境をユーザーに近いリージョンに配置し、Functions など他の Firebase サービスとはあまり同じになるようにします。この Codelab では、デフォルトのリージョンをそのまま使用することも、お近くのリージョンを選択することもできます。
- [有効にする] をクリックして Firestore データベースをプロビジョニングします。
では、Firestore データベースに堅牢なセキュリティ ルールを作成しましょう。Firestore ダッシュボードを開き、[ルール] タブに移動します。次に、セキュリティ ルールを次のように更新します。
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow create: if request.auth != null;
allow read, update, delete: if request.auth != null && resource.data.userId == request.auth.uid;
}
}
}
これらのルールは、基本的に、アプリにログインしているユーザーはどのコレクションでも自分用のドキュメントを作成できることを意味します。いったんドキュメントを作成すると、そのドキュメントを作成したユーザーだけが、そのドキュメントを表示、更新、削除できるようになります。
アプリケーションを実行する
これで、アプリケーションを実行する準備が整いました。Android Studio で make-it-so-android/start
フォルダを開き、アプリを実行します(Android Emulator または実際の 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 つの新しいオプションが表示されます。作成した新しいアカウントは、Firebase コンソールの [Authentication] ダッシュボードで [Users] タブをクリックして確認できます。
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 コレクションにタスクが表示されます。同じアカウントで別のデバイスで ToDo リストにログインすると、ToDo リストを編集し、すべてのデバイスでリアルタイムに更新を確認できます。
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)
}
最初の行で値を取得し、その値を使用して 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 つのオプションが表示されます。
Console で値を数回変更してアプリを再起動してみてください。Remote Config を使用してアプリで新機能をリリースするのは、これほど簡単です。
7. 完了
これで、Firebase と Jetpack Compose を使用して Android アプリを作成できました。
UI に Jetpack Compose のみを使用して構築した Android アプリに、Firebase Authentication、Firebase Performance Monitoring、Firebase Remote Config、Firebase Cloud Firestore を追加し、推奨される MVVM アーキテクチャに適合させました。
参考資料
- Firebase と Compose を使用して Android アプリを作成する
- Jetpack Compose アプリに Firebase Authentication を追加する
- Jetpack Compose アプリに Cloud Firestore を追加する
- Firebase と Compose でビルドした Android アプリにコルーチンと Flow を追加する
- Jetpack Compose アプリに Firebase Performance Monitoring を追加する
- Firebase Remote Config を Jetpack Compose アプリに追加する