1.登录分类
授权登录 和 一键登录
一键登录在部分设备会登录不了,报白名单错误,国外的 大多数 应用使用的是授权登录,建议使用授权登录
2.申请key
在FireBase中直接创建Android 项目,会在Google Cloud 直接生成相关的key,不需要在GoogleCloud手动创建。
会生成一个Android 和 一个 Web 的配置,需要使用 Web 的 Key。
3.授权登录
class LoginActivity : BaseActivity() {
companion object {
private const val SIGN_LOGIN = 901
/**
* google自动登录,使用的是Web的key。web项目会在Android项目生成的时候自动生成
*/
private const val SERVER_CLIENT_ID = "xxx"
}
private lateinit var auth: FirebaseAuth
private var mGoogleSignInClient: GoogleSignInClient? = null
private fun signInClient() {
if (mGoogleSignInClient == null) {
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestIdToken(SERVER_CLIENT_ID)
.build();
mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
}
}
private fun getGoogleIntent(): Intent {
var signInInten: Intent
if (mGoogleSignInClient == null) {
signInClient();
}
signInInten = mGoogleSignInClient!!.signInIntent;
return signInInten
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
auth = FirebaseAuth.getInstance()
btnLoginGoogle.setOnClickListener {
signInClient()
startActivityForResult(getGoogleIntent(), SIGN_LOGIN)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
SIGN_LOGIN -> {
val task = GoogleSignIn.getSignedInAccountFromIntent(data);
if (task == null) {
Log.d("tag", "task:null")
}
try {
val account = task.getResult(ApiException::class.java)
Log.d("tag", "id:" + account.idToken)
val firebaseCredential = GoogleAuthProvider.getCredential(account.idToken, null)
auth.signInWithCredential(firebaseCredential)
.addOnCompleteListener(this@LoginActivity) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Log.d("tag", "signInWithCredential:success")
val user = auth.currentUser
user?.getIdToken(true)
?.addOnCompleteListener(OnCompleteListener<GetTokenResult?> { task ->
if (task.isSuccessful) {
val idToken: String? = task.result.token
// 和后台交互进行登录
} else {
// Handle error -> task.getException();
}
})
} else {
// If sign in fails, display a message to the user.
Log.w("tag", "signInWithCredential:failure", task.exception)
}
}
} catch (e: ApiException) {
Log.d("tag", "task:" + e.localizedMessage)
}
}
}
}
}
4.一键登录
private val REQ_ONE_TAP = 2 // Can be any integer unique to the Activity
private lateinit var oneTapClient: SignInClient
private lateinit var signInRequest: BeginSignInRequest
oneTapClient = Identity.getSignInClient(this)
signInRequest = BeginSignInRequest.builder()
.setPasswordRequestOptions(BeginSignInRequest.PasswordRequestOptions.builder().setSupported(true).build())
.setGoogleIdTokenRequestOptions(
BeginSignInRequest.GoogleIdTokenRequestOptions.builder()
.setSupported(true)
.setServerClientId(ServerClientId)
.setFilterByAuthorizedAccounts(false)
.build()
).setAutoSelectEnabled(true).build()
//https://developers.google.com/identity/one-tap/android/get-saved-credentials
oneTapClient.beginSignIn(signInRequest)
.addOnSuccessListener(this@LoginActivity) { result ->
try {
startIntentSenderForResult(
result.pendingIntent.intentSender, REQ_ONE_TAP,
null, 0, 0, 0, null
)
} catch (e: IntentSender.SendIntentException) {
Log.e("tag", "Couldn't start One Tap UI: ${e.localizedMessage}")
}
}
.addOnFailureListener(this@LoginActivity) { e ->
// No saved credentials found. Launch the One Tap sign-up flow, or
// do nothing and continue presenting the signed-out UI.
Log.d("tag", e.localizedMessage)
}
onActivityResult
REQ_ONE_TAP -> {
try {
val credential = oneTapClient.getSignInCredentialFromIntent(data)
val idToken = credential.googleIdToken
val username = credential.id
val password = credential.password
when {
idToken != null -> {
// Got an ID token from Google. Use it to authenticate
// with your backend.
Log.d("tag", "Got ID token:" + idToken)
val firebaseCredential = GoogleAuthProvider.getCredential(idToken, null)
auth.signInWithCredential(firebaseCredential)
.addOnCompleteListener(this@LoginActivity) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Log.d("tag", "signInWithCredential:success")
val user = auth.currentUser
user?.getIdToken(true)
?.addOnCompleteListener(OnCompleteListener<GetTokenResult?> { task ->
if (task.isSuccessful) {
val idToken: String? = task.result.token
Log.d("tag", "uid: " + user.uid)
Log.d("tag", "IDToken: " + idToken)
} else {
// Handle error -> task.getException();
}
})
} else {
// If sign in fails, display a message to the user.
Log.w("tag", "signInWithCredential:failure", task.exception)
}
}
}
password != null -> {
// Got a saved username and password. Use them to authenticate
// with your backend.
Log.d("tag", "Got password.")
}
else -> {
// Shouldn't happen.
Log.d("tag", "No ID token or password!")
}
}
} catch (e: ApiException) {
// ...
}
}
5.常见错误
有可能错误是vpn的问题,检查下自己的网络
5.1 Failure16:Cannot find a matching credential.
一键登录场景下:修改了登录模式为注册登录
5.2 Failure10:Caller not whitelisted to call this API
测试账号没有加入Google Cloud
5.3 12500
检查 debug 和 release 的签名是否配置到 firebase
5.4 Firebase ID token has incorrect “aud” (audience) claim.
后台校验失败,获取到 idToken 以后还需要用 GoogleAuthProvider 的api进行二次处理
5.5 Firebase Installations Service is unavailable.
网络问题,需要在控制台才能看到错误信息,不会在登录回调里面展示。连接外网
com.google.firebase.installations.FirebaseInstallationsException: Firebase Installations Service is unavailable. Please try again later.