Android Google登录和facebook登录接入

3,888 阅读2分钟

公司接下来的项目需要用到Google登录和Facebook登录,本篇文章用来记录一下接入的流程。

Google Sign-In

Google Sign-In 官方文档

1. 创建项目

可以选择到Google API Console创建项目,或者直接在文档中创建,需要配置签名文件的SHA-1。

WeChat82a63df9f1058c9dcee29e86439cd316.png

签名文件的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和服务-凭据中找到,如图:

WeChat7d5b70ce90ac1db436c851a22537d62f.png

实现代码如下:

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()
        }
    }
}

最终实现效果如图:

google sign in.gif

Facebook 登录

Facebook登录官方文档

1. 创建项目

需要到Meta for Develpers创建项目,或者可以直接在文档中创建。

创建完应用之后在首页添加Facebook登录,如下图:

企业微信截图_d88975dd-173b-4f3a-b4b6-7f9a088927bc.png

添加完产品之后,根据快速启动的引导配置相应信息,如下图:

WeChat1fc6089221ff9bed398bc311d52f4573.png

其中需要注意的是配置秘钥散列这一步,我按照快速启动的引导,通过命令行获取到的秘钥散列是错误的,导致测试登录时失败,提示将你登入到此应用程序时出错,请稍后再试。

后续在疑难解决中找到了解决方法,不过文档提供的代码中有过时的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

配置需要用到应用编号以及客户端口令,可以在应用后台的设置-高级中找到,如图:

image.png

String.xmlAndroidManifest中添加如下代码:

<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()
    }
}

测试登录可以使用测试账号,测试账号可以在应用后台的用户身份-测试用户中创建,如图:

WeChatc1180b204dab5ff77d60d334281837cd.png

最终实现效果如图:

Facebook 登录.gif