Android运用Kotlin封装海外登录东西类
前言:
之前因为项目做国际化,所以需求接入Google、FaceBook、Twitter等各种第三方登录的Api,所以查找官网材料,申请各种key和密钥,最后成功完成了这三个第三方登录Api的功用,但是因为许多当地需求调用,前期做得很粗糙,发现调用很麻烦,所以做了一次封装,总结一下,关于材料的申请这儿就不说了.如果是海外或许有vpn的小伙伴能够集成各种key后直接测验,国内你懂的. 本文选用的是Kotlin语法,直接上封装的代码:
1.装备google依靠:
// google
"play-services-auth" : 'com.google.android.gms:play-services-auth:19.0.0',
"play-services-wallet" : 'com.google.android.gms:play-services-wallet:18.1.2',
"play-services-base" : 'com.google.android.gms:play-services-base:17.6.0',
"play-services-analytics" : 'com.google.android.gms:play-services-analytics:17.0.0',
"google-pay" : 'com.android.billingclient:billing:4.0.0',
"google-ar" : 'com.google.ar:core:1.11.0',
2.装备FaceBook依靠:
// Facebook Core only (Analytics)
"facebook-core" : 'com.facebook.android:facebook-core:8.1.0',
// Facebook Login only
"facebook-login" : 'com.facebook.android:facebook-login:8.1.0',
// Facebook Share only
"facebook-share" : 'com.facebook.android:facebook-share:8.1.0',
// Facebook Messenger only
"facebook-messenger" : 'com.facebook.android:facebook-messenger:8.1.0',
// Facebook App Links only
"facebook-applinks" : 'com.facebook.android:facebook-applinks:8.1.0',
// Facebook Android SDK (everything)
"facebook-android-sdk" : 'com.facebook.android:facebook-android-sdk:8.1.0',
3.装备Twitter依靠
:
//twitter
"twitter" : 'com.twitter.sdk.android:twitter:3.3.0',
"tweet-composer" : 'com.twitter.sdk.android:tweet-composer:3.3.0',
"colorfulText" : 'org.zhx.common:colorfulText:1.0.0'
4.在build.gradle导入依靠:
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
api rootProject.ext.dependencies["facebook-login"]
api rootProject.ext.dependencies["facebook-core"]
api rootProject.ext.dependencies["play-services-auth"]
api rootProject.ext.dependencies["play-services-wallet"]
api rootProject.ext.dependencies["twitter"]
api rootProject.ext.dependencies["tweet-composer"]
}
5.接入Google、Facebook、Twitter:
Google、Facebook、Twitter之前需求装置Google服务,所以首要需求判别用户是否装置Google服务插件,这儿说特别阐明一下,一定要装置官网的正版Google服务插件,要不然会呈现各种问题,这儿就不展开了.检测用户是否装置Google服务的办法如下:
/**
* 查看用户是否装置Google Play 服务
*/
open fun onCheckGooglePlayService(activity:Activity,code:Int){
// 验证是否已在此设备上装置并启用Google Play服务,以及此设备上装置的旧版本是否为此客户端所需的版本
GoogleApiAvailability.getInstance().makeGooglePlayServicesAvailable(activity)
/**
* 经过isUserResolvableError来确认是否能够经过用户操作处理错误
*/
if (GoogleApiAvailability.getInstance().isUserResolvableError(code)) {
GoogleApiAvailability.getInstance().getErrorDialog(activity, code, 200).show()
}
fun checkGooglePlayServiceExist(activity: Activity): Int {
return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(activity)
}
6.Google登录东西类的封装:
/**
* @author: njb
* @date: 2021/5/8 14:37
* @desc: Google登录东西类
*/
open class GoogleLoginUtils(private val activity: Activity, var listener: GoogleSignListener) {
var requestCode = 10
private var mGoogleSignInClient: GoogleSignInClient? = null
private var googleSignListener: GoogleSignListener? = null
init {
//初始化谷歌登录服务
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build()
mGoogleSignInClient = GoogleSignIn.getClient(activity, gso)
}
/**
* 登录
*/
open fun signIn() {
val signInIntent: Intent = mGoogleSignInClient!!.signInIntent
activity.startActivityForResult(signInIntent, requestCode)
}
/**
* 退出登录
*/
open fun signOut() {
}
fun handleSignInResult(completedTask: Task<GoogleSignInAccount>) {
try {
val account: GoogleSignInAccount? = completedTask.getResult(ApiException::class.java)
val status: Task<GoogleSignInAccount> = completedTask
if (status.isSuccessful) {
if (account != null) {
//ToastUtils.showShort(activity.getString(R.string.login_success))
googleSignListener?.googleLoginSuccess(account)
LogUtils.d("account" + account?.account)
} else {
googleSignListener?.googleLoginFail(activity.getString(R.string.login_failed))
}
}
} catch (e: ApiException) {
LogUtils.d("signInResult:failed code=" + e.statusCode)
}
}
open fun setGoogleSignListener(googleSignListener: GoogleSignListener?) {
this.googleSignListener = googleSignListener
}
interface GoogleSignListener {
fun googleLoginSuccess(account: GoogleSignInAccount)
fun googleLoginFail(message: String?)
fun googleLogoutSuccess()
fun googleLogoutFail()
}
/**
* 查看 Google Play 服务
*/
open fun onCheckGooglePlayServices(activity: Activity, code: Int) {
// 验证是否已在此设备上装置并启用Google Play服务,以及此设备上装置的旧版本是否为此客户端所需的版本
GoogleApiAvailability.getInstance().makeGooglePlayServicesAvailable(activity)
/**
* 经过isUserResolvableError来确认是否能够经过用户操作处理错误
*/
if (GoogleApiAvailability.getInstance().isUserResolvableError(code)) {
GoogleApiAvailability.getInstance().getErrorDialog(activity, code, 200).show()
}
}
fun checkGooglePlayServiceExist(activity: Activity): Int {
return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(activity)
}
}
7.FaceBook登录东西类的封装:
/**
*@author: njb
*@date: 2021/5/8 14:26
*@desc: FaceBook登录东西类
*/
open class FacebookLoginUtils(private val activity: Activity) {
private var loginManager: LoginManager? = null
private val permissions: List<String>
private var callbackManager: CallbackManager? = null
private var requestSuccessCode = 2896
private var requestCancelCode = 2897
private var requestFailedCode = 2898
private var mFaceBookLoginListener: FaceBookLoginListener? = null
var infoBean: FaceLoginInfoBean? = null
init {
//初始化facebook登录服务
callbackManager = CallbackManager.Factory.create()
getLoginManager().registerCallback(callbackManager, object : FacebookCallback<LoginResult> {
override fun onSuccess(result: LoginResult?) {
activity.setResult(requestSuccessCode)
getLoginInfo(result?.accessToken)
}
override fun onCancel() {
activity.setResult(requestCancelCode)
mFaceBookLoginListener?.onLoginCancel(activity.getString(R.string.login_cancel))
}
override fun onError(error: FacebookException?) {
activity.setResult(requestFailedCode)
mFaceBookLoginListener?.onLoginFail(error?.message)
LogUtils.d(error?.message)
}
})
permissions = listOf("email", "user_likes", "user_status", "user_photos", "user_birthday", "public_profile", "user_friends");
}
/**
* 登陆
*/
fun login() {
getLoginManager().logIn(activity, permissions)
}
/**
* 退出登陆
*/
fun loginOut() {
var logout = activity.resources.getString(R.string.com_facebook_loginview_log_out_action)
var cancel = activity.resources.getString(R.string.com_facebook_loginview_cancel_action)
val message: String
val profile: Profile = Profile.getCurrentProfile()
message = if (profile?.name != null) {
java.lang.String.format(
activity.resources.getString(
R.string.com_facebook_loginview_logged_in_as),
profile.name)
} else {
activity.resources.getString(
R.string.com_facebook_loginview_logged_in_using_facebook)
}
val builder: AlertDialog.Builder = AlertDialog.Builder(activity)
builder.setMessage(message)
.setCancelable(true)
.setPositiveButton(logout) { _, _ ->
getLoginManager().logOut()
}
.setNegativeButton(cancel, null)
builder.create().show()
}
/**
* 获取登录信息
* @param accessToken
*/
private fun getLoginInfo(accessToken: AccessToken?) {
var request = GraphRequest.newMeRequest(accessToken, object : GraphRequest.GraphJSONObjectCallback {
override fun onCompleted(`object`: JSONObject?, response: GraphResponse?) {
`object`?.run {
val id = optString("id") //比方:13813813888
val name = optString("name") //比方:Zhang San
val gender = optString("gender") //性别:比方 male (男) female (女)
val email = optString("email") //邮箱:比方:11111@qq.com
//获取用户头像
val object_pic = optJSONObject("picture")
val object_data = object_pic.optJSONObject("data")
val photo = object_data.optString("url")
//获取地域信息
val locale = optString("locale") //zh_CN 代表中文简体
infoBean = FaceLoginInfoBean()
infoBean?.id = id
infoBean?.name = name
infoBean?.email = email
infoBean?.gender = gender
infoBean?.picture = object_pic.toString()
infoBean?.data = object_data.toString()
infoBean?.photo = photo
infoBean?.locale = locale
infoBean?.let { mFaceBookLoginListener?.onLoginSuccess(it) }
}
}
})
val parameters = Bundle()
parameters.putString("fields", "id,name,link,gender,birthday,email,picture,locale,updated_time,timezone,age_range,first_name,last_name")
request.parameters = parameters
request.executeAsync()
}
fun getCallbackManager(): CallbackManager? {
return callbackManager
}
/**
* 获取loginMananger
* @return
*/
private fun getLoginManager(): LoginManager {
if (loginManager == null) {
loginManager = LoginManager.getInstance();
}
return loginManager!!
}
companion object {
/**
* 是否处在登陆状态
*/
fun isLogin(): Boolean {
val accessToken = AccessToken.getCurrentAccessToken()
val isLoggedIn = accessToken != null && !accessToken.isExpired
return isLogin()
}
}
open fun setFaceBookLoginListener(faceBookLoginListener: FaceBookLoginListener?) {
this.mFaceBookLoginListener = faceBookLoginListener
}
interface FaceBookLoginListener {
fun onLoginSuccess(infoBean: FaceLoginInfoBean)
fun onLoginCancel(message: String?)
fun onLoginFail(message: String?)
fun onLogoutSuccess()
fun onLogoutFail()
}
}
8.Twitter登录东西类的封装:
**
* @author: njb
* @date: 2021/5/14 10:08
* @desc: Twitter登录东西类
*/
class TwitterLoginUtils(activity: Activity) {
private var activityRef: WeakReference<Activity>? = null
var callback: Callback<TwitterSession>? = null
@Volatile
var authClient: TwitterAuthClient? = null
companion object {
const val ERROR_MSG_NO_ACTIVITY = ("TwitterLoginButton requires an activity."
+ " Override getActivity to provide the activity for this button.")
}
init {
activityRef = WeakReference(activity)
TwitterCore.getInstance()
}
fun setOnLoginByTwitterClick(callback: Callback<TwitterSession>?) {
this.callback = callback
checkCallback(callback)
checkActivity(activityRef?.get())
twitterAuthClient!!.authorize(activityRef?.get(), callback)
}
private val twitterAuthClient: TwitterAuthClient?
get() {
if (authClient == null) {
synchronized(TwitterLoginButton::class.java) {
if (authClient == null) {
authClient = TwitterAuthClient()
}
}
}
return authClient
}
private fun checkCallback(callback: Callback<*>?) {
if (callback == null) {
CommonUtils.logOrThrowIllegalStateException(TwitterCore.TAG,
"Callback must not be null, did you call setCallback?")
}
}
private fun checkActivity(activity: Activity?) {
if (activity == null || activity.isFinishing) {
CommonUtils.logOrThrowIllegalStateException(TwitterCore.TAG, ERROR_MSG_NO_ACTIVITY)
}
}
/**
* Call this method when [Activity]
* is called to complete the authorization flow.
*
* @param requestCode the request code used for SSO
* @param resultCode the result code returned by the SSO activity
* @param data the result data returned by the SSO activity
*/
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == twitterAuthClient!!.requestCode) {
twitterAuthClient!!.onActivityResult(requestCode, resultCode, data)
}
}
}
9.简单运用代码如下:
运用具体步骤如下:
9.1先判别用户是否装置Google服务:
9.2先声明东西类:
private var mGoogleLogin: GoogleLoginUtils? = null
private var mFacebookLoginUtils: FacebookLoginUtils? = null
9.3 Google、FaceBook东西类的初始化:
private fun initGoogle() {
mGoogleLogin = GoogleLoginUtils(this, this)
mGoogleLogin?.setGoogleSignListener(this)
}
private fun initFaceBook() {
mFacebookLoginUtils = FacebookLoginUtils(this)
mFacebookLoginUtils?.setFaceBookLoginListener(this)
}
9.4 Google、FaceBook调用不同的办法:
R.id.iv_google -> {//先查看是否装置Google服务
checkGoogleService()
}
R.id.iv_face_book -> {//查看是否装置FaceBook客户端
if (!CheckApkExist.checkFacebookExist(this)) {
ToastUtils.showShort(getString(com.jiaoday.base.R.string.please_install_face_book_first))
} else {
mFacebookLoginUtils?.login()
}
}
private fun checkGoogleService() {
val code = mGoogleLogin?.checkGooglePlayServiceExist(this)
if (code == ConnectionResult.SUCCESS) {
mGoogleLogin?.signIn()
} else {
code?.let { mGoogleLogin?.onCheckGooglePlayServices(this, it) }
}
}
9.5Google和FaceBook登录回调:
在最开端承继一下登录回调监听办法:
GoogleLoginUtils.GoogleSignListener, FacebookLoginUtils.FaceBookLoginListener
9.6登录成功、失利、取消登录后的回调
override fun googleLoginSuccess(account: GoogleSignInAccount) {
//google登录成功后返回的信息
if (account.email != null) {
thirdAccountLogin(account.email.toString(), account.email.toString(), "4")
}
}
override fun googleLoginFail(message: String?) {
ToastUtils.showShort(message)
}
override fun googleLogoutSuccess() {
}
override fun googleLogoutFail() {
}
override fun onLoginSuccess(infoBean: FaceLoginInfoBean) {
//faceBook登录成功后返回的信息
if (infoBean.email.isNotEmpty()) {
thirdAccountLogin(infoBean.email, infoBean.email, "1") }
}
override fun onLoginCancel(message: String?) { ToastUtils.showShort(message) }
override fun onLoginFail(message: String?) { ToastUtils.showShort(message) }
override fun onLogoutSuccess() { }
override fun onLogoutFail() { }
9.7 onActivityResult回调结果:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == mGoogleLogin?.requestCode) {
val task: Task<GoogleSignInAccount> = GoogleSignIn.getSignedInAccountFromIntent(data)
mGoogleLogin?.handleSignInResult(task)
}
mFacebookLoginUtils?.getCallbackManager()?.onActivityResult(requestCode, resultCode, data)
}
10. 懒加载:
kotlin中的懒加载很闲适,运用起来十分简单便利,举个栗子:
private val mCallbackManager by lazy { CallbackManager.Factory.create() }
private val TAG by lazy { "MainActivity" }
private val mGoogleLoginUtils by lazy { GoogleLoginUtils(this, this) }
11.完好的运用流程如下:
- 初始化view.
- 初始化Google和FaceBook.
- 增加事情监听.
- 查看googlePlay服务.
- FaceBook登录时查看是否装置FaceBook客户端.
- 增加登录回调(登录成功、失利、取消登录等).
12.初始化view:
private fun initView() {
tv_google.setOnClickListener {
checkGoogleService()
}
tv_facebook.setOnClickListener {
if (!CheckApkExistUtils.checkFacebookExist(this)) {
Toast.makeText(this, "请先装置FaceBook客户端", Toast.LENGTH_LONG).show()
} else {
mFaceBookLoginUtils.login()
}
}
tv_twitter.setOnClickListener {
}
}
13.初始化Google和FaceBook:
private fun initGoogle() {
mGoogleLoginUtils.setGoogleSignListener(this)
}
private fun initFaceBook() {
mFaceBookLoginUtils.setFaceBookLoginListener(this)
}
14.增加事情监听:
GoogleLoginUtils.GoogleLoginListener,
FaceBookLoginUtils.FaceBookLoginListener {
private val mFaceBookLoginUtils by lazy {
FaceBookLoginUtils(
this,
callbackManager = mCallbackManager
)
}
private val mCallbackManager by lazy { CallbackManager.Factory.create() }
private val TAG by lazy { "MainActivity" }
private val mGoogleLoginUtils by lazy { GoogleLoginUtils(this, this) }
15.先查看是否装置Googleplay服务:
/**
* 先查看用户是否装置Google服务
*/
private fun checkGoogleService() {
val code = CheckGoogleServiceUtils.checkGooglePlayServiceExist(this)
if (code == ConnectionResult.SUCCESS) {
mGoogleLoginUtils.signIn()
} else {
code.let { CheckGoogleServiceUtils.onCheckGooglePlayServices(this, it) }
}
}
16.FaceBook登录时先查看是否装置客户端
tv_facebook.setOnClickListener {
if (!CheckApkExistUtils.checkFacebookExist(this)) {
Toast.makeText(this, "请先装置FaceBook客户端", Toast.LENGTH_LONG).show()
} else {
mFaceBookLoginUtils.login()
}
}
17.登录回调:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Log.d(TAG, resultCode.toString())
if (mCallbackManager != null) {
mCallbackManager.onActivityResult(requestCode, resultCode, data)
}
if (requestCode == mGoogleLoginUtils.requestCode) {
val task: Task<GoogleSignInAccount> = GoogleSignIn.getSignedInAccountFromIntent(data)
mGoogleLoginUtils.handleSignInResult(task)
}
}
18.完好Activity测验代码:
package com.powervision.thirdlogindemo
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.facebook.CallbackManager
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.tasks.Task
import com.powervision.thirdlogindemo.bean.FaceBookLoginInfoBean
import com.powervision.thirdlogindemo.utils.CheckApkExistUtils
import com.powervision.thirdlogindemo.utils.CheckGoogleServiceUtils
import com.powervision.thirdlogindemo.utils.FaceBookLoginUtils
import com.powervision.thirdlogindemo.utils.GoogleLoginUtils
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity(), GoogleLoginUtils.GoogleLoginListener,
FaceBookLoginUtils.FaceBookLoginListener {
private val mFaceBookLoginUtils by lazy {
FaceBookLoginUtils(
this,
callbackManager = mCallbackManager
)
}
private val mCallbackManager by lazy { CallbackManager.Factory.create() }
private val TAG by lazy { "MainActivity" }
private val mGoogleLoginUtils by lazy { GoogleLoginUtils(this, this) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initView()
initFaceBook()
initGoogle()
}
private fun initGoogle() {
mGoogleLoginUtils.setGoogleSignListener(this)
}
private fun initFaceBook() {
mFaceBookLoginUtils.setFaceBookLoginListener(this)
}
private fun initView() {
tv_google.setOnClickListener {
checkGoogleService()
}
tv_facebook.setOnClickListener {
if (!CheckApkExistUtils.checkFacebookExist(this)) {
Toast.makeText(this, "请先装置FaceBook客户端", Toast.LENGTH_LONG).show()
} else {
mFaceBookLoginUtils.login()
}
}
tv_twitter.setOnClickListener {
}
}
/**
* 先查看用户是否装置Google服务
*/
private fun checkGoogleService() {
val code = CheckGoogleServiceUtils.checkGooglePlayServiceExist(this)
if (code == ConnectionResult.SUCCESS) {
mGoogleLoginUtils.signIn()
} else {
code.let { CheckGoogleServiceUtils.onCheckGooglePlayServices(this, it) }
}
}
override fun onLoginSuccess(infoBean: FaceBookLoginInfoBean) {
//处理Facebook登录成功后的恳求
}
override fun onLoginFailed(message: String) {
}
override fun onLoginCancel(message: String) {
}
override fun onLogoutSuccess() {
}
override fun onLogoutFailed() {
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Log.d(TAG, resultCode.toString())
if (mCallbackManager != null) {
mCallbackManager.onActivityResult(requestCode, resultCode, data)
}
if (requestCode == mGoogleLoginUtils.requestCode) {
val task: Task<GoogleSignInAccount> = GoogleSignIn.getSignedInAccountFromIntent(data)
mGoogleLoginUtils.handleSignInResult(task)
}
}
override fun googleLoginSuccess(account: GoogleSignInAccount) {
//处理Google登录成功后的恳求
}
override fun googleLoginFail(message: String?) {
}
override fun googleLogoutSuccess() {
}
override fun googleLogoutFail() {
}
}
19.布局代码如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
•
<TextView
android:id="@+id/tv_google"
android:layout_width="0dp"
android:layout_height="40dp"
android:text="Google登录"
android:textColor="@color/white"
android:background="@color/colorPrimary"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/tv_facebook"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_facebook"
android:layout_width="0dp"
android:layout_height="40dp"
android:text="FaceBook登录"
android:textColor="@color/white"
android:background="@color/colorPrimary"
android:gravity="center"
android:layout_marginStart="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/tv_google"
app:layout_constraintRight_toLeftOf="@id/tv_twitter"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_twitter"
android:layout_width="0dp"
android:layout_height="40dp"
android:text="Twitter登录"
android:textColor="@color/white"
android:background="@color/colorPrimary"
android:gravity="center"
android:layout_marginStart="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@id/tv_facebook"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
20.总结:
以上就是Google、Facebook、Twitter登录东西类的完好封装和运用流程,如有适宜的你能够放到自己项目中,当然集成ShareSdk或许友盟能够很好的完成国外第三方登录,一键集成即可,不必专门去下载集成每一家的sdk,这儿我做这个的封装是为了能够更好地运用,便利其他搭档和项目,后边还能够做一致封装,只需求传递相应类型,登录成功和失利的办法回调出来就能够了.如有问题,及时交流,我会尽力改正,一起学习,共同进步,谢谢大家~~
21.项目源码地址如下:
ThirdLoginDemo: 运用Kotin封装的Google、FaceBook、Twitter登录东西类