公司接下来的项目需要用到Google登录和Facebook登录,本篇文章用来记录一下接入的流程。
Google Sign-In
1. 创建项目
可以选择到Google API Console创建项目,或者直接在文档中创建,需要配置签名文件的SHA-1。
签名文件的SHA值,我一般是在AndroidStudio的Terminal中通过如下代码获取:
keytool -list -v -keystore YOUR_KEY_PATH
YOUR_KEY_PATH是签名文件的完整路径包含后缀名。
2. 添加依赖
在项目app module的build.gradle中的dependencies中添加依赖:
dependencies {
implementation 'com.google.android.gms:play-services-auth:20.2.0'
}
3. 添加登录
文档中登录的方式有两种,一种是添加SDK提供的登录按钮,另一种是通过调用API来登录。
登录按钮与我项目中的需求并不适配,所以我采用的是API的方式。
3.1 检查现有的登录用户
Google Sign-In提供了检查现在是否已有登录账号的API,可以根据App业务决定是否使用,代码如下:
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(context);
3.2 登录API
登录API会用到ServerClientId,可以在应用后台的API和服务-凭据中找到,如图:
实现代码如下:
const val TAG = "TripartiteLogin"
class TripartiteLoginActivity : AppCompatActivity() {
private val googleLoginLauncher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result ->
Log.i(TAG, "google login get account info result.resultCode:${result.resultCode}")
if (result.resultCode == Activity.RESULT_OK) {
try {
val credential = Identity.getSignInClient(this).getSignInCredentialFromIntent(result.data)
showToast("Google login success id:${credential.id}")
Log.i(TAG, "google login get account info id:${credential.id}")
Log.i(TAG, "google login get account info googleIdToken:${credential.googleIdToken}")
Log.i(TAG, "google login get account info password:${credential.password}")
Log.i(TAG, "google login get account info givenName:${credential.givenName}")
Log.i(TAG, "google login get account info familyName:${credential.familyName}")
Log.i(TAG, "google login get account info displayName:${credential.displayName}")
Log.i(TAG, "google login get account info profilePictureUri:${credential.profilePictureUri}")
} catch (exception: ApiException) {
Log.e(TAG, "google login get account info error :${exception.message}")
exception.printStackTrace()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<LayoutTripartiteLoginActivityBinding>(this, R.layout.layout_tripartite_login_activity)
binding.btnGoogleLogin.setOnClickListener {
checkGoogleLoginAccount()
}
binding.btnGoogleLogout.setOnClickListener {
googleLogout()
}
}
private fun checkGoogleLoginAccount() {
val lastLoginAccountInfo = GoogleSignIn.getLastSignedInAccount(this)
if (lastLoginAccountInfo == null) {
googleLogin()
}
}
private fun googleLogin() {
val signInRequest = GetSignInIntentRequest.builder()
.setServerClientId(“ServerClientId”)
.build()
Identity.getSignInClient(this)
.getSignInIntent(signInRequest)
.addOnSuccessListener { pendingIntent ->
Log.i(TAG, "google call login success")
googleLoginLauncher.launch(IntentSenderRequest.Builder(pendingIntent).build())
}
.addOnFailureListener {
Log.i(TAG, "google call login failed message:${it.message}")
}
}
private fun googleLogout() {
Identity.getSignInClient(this)
.signOut()
.addOnSuccessListener {
Log.i(TAG, "google call logout success")
showToast("Google logout success")
}
}
private fun showToast(message: String) {
runOnUiThread {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
}
}
最终实现效果如图:
Facebook 登录
1. 创建项目
需要到Meta for Develpers创建项目,或者可以直接在文档中创建。
创建完应用之后在首页添加Facebook登录,如下图:
添加完产品之后,根据快速启动的引导配置相应信息,如下图:
其中需要注意的是配置秘钥散列这一步,我按照快速启动的引导,通过命令行获取到的秘钥散列是错误的,导致测试登录时失败,提示将你登入到此应用程序时出错,请稍后再试。
后续在疑难解决中找到了解决方法,不过文档提供的代码中有过时的API,调整后代码如下:
private fun checkKeyStoreHash() {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val info = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES)
val signingInfo = info.signingInfo
val apkContentsSigners = signingInfo.apkContentsSigners
for (signature in apkContentsSigners) {
val md: MessageDigest = MessageDigest.getInstance("SHA")
md.update(signature.toByteArray())
val keyStoreHash = encodeToString(md.digest(), DEFAULT)
}
}
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
}
}
添加代码后安装签名过的apk,可以在日志中看到秘钥散列。
2. 添加依赖
在项目app module的build.gradle中的dependencies中添加依赖:
dependencies {
implementation 'com.facebook.android:facebook-login:13.2.0'
}
3. 配置Manifest
配置需要用到应用编号以及客户端口令,可以在应用后台的设置-高级中找到,如图:
在String.xml和AndroidManifest中添加如下代码:
<resources>
<string name="facebook_app_id">应用编号</string>
<string name="fb_login_protocol_scheme">fb应用编号</string>
<string name="facebook_client_token">客户端口令</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<application >
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id" />
<meta-data
android:name="com.facebook.sdk.ClientToken"
android:value="@string/facebook_client_token" />
<activity
android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation" />
<activity
android:name="com.facebook.CustomTabActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="@string/fb_login_protocol_scheme" />
</intent-filter>
</activity>
</application>
</manifest>
4. 添加登录
Facebook登录同样有登录按钮以及API两种方式,我使用的是API方式。
4.1 检查现有的登录用户
Facebook登录提供了检查现在是否已有登录账号的API,可以根据App业务决定是否使用,代码如下:
boolean currentAccessTokenActive = AccessToken.isCurrentAccessTokenActive()
4.2 登录API
实现代码如下:
const val TAG = "TripartiteLogin"
class TripartiteLoginActivity : AppCompatActivity() {
private lateinit var metaCallbackManager: CallbackManager
private lateinit var profileTracker: ProfileTracker
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<LayoutTripartiteLoginActivityBinding>(this, R.layout.layout_tripartite_login_activity)
metaCallbackManager = CallbackManager.Factory.create()
LoginManager.getInstance().registerCallback(metaCallbackManager, object : FacebookCallback<LoginResult> {
override fun onSuccess(result: LoginResult) {
Log.i(TAG, "Meta login success")
Log.i(TAG, "Meta login account info userId:${result.accessToken.userId}")
Log.i(TAG, "Meta login account info token:${result.accessToken.token}")
Log.i(TAG, "Meta login account info applicationId:${result.accessToken.applicationId}")
showToast("Meta login success userId:${result.accessToken.userId}")
}
override fun onCancel() {
Log.i(TAG, "Meta login canceled")
}
override fun onError(error: FacebookException) {
Log.e(TAG, "Meta login failed error:${error.message}")
}
})
profileTracker = object : ProfileTracker() {
override fun onCurrentProfileChanged(oldProfile: Profile?, currentProfile: Profile?) {
currentProfile?.run {
Log.i(TAG, "Meta onCurrentProfileChanged id:$id")
Log.i(TAG, "Meta onCurrentProfileChanged firstName:$firstName")
Log.i(TAG, "Meta onCurrentProfileChanged middleName:$middleName")
Log.i(TAG, "Meta onCurrentProfileChanged lastName:$lastName")
Log.i(TAG, "Meta onCurrentProfileChanged name:$name")
Log.i(TAG, "Meta onCurrentProfileChanged pictureUri:$pictureUri")
}
}
}
//开始跟踪用户信息变化
profileTracker.startTracking()
binding.btnFacebookLogin.setOnClickListener {
metaLogin()
}
binding.btnFacebookLogout.setOnClickListener {
metaLogout()
}
}
private fun metaLogin() {
val currentAccessTokenActive = AccessToken.isCurrentAccessTokenActive()
Log.i(TAG, "Meta login current AccessToken active :$currentAccessTokenActive")
if (!currentAccessTokenActive) {
LoginManager.getInstance().logIn(this, metaCallbackManager, listOf("public_profile"))
}
}
private fun metaLogout() {
Log.i(TAG, "Meta call logout")
LoginManager.getInstance().logOut()
showToast("Meta logout success")
}
private fun showToast(message: String) {
runOnUiThread {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
}
override fun onDestroy() {
LoginManager.getInstance().unregisterCallback(metaCallbackManager)
profileTracker.stopTracking()
super.onDestroy()
}
}
测试登录可以使用测试账号,测试账号可以在应用后台的用户身份-测试用户中创建,如图:
最终实现效果如图: