1. 简介
上次更新时间:2022 年 11 月 16 日
使用 Firebase 和 Jetpack Compose 构建 Android 应用
在此 Codelab 中,您将构建一个名为 Make It So 的 Android 应用。此应用的界面完全使用 Jetpack Compose 构建,后者是 Android 用于构建原生界面的现代工具包,它直观易懂,与编写 .xml 文件并将其绑定到 activity、fragment 或 view 相比,所需的代码更少。
要了解 Firebase 和 Jetpack Compose 的协同效果,首先要了解新式 Android 架构。良好的架构可清晰地呈现组件的组织方式以及它们之间的通信方式,从而使系统易于理解、开发和维护。在 Android 世界中,推荐的架构称为 Model - View - ViewModel。模型表示应用中访问数据的层。视图是界面层,不应了解任何业务逻辑。ViewModel 是应用业务逻辑的地方,有时需要 ViewModel 调用 Model 层。
我们强烈建议您阅读这篇文章,了解如何将 Model - View - ViewModel 应用于使用 Jetpack Compose 构建的 Android 应用,因为这样可以更轻松地理解代码库,并更轻松地完成后续步骤。
构建内容
Make It So 是一款简单的待办事项列表应用,可让用户添加和修改任务、添加标记、优先级和截止日期,以及将任务标记为已完成。下图显示了此应用的两个主要页面:任务创建页面和包含已创建任务列表的主页面。
您将添加此应用中缺少的一些功能:
- 使用电子邮件和密码对用户进行身份验证
- 向 Firestore 集合添加监听器,并使界面对更改做出反应
- 添加自定义轨迹以监控应用中特定代码的性能
- 使用 Remote Config 创建功能开关,并使用分阶段发布来启动该开关
学习内容
- 如何在现代 Android 应用中使用 Firebase Authentication、Performance Monitoring、Remote Config 和 Cloud Firestore
- 如何使 Firebase API 适应 MVVM 架构
- 如何在 Compose 界面中反映使用 Firebase API 所做的更改
所需条件
- Android Studio Flamingo+
- 搭载 API 21 或更高版本的 Android 模拟器
- 熟悉 Kotlin 编程语言
2. 获取示例应用并设置 Firebase
获取示例应用的代码
从命令行克隆 GitHub 代码库:
git clone https://github.com/FirebaseExtended/make-it-so-android.git
创建 Firebase 项目
您需要做的第一件事是前往 Firebase 控制台,然后点击“+ 添加项目”按钮来创建 Firebase 项目,如下所示:
按照屏幕上的步骤完成项目创建。
将 Android 应用添加到 Firebase 项目
在 Firebase 项目中,您可以注册不同的应用:Android 应用、iOS 应用、Web 应用、Flutter 应用和 Unity 应用。
选择 Android 选项,如图所示:
然后按以下步骤操作:
- 输入
com.example.makeitso
作为软件包名称,还可以选择输入昵称。在本 Codelab 中,您无需添加调试签名证书。 - 点击下一步以注册您的应用并访问 Firebase 配置文件。
- 点击下载 google-services.json 下载配置文件,并将其保存到
make-it-so-android/app
目录中。 - 点击下一步。由于示例项目中的
build.gradle
文件已包含 Firebase SDK,因此点击下一步即可跳至后续步骤。 - 点击继续前往控制台以完成操作。
为了让 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
块内执行这些调用,因此如果第一行发生错误,系统会捕获并处理该异常,而根本不会到达第二行。
重新打开 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,然后点击屏幕右上角的齿轮图标,前往设置。然后,点击“创建账号”选项:
输入有效的电子邮件地址和安全系数高的密码,以创建账号。该链接应可正常使用,您应会被重定向到设置页面,其中会显示两个新选项:退出账号和删除账号。点击“用户”标签页,您可以在 Firebase 控制台的“身份验证”信息中心内查看新创建的账号。
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
最后,让 TasksScreens.kt
中的 composable function
(表示界面)了解此 flow 并将其作为状态进行收集。每次状态发生变化时,可组合函数都会自动重组自身,并向用户显示最新状态。将以下内容添加到 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 来创建自定义轨迹,并将轨迹名称作为参数传递。您看到的另一个参数是您要监控的代码块。为每个轨迹收集的默认指标是完成运行所需的时间:
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 控制台,并转到性能信息中心。在屏幕底部,您会看到三个标签页:网络请求、自定义轨迹和屏幕渲染。
前往自定义轨迹标签页,检查您在代码库中添加的轨迹是否显示在此处,以及您是否可以看到执行这些代码段通常需要多长时间。
6. Remote Config
您要添加哪项功能?
Remote Config 有多种使用情形,从远程更改应用的外观到为不同的细分用户群配置不同的行为,不一而足。在此 Codelab 中,您将使用 Remote Config 创建一个功能开关,用于在 Make it So 应用中显示或隐藏新的修改任务功能。
开始编码吧!
您需要做的第一件事是在 Firebase 控制台中创建配置。为此,您需要前往 Remote Config 信息中心,然后点击添加参数按钮。根据下图填写各个字段:
填写完所有字段后,您可以点击保存按钮,然后点击发布。现在,参数已创建并可供您的代码库使用,您需要向应用添加用于提取新值的代码。打开 ConfigurationServiceImpl.kt
文件并更新以下两个函数的实现:
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
中调用。这是确保从一开始所有屏幕上都显示最新值的最佳方式。如果您在用户正在执行某项操作时更改界面或应用的行为,则会带来糟糕的用户体验!
第二个函数返回的是您刚刚在控制台中为参数发布的布尔值。您需要在 TasksViewModel.kt
中检索此信息,方法是将以下代码添加到 loadTaskOptions
函数中:
screens/tasks/TasksViewModel.kt
fun loadTaskOptions() {
val hasEditOption = configurationService.isShowTaskEditButtonConfig
options.value = TaskActionOption.getOptions(hasEditOption)
}
您正在第一行中检索值,并使用该值在第二行中加载任务项的菜单选项。如果值为 false
,则表示菜单中不会包含修改选项。现在您已经有了选项列表,接下来需要让界面正确显示该列表。使用 Jetpack Compose 构建应用时,您需要查找声明 TasksScreen
界面外观的 composable function
。因此,请打开 TasksScreen.kt
文件并更新 LazyColum
以指向 TasksViewModel.kt
中提供的选项:
screens/tasks/TasksScreen.kt
val options by viewModel.options
LazyColumn {
items(tasks.value, key = { it.id }) { taskItem ->
TaskItem(
options = options,
[...]
)
}
}
TaskItem
是另一个 composable function
,用于声明单个任务的界面应如何显示。每项任务都有一个菜单,其中包含多个选项,当用户点击任务末尾的三点状图标时,系统会显示该菜单。
是时候测试了!
现在,您可以运行应用了!检查您使用 Firebase 控制台发布的值是否与应用的行为一致:
- 如果为
false
,您点击三点状图标时应该只会看到两个选项; - 如果为
true
,您应该会在点击三点状图标时看到三个选项;
尝试在管理中心内更改该值几次,然后重启应用。使用 Remote Config 在应用中发布新功能就是这么简单!
7. 恭喜
恭喜,您已成功使用 Firebase 和 Jetpack Compose 构建了一个 Android 应用!
您已向完全使用 Jetpack Compose 构建界面并符合建议的 MVVM 架构的 Android 应用添加了 Firebase Authentication、Performance Monitoring、Remote Config 和 Cloud Firestore!
深入阅读
- 使用 Firebase 和 Compose 构建 Android 应用
- 向 Jetpack Compose 应用添加 Firebase Authentication
- 将 Cloud Firestore 添加到 Jetpack Compose 应用
- 向使用 Firebase 和 Compose 构建的 Android 应用添加协程和 Flow
- 向 Jetpack Compose 应用添加 Firebase Performance Monitoring
- 向 Jetpack Compose 应用添加 Firebase Remote Config