跳到正文 Google Firebase and Authentication · Jimmy Huang's Blog
← Week 11 Guest Lecturer 学习 › C6001 › 2026 S1 › FIT5046 Mobile and distributed computing systems › Week 11 Guest Lecturer Google Firebase and Authentication Google Firebase and Authentication 本页目录· 56 条 Lab学完总结 › Overview 本周 Additional Lab 的主题是 Google Firebase and Authentication 。
这次 Lab 的主线不是做一个复杂 App,而是让我们把一个 Android Studio 项目连接到 Firebase,然后实现一个最小版本的 Google Sign-In 登录 Demo 。
你最终会完成这些事情:
在 Firebase Console 创建一个 Firebase Project
在 Firebase Project 里注册 Android App
把 google-services.json 放进 Android Studio 项目的 app/ 目录
配置 Gradle,让 Android 项目能识别 Firebase
在 Firebase Authentication 中启用 Google 登录
获取并添加 SHA-1 fingerprint
重新下载更新后的 google-services.json
在 Android App 里写一个 Google 登录 / 登出 Demo
登录成功后,在 Firebase Console 的 Authentication 用户列表中看到用户记录
这周的重点是理解:
本页目录 Google Sign-In 和 Firebase Authentication 之间是什么关系
Android 端如何通过 FirebaseAuth 判断用户是否已登录
Goal 创建并配置 Firebase Project
将 Android Studio 项目连接到 Firebase
正确添加 Google Services Gradle plugin
启用 Firebase Authentication 的 Google Provider
获取 Android 项目的 SHA-1 fingerprint
使用 Google 登录获得 ID Token
用 ID Token 登录 Firebase Authentication
在 App 中显示登录状态,并支持 Logout
在 Firebase Console 中验证用户是否真的登录成功
Task 0: 创建 Android Studio 起始项目 这一部分先准备一个干净的 Android 项目,后面所有 Firebase 配置都基于这个项目来做。
创建一个新的 Empty Activity 项目
项目名称使用 GoogleAuthentication
确认项目的 package name / namespace
知道之后 Firebase 注册 Android App 时要填哪个 package name
Step 0.1:创建 Android Studio 项目 我们先创建一个最小可运行的 Android App。后面 Firebase Auth Demo 会直接写在这个项目的 MainActivity.kt 里面。
Firebase 不是单独运行的,它需要绑定到一个具体 Android App。Firebase 识别 Android App 主要靠:
Step 0.2:确认你的 package name / namespace 打开 module-level 的 build.gradle.kts 文件:
就是你后面在 Firebase 里注册 Android App 时要填写的 Android package name 。
Firebase 里的 package name 必须和这里完全一致
大小写、单词、点号都不能错
不要填 App 名称 GoogleAuthentication
要填类似 com.example.googleauthentication 这种格式
Task 1: 在 Firebase Console 创建项目并注册 Android App 进入 Firebase Console
创建一个 Firebase Project
在 Firebase Project 中添加 Android App
填入 Android package name
暂时不填 SHA-1
下载第一次的 google-services.json
把 JSON 文件放进 Android Studio 的 app/ 目录
Step 1.1:进入 Firebase Console 如果你还没有登录 Google 账号,需要先登录。
Firebase Console 是管理 Firebase 项目的网页后台。我们后面启用 Authentication、下载配置文件、查看登录用户,都要在这里完成。
Step 1.2:创建 Firebase Project Google Analytics 可以选择开启或关闭。这个 Lab 不依赖 Analytics,所以开启或关闭都可以。
Firebase Project 可以理解成一个后端项目容器。之后 Authentication、Firestore、Storage、Cloud Messaging 等 Firebase 服务都会挂在这个 project 下面。
你的 Android App 需要连接到一个 Firebase Project,Firebase 才知道:
Step 1.3:在 Firebase Project 中添加 Android App 进入刚刚创建好的 Firebase Project 后,点击:
这个 Firebase Project 里有一个 Android App,它的 package name 是什么。
原始 Lab 的流程是先完成基础绑定,然后后面再获取 SHA-1,并重新下载更新后的 google-services.json。
Step 1.4:下载 google-services.json注册 App 后,Firebase 会提示你下载配置文件:
下载后,把它放到 Android Studio 项目的:
必须放在 app/ 目录下
不是放在项目根目录
不是放在 src/ 里面
不是放在 res/ 里面
google-services.json 是 Firebase 给这个 Android App 的配置文件。里面包含:
Firebase project id
Firebase app id
API key
OAuth client 信息
package name 信息
Android 项目本身不知道它对应哪个 Firebase Project。 google-services.json 就是把 Android App 和 Firebase Project 连接起来的配置文件。
Task 2: 配置 Android 项目的 Firebase Gradle 设置 这一部分是在 Android Studio 里完成的。
修改 libs.versions.toml
修改 project-level build.gradle.kts
修改 module-level app/build.gradle.kts
添加 Firebase BOM
Sync Gradle
Build 项目确认 Firebase 基础配置成功
Step 2.1:在 libs.versions.toml 中添加 Google Services 版本 如果你的文件里已经有 [versions],不要再新建第二个 [versions],而是把这一行放进已有的 [versions] 里面。
我们先在 version catalog 里定义 Google Services Plugin 的版本号。
现代 Android 项目经常用 libs.versions.toml 集中管理依赖和插件版本。这样后面在 build.gradle.kts 中就可以通过 libs.plugins.google.services 引用它。
Step 2.2:在 libs.versions.toml 中添加 plugin alias 为什么 google-services 会变成 libs.plugins.google.services:
在 TOML 里,连字符 - 会被 Gradle 转换成分层访问形式。
Step 2.3:在 project-level build.gradle.kts 中声明 Google Services plugin 注意:这个是项目根目录下的 build.gradle.kts,不是 app/build.gradle.kts。
project-level 的 build.gradle.kts 只是声明这个 plugin 可以被子模块使用。
因为这里不是直接把 plugin 应用到整个 project,而是先声明版本。真正要使用它的是 app module,所以后面还要在 app/build.gradle.kts 里面 apply。
Step 2.4:在 module-level app/build.gradle.kts 中应用 plugin 这里是真正把 Google Services plugin 应用到 Android App module 上。
Google Services plugin 会读取:
然后生成 Android App 运行 Firebase 所需要的资源配置。
如果你没有 apply 这个 plugin,项目可能找不到 Firebase 的配置资源,例如:
Step 2.5:添加 Firebase BOM dependency Firebase BOM 用来统一管理 Firebase 各个库的兼容版本。
Firebase Auth
Firebase Firestore
Firebase Storage
Firebase Messaging
BOM 可以帮你避免手动管理每一个 Firebase library 的版本。
Step 2.6:Sync Gradle 并 Build 项目
Task 3: 在 Firebase Console 启用 Google Authentication 这一部分让 Firebase 支持 Google 账号登录。
Step 3.1:进入 Authentication 设置页面 在 Firebase Console 左侧菜单中找到:
Firebase Authentication 是 Firebase 提供的用户登录服务。它可以支持很多登录方式,例如:
Email / Password
Google
Facebook
GitHub
Anonymous
Step 3.2:启用 Google Provider 打开 Enable toggle,选择 support email,然后点击:
这个 Project 允许用户使用 Google Account 登录。
如果你没有启用 Google Provider,Android App 即使写了 Google Sign-In 代码,Firebase 端也不会接受这种登录方式。
Task 4: 获取 SHA-1 fingerprint 并更新 Firebase 配置 Google Sign-In 经常失败,就是因为 SHA-1 没配对,或者配完后没有重新下载 google-services.json。
在 Android Studio 中运行 signingReport
找到 debug variant 的 SHA-1
把 SHA-1 添加到 Firebase Project Settings
重新下载 google-services.json
替换 app/ 目录里的旧 JSON 文件
Step 4.1:在终端运行 signingReport 在 Android Studio 右侧Gradle中运行:
如果你使用的是 PowerShell,也可以尝试:
Step 4.2:在 Firebase 中添加 SHA-1 你正在把 Android App 的签名证书 fingerprint 注册到 Firebase。
Google 登录不只看 package name,还要确认 App 的签名证书。这样可以防止其他人创建一个同 package name 的假 App 来冒充你的应用请求登录。
Step 4.3:重新下载 google-services.json添加 SHA1 后,在 Firebase 的 Android App 设置区域重新下载:
然后替换掉 Android Studio 中旧的:
你第一次下载的 google-services.json 里面还没有 SHA1 相关的 OAuth client 配置。
添加 SHA1 后,Firebase 会更新配置文件。你的 Android App 必须使用新的 JSON 文件,Google Sign-In 才能正确识别 OAuth client。
Task 5: 添加 Google Authentication dependencies 和 Client ID 这一部分开始正式写 Android 端的 Google 登录 Demo。
添加 Firebase Auth dependency
添加 Google Play Services Auth dependency
添加或确认 default_web_client_id
Sync Gradle
Step 5.1:添加 Authentication 相关 dependencies Google Sign-In 和 Firebase Authentication 不是同一个东西。
Step 5.2:找到 default_web_client_id你通常要找的是 client_type 为 3 的 OAuth client,例如:
Step 5.3:在 strings.xml 中添加 client id 原始 Lab 写的是 res > xml > strings.xml,但 Android 项目里常见路径是:
把 YOUR_CLIENT_ID 替换成你自己的 client id。
Android 代码中会通过下面这句读取这个 client id:
Google Sign-In 需要知道当前 App 请求的是哪个 OAuth client。这个 client id 用来让 Google 知道:
哪个 Firebase project
哪个 Android app
哪个 OAuth client
哪个登录请求
Step 5.4:如果出现 duplicate resource 怎么办 有些 Android/Firebase 配置中,Google Services plugin 会自动生成:
如果你手动在 strings.xml 里也加了一份,可能出现类似:
如果出现 duplicate resource,就删除 strings.xml 里手动添加的这一行:
Task 6: 编写 Google Sign-In Demo 代码 修改 MainActivity.kt
初始化 FirebaseAuth
初始化 GoogleSignInClient
点击按钮启动 Google 登录流程
获取 Google ID token
用 token 登录 Firebase
登录成功后显示用户名
点击 Logout 登出
Step 6.1:打开 MainActivity.kt下面代码第一行的 package 需要改成你自己的 package name。
如果你不确定 package name,就看你当前 MainActivity.kt 文件最上面的第一行,保留它即可。
Step 6.2:替换 MainActivity.kt 代码 把 MainActivity.kt 替换为下面代码。
Step 6.3:代码在做什么
1. FirebaseAuth.getInstance()这句用来拿到 Firebase Authentication 的入口对象。
2. GoogleSignInOptions登录成功后,我不仅要 Google account 信息,还要一个 ID token。
Firebase 不能直接相信 App 说“这个用户是某某 Google 用户”。Firebase 需要 Google 给出的 token 来验证这个用户身份。
3. signInLauncher这段用来启动 Google 登录页面,并接收登录结果。
Google 登录会打开一个新的登录界面。用户选择账号后,结果会返回到 App。 signInLauncher 就是负责处理这个返回结果的。
4. firebaseAuthWithGoogle(idToken)把 Google ID token 转成 Firebase credential
用 credential 登录 Firebase Authentication
5. userName
Task 7: 运行 App 并验证 Google 登录 这一部分要真正运行 App,完成登录,并在 Firebase Console 里验证。
Build App
Run App
点击 Google 登录按钮
选择 Gmail 账号
登录成功后看到用户名
Firebase Console 中看到用户
测试 Logout
Step 7.1:Build 项目 没有 Gradle dependency 错误
没有 Kotlin compile error
App 可以安装到 emulator 或真机
Step 7.2:运行 App 点击 Android Studio 顶部绿色 Run 按钮。
Step 7.3:如果 Run 运行了 signingReport 而不是 App 如果你刚刚运行过 Gradle 的 signingReport,Android Studio 的 Run Configuration 可能还停留在 signingReport。
确认 Run Configuration 是你的 Android App,而不是:
如果没有 App configuration,就重新添加一个 Android App run configuration。
Android Studio 顶部绿色 Run 按钮有时候会记住你上一次运行的是 Gradle task。我们现在要运行 App,不是运行 Gradle task。
截图占位:这里放 Run Configuration 指向 Android App 的截图
Step 7.4:点击 Google 登录按钮
Step 7.5:在 Firebase Console 验证用户 Provider:Google
Identifier:用户邮箱
Created:创建时间
Signed in:最近登录时间
User UID
这一步不是只看 App UI,而是去 Firebase 后台确认:
这个 Google 用户真的已经被 Firebase Authentication 记录了。
App 页面显示用户名只能说明前端状态变化了。Firebase Console 中出现用户,才说明 Firebase Authentication 登录流程真正成功。
Step 7.6:测试 Logout
Summary 这周 Lab 的核心不是 UI,而是理解 Android App 和 Firebase Authentication 的连接流程。
google-services.json 负责让 Android App 找到 Firebase Project
SHA-1 负责证明这个 App 的签名身份
Google Provider 负责允许 Google 账号登录
GoogleSignInClient 负责打开 Google 登录流程
FirebaseAuth 负责把 Google token 变成 Firebase 用户
Firebase Console 的 Users 列表是最终验证点
本周必须理解的知识点
1. Firebase Project 和 Android App 注册不是一回事 Firebase Project 是后端项目容器。
Android App 注册是告诉 Firebase:
一个 Firebase Project 可以有多个 App,例如:
Android App
iOS App
Web App
2. google-services.json 是 Android App 和 Firebase 的连接文件 google-services.json 里面包含 Firebase 配置信息。
project id
app id
API key
OAuth client
package name
如果这个文件放错位置,Firebase 配置通常会失败。
3. SHA-1 是 Google 登录经常失败的关键点 所以只填 package name 不够,还需要 SHA-1。
Google 登录失败
Firebase Auth 登录失败
出现 DEVELOPER_ERROR
token 获取失败
4. 添加 SHA-1 后必须重新下载 JSON 如果不重新下载,Android App 仍然使用旧配置,可能无法正确完成 Google 登录。
5. Google Sign-In 和 Firebase Authentication 的区别
关键概念对比
Firebase Project vs Android App
google-services.json vs Google Services Plugin
GoogleSignInClient vs FirebaseAuth com.example.googleauthenticationhttps://firebase.google.comGet started by setting up a Firebase projectProject name: google-authAndroid package name: 你的 namespace
App nickname: GoogleAuthenticationAndroid package name: com.example.googleauthentication
App nickname: GoogleAuthenticationGoogleAuthentication/
├── app/
│ ├── google-services.json
│ ├── build.gradle.kts
│ └── src/
├── build.gradle.kts
├── gradle/
└── settings.gradle.ktsgradle/libs.versions.toml[versions]
agp = "8.13.0"
kotlin = "2.0.21"
googleServices = "4.4.3"gradle/libs.versions.tomlgoogle-services = {id = "com.google.gms.google-services",version.ref = "googleServices" }[plugins]
android-application = {id = "com.android.application",version.ref = "agp" }
kotlin-android = {id = "org.jetbrains.kotlin.android",version.ref = "kotlin" }
kotlin-compose = {id = "org.jetbrains.kotlin.plugin.compose",version.ref = "kotlin" }
google-services = {id = "com.google.gms.google-services",version.ref = "googleServices" }default_web_client_id
google_app_idFile → Sync Project with Gradle FilesVariant: debug
Config: debug
Store: ...
Alias: AndroidDebugKey
MD5: ...
SHA1: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX
SHA-256: ...Google Sign-In 负责让用户选择 Google 账号
Firebase Authentication 负责把这个 Google 账号变成 Firebase 用户app/src/main/res/values/strings.xmlDuplicate resources
default_web_client_idapp/src/main/java/你的/package/name/MainActivity.ktapp/src/main/java/com/example/googleauthentication/MainActivity.ktGoogle Account → ID Token → Firebase Credential → Firebase UserRun → Edit Configurations...Build → Authentication → UsersAndroid Studio 创建 App
↓
Firebase Console 创建 Firebase Project
↓
Firebase 中注册 Android App package name
↓
下载 google-services.json 放进 app/
↓
配置 Google Services Gradle plugin
↓
启用 Firebase Authentication 的 Google Provider
↓
获取 SHA-1 fingerprint
↓
把 SHA-1 加到 Firebase
↓
重新下载 google-services.json
↓
Android 端使用 GoogleSignInClient 发起登录
↓
Google 返回 ID token
↓
FirebaseAuth 使用 ID token 登录
↓
Firebase Console Authentication Users 出现用户这个 Firebase Project 下面有一个 Android App
它的 package name 是 xxxpackage name + signing certificate第一次下载 google-services.json
↓
获取 SHA-1
↓
Firebase 添加 SHA-1
↓
重新下载 google-services.json
↓
替换 app/ 下旧文件负责让用户选择 Google 账号,并返回 Google ID token负责验证这个 token,并在 Firebase 中创建 / 登录用户Google 登录成功
↓
拿到 ID token
↓
Firebase 用 token 登录
↓
Firebase Authentication Users 出现用户android { namespace = "com.example.googleauthentication" } alias(libs.plugins.google.services) libs.plugins.google.services alias(libs.plugins.google.services) apply false plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.compose) apply false alias(libs.plugins.google.services) apply false } alias(libs.plugins.google.services) plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.compose) alias(libs.plugins.google.services) } implementation(platform( "com.google.firebase:firebase-bom:34.3.0" )) dependencies { implementation(platform( "com.google.firebase:firebase-bom:34.3.0" )) implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.ui) implementation(libs.androidx.material3) } gradlew.bat assembleDebug gradlew.bat signingReport implementation( "com.google.firebase:firebase-auth:23.0.0" ) implementation( "com.google.android.gms:play-services-auth:21.0.0" ) dependencies { implementation(platform( "com.google.firebase:firebase-bom:34.3.0" )) implementation( "com.google.firebase:firebase-auth:23.0.0" ) implementation( "com.google.android.gms:play-services-auth:21.0.0" ) implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.ui) implementation(libs.androidx.material3) } { " client_id " : " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com " , " client_type " : 3 } < string name= " default_web_client_id " >YOUR_CLIENT_ID</ string > < resources > < string name= " app_name " >GoogleAuthentication</ string > < string name= " default_web_client_id " >xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com</ string > </ resources > getString(R.string.default_web_client_id) < string name= " default_web_client_id " >...</ string > package com.example.googleauthentication import android.app.Activity import android.content.Intent import android.os.Bundle import android.util.Log import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.material3.Button import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.google.android.gms.auth.api.signin.GoogleSignIn import com.google.android.gms.auth.api.signin.GoogleSignInClient import com.google.android.gms.auth.api.signin.GoogleSignInOptions import com.google.android.gms.common.api.ApiException import com.google.firebase.auth.FirebaseAuth import com.google.firebase.auth.GoogleAuthProvider class MainActivity : ComponentActivity() { private lateinit var googleSignInClient: GoogleSignInClient private lateinit var auth: FirebaseAuth private var userName by mutableStateOf<String?>(null) private val signInLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> if (result.resultCode == Activity.RESULT_OK) { val data : Intent? = result. data val task = GoogleSignIn.getSignedInAccountFromIntent( data ) try { val account = task.getResult(ApiException::class.java) val idToken = account.idToken if (idToken != null) { firebaseAuthWithGoogle(idToken) } else { Toast.makeText( this, "No ID token returned." , Toast.LENGTH_SHORT ).show() } } catch (e: ApiException) { Log.w( "GoogleSignIn" , "Google sign in failed" , e) Toast.makeText( this, "Google sign in failed." , Toast.LENGTH_SHORT ).show() } } else { Log.w( "GoogleSignIn" , "Google sign in cancelled or failed." ) } } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) auth = FirebaseAuth.getInstance() val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(getString(R.string.default_web_client_id)) .requestEmail() .build() googleSignInClient = GoogleSignIn.getClient(this, gso) auth.currentUser?.let { user -> userName = user.displayName } setContent { MaterialTheme { GoogleSignInDemo( userName = userName, onSignInClick = { signIn() }, onSignOutClick = { signOut() } ) } } } private fun signIn() { val signInIntent = googleSignInClient.signInIntent signInLauncher.launch(signInIntent) } private fun firebaseAuthWithGoogle(idToken: String) { val credential = GoogleAuthProvider.getCredential(idToken, null) auth.signInWithCredential(credential) .addOnCompleteListener(this) { task -> if (task.isSuccessful) { val user = auth.currentUser userName = user?.displayName Toast.makeText( this, "Welcome ${ user?.displayName } " , Toast.LENGTH_SHORT ).show() } else { Toast.makeText( this, "Authentication Failed." , Toast.LENGTH_SHORT ).show() } } } private fun signOut() { auth.signOut() googleSignInClient.signOut().addOnCompleteListener { userName = null Toast.makeText( this, "Signed Out Successfully." , Toast.LENGTH_SHORT ).show() } } } @Composable fun GoogleSignInDemo( userName: String?, onSignInClick: () -> Unit, onSignOutClick: () -> Unit ) { Box( modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { if (userName == null) { Button( onClick = onSignInClick, modifier = Modifier .fillMaxWidth(0.6f) .height(50.dp) ) { Text(text = "Sign in with Google" ) } } else { Column( horizontalAlignment = Alignment.CenterHorizontally ) { Text(text = "Hello,$userName!" ) Spacer(modifier = Modifier.height(16.dp)) Button( onClick = onSignOutClick, modifier = Modifier .fillMaxWidth(0.6f) .height(50.dp) ) { Text(text = "Logout" ) } } } } } auth = FirebaseAuth.getInstance() auth.signInWithCredential(...) auth.signOut() auth.currentUser val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(getString(R.string.default_web_client_id)) .requestEmail() .build() .requestIdToken(getString(R.string.default_web_client_id)) private val signInLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> ... } private fun firebaseAuthWithGoogle(idToken: String) { val credential = GoogleAuthProvider.getCredential(idToken, null) auth.signInWithCredential(credential) .addOnCompleteListener(this) { task -> ... } } private var userName by mutableStateOf<String?>(null)