Android 应用程序集成Google 登录及二次封装
最新更新(2020/4/15)
最新有个项目要集成 google 登陆,我又又又又 重新做了一遍,发现很多重要 api 都变了,这里重新总结一下,用 Kotlin 编写。
首先依赖包已经更新到 18.0.0
api 'com.google.android.gms:play-services-auth:18.0.0'
GoogleLoginUtil 工具类:
package com.enjoy.literaturemodule.account.login.google
import android.content.Context
import androidx.fragment.app.FragmentActivity
import com.enjoy.library.utils.LogUtils
import com.enjoy.literaturemodule.R
import com.google.android.gms.auth.api.signin.*
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.tasks.Task
/**
* @author yanjun.zhao
* @time 2020/4/15 3:20 PM
* @desc Google 登陆
*/
class GoogleLoginUtil(var activity: FragmentActivity, private var googleSignListener: GoogleSignListener) {
private var gso: GoogleSignInOptions? = null
private var mGoogleSignClient: GoogleSignInClient? = null
companion object {
const val requestCode = 10
}
init {
gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestId()
.requestIdToken(activity.getString(R.string.google_server_client_id))
.requestProfile()
.build()
mGoogleSignClient = GoogleSignIn.getClient(activity, gso!!)
}
/**
* 登陆
*/
fun login() {
var intent = mGoogleSignClient?.signInIntent
activity.startActivityForResult(intent, requestCode)
}
/**
* 退出登陆
*/
fun signOut() {
mGoogleSignClient?.signOut()
?.addOnCompleteListener {
googleSignListener?.googleLogoutSuccess()
}
?.addOnFailureListener {
googleSignListener?.googleLogoutFail()
}
}
/**
* 是否 登陆过
*/
fun hasLogin(context: Context): Boolean {
var accout = GoogleSignIn.getLastSignedInAccount(context)
if (accout == null) {
//是新用户,没有登陆过
return false
} else {
//老用户,已经登陆过
//获取用户信息
var displayName = accout?.displayName
var email = accout?.email
val id = accout?.id
val photoUrl = accout?.photoUrl
val familyName = accout?.familyName
val givenName = accout?.givenName
return true
}
}
fun handleSignInResult(completedTask: Task<GoogleSignInAccount>) {
try {
var accout = completedTask.getResult(ApiException::class.java)
//登陆成功
var displayName = accout?.displayName
var email = accout?.email
val id = accout?.id
val photoUrl = accout?.photoUrl
val familyName = accout?.familyName
val givenName = accout?.givenName
LogUtils.d("google-displayName", displayName)
LogUtils.d("google-email", email)
LogUtils.d("google-photoUrl", photoUrl?.encodedPath)
LogUtils.d("google-photoUrl", photoUrl?.toString())
LogUtils.d("google-familyName", familyName)
LogUtils.d("google-givenName", givenName)
LogUtils.d("google-id", id)
googleSignListener?.googleLoginSuccess()
} catch (e: ApiException) {
googleSignListener?.googleLoginFail()
}
}
interface GoogleSignListener {
fun googleLoginSuccess()
fun googleLoginFail()
fun googleLogoutSuccess()
fun googleLogoutFail()
}
}
Activity 使用
package com.enjoy.literaturemodule.account
import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.FragmentActivity
import com.enjoy.literaturemodule.account.login.google.GoogleLoginUtil
import com.google.android.gms.auth.api.signin.GoogleSignIn
import kotlinx.android.synthetic.main.activity_login.*
/**
* 登陆
*/
class LoginActivity : FragmentActivity(), GoogleLoginUtil.GoogleSignListener {
private var googleLoginUtil: GoogleLoginUtil? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
googleLoginUtil = GoogleLoginUtil(this, this)
//登陆
google_signIn_bt.setOnClickListener {
googleLoginUtil?.login()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
//google登陆
if (requestCode == GoogleLoginUtil.requestCode) {
var googleResultTask = GoogleSignIn.getSignedInAccountFromIntent(data)
googleLoginUtil?.handleSignInResult(googleResultTask)
}
super.onActivityResult(requestCode, resultCode, data)
}
override fun googleLoginSuccess() {
Log.e("google", "googleLoginSuccess")
}
override fun googleLoginFail() {
Log.e("google", "googleLoginFail")
}
override fun googleLogoutSuccess() {
Log.e("google", "googleLogoutSuccess")
}
override fun googleLogoutFail() {
Log.e("google", "googleLogoutFail")
}
}
在做的时候,发现一直登陆不成功 StatusCode = 12500 ,
折腾了很久,才弄好,有两点需要注意:
注意事项1:
一旦添加了 google_server_client_id , 那么 客户端 google-services.json 一定要更新。
注意事项2:
项目集成 Google 登陆,一定要在 Firebase 后台开启 Google 登陆功能,一定、一定、一定。
开启之前的状态
开启之后的状态:
补充:(2016/8/9)
有很多人留言或者发私信说一直登陆失败。然后我就自己写了一个demo,核心代码完全复制博客里面的 GoogleLogin (代码见第六个标题, 6、Google SDK 二次封装) 里面的代码,真的是一行代码都没有改,完完全全复制的。最后实现登陆成功,可见博客里面的代码是没有问题的。我在操作过程中,有几个关键的地方提一下。
1、权限问题:只需要添加联网权限即可
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
2、签名问题
在开发者后台创建app的时候,需要添加 SHA-1的值,这个值是从你的签名里面获取的。注意,在你运行demo的时候,如果直接运行是不行的,因为直接运行,android studio 会为你的app使用默认签名,这个签名是系统自带的,这个签名的SHA-1值肯定和你真正的签名文件SHA-1值不一样,所以必然会登录失败。 你需要修改你的app debug 时的签名和 发布时的签名一致就好了。
正文:
谷歌登录API: https://developers.google.com/identity/sign-in/android/
1、注册并且登录google网站
2、进入google开发者平台创建应用
https://developers.google.com/mobile/add?platform=android&cntapi=signin&cntapp=Default%20Demo%20App&cntpkg=com.google.samples.quickstart.signin&cnturl=https:%2F%2Fdevelopers.google.com%2Fidentity%2Fsign-in%2Fandroid%2Fstart%3Fconfigured%3Dtrue&cntlbl=Continue%20with%20Try%20Sign-In
3、在开发者平台填写响应的信息,包括 应用名、包名、签名的SHA-1值
图1
图2
图3
4、在项目中添加谷歌服务
4.1、在SDK Manager 里面下载 google service
4.2、在project目录下的build.gradle下添加
classpath 'com.google.gms:google-services:2.1.0-alpha4'
查看最新版本号:https://jcenter.bintray.com/com/google/gms/google-services/
4.3 在model目录下的build.gradle下添加
compile 'com.google.android.gms:play-services-auth:8.4.0'
5、代码实现
5.1、在布局文件中
1 <com.google.android.gms.common.SignInButton 2 android:id="@+id/google_signIn_bt" 3 android:layout_width="wrap_content" 4 android:layout_height="wrap_content" /> 5 6 <Button 7 android:id="@+id/google_loginOut_bt" 8 android:layout_width="match_parent" 9 android:layout_height="wrap_content" 10 android:text="google退出登录" 11 android:layout_gravity="center" 12 android:gravity="center" 13 > 14 </Button>
5.2、java代码
1 package com.pegasus.map.presentation.ui.activity; 2 3 import android.content.Intent; 4 import android.os.Bundle; 5 import android.view.View; 6 import android.widget.Button; 7 8 import com.google.android.gms.auth.api.Auth; 9 import com.google.android.gms.auth.api.signin.GoogleSignInAccount; 10 import com.google.android.gms.auth.api.signin.GoogleSignInOptions; 11 import com.google.android.gms.auth.api.signin.GoogleSignInResult; 12 import com.google.android.gms.common.ConnectionResult; 13 import com.google.android.gms.common.SignInButton; 14 import com.google.android.gms.common.api.GoogleApiClient; 15 import com.google.android.gms.common.api.ResultCallback; 16 import com.google.android.gms.common.api.Status; 17 import com.pegasus.map.R; 18 import com.pegasus.map.presentation.ui.base.BaseActivity; 19 20 import butterknife.Bind; 21 import butterknife.ButterKnife; 22 23 /** 24 * Created by ${zyj} on 2016/3/24. 25 * 登录 26 */ 27 28 public class LoginActivity1 extends BaseActivity implements GoogleApiClient.OnConnectionFailedListener , View.OnClickListener { 29 30 public int RequestCode = 10 ; 31 32 @Bind( R.id.google_signIn_bt ) 33 public SignInButton google_signIn_bt ; 34 35 @Bind( R.id.google_loginOut_bt ) 36 public Button google_loginOut_bt ; 37 38 public GoogleSignInOptions gso ; 39 public GoogleApiClient mGoogleApiClient ; 40 41 @Override 42 protected void onCreate(Bundle savedInstanceState) { 43 super.onCreate(savedInstanceState); 44 setContentView(R.layout.activity_login); 45 ButterKnife.bind(this); 46 init(); 47 } 48 49 50 private void init() { 51 //初始化谷歌登录服务 52 gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) 53 .requestEmail() //获取邮箱 54 .requestId() //获取id 号 55 .requestIdToken("456212545785") //获取token 56 .build(); 57 58 // Build a GoogleApiClient with access to GoogleSignIn.API and the options above. 59 mGoogleApiClient = new GoogleApiClient.Builder( this ) 60 .enableAutoManage( this , this ) 61 .addApi(Auth.GOOGLE_SIGN_IN_API, gso) 62 .build(); 63 64 //登录 65 google_signIn_bt.setSize(SignInButton.SIZE_STANDARD); 66 google_signIn_bt.setScopes(gso.getScopeArray()); 67 google_signIn_bt.setOnClickListener(this) ; 68 69 //退出 70 google_loginOut_bt.setOnClickListener(this) ; 71 72 } 73 74 @Override 75 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 76 super.onActivityResult(requestCode, resultCode, data); 77 78 //谷歌登录成功回调 79 if ( requestCode == RequestCode ) { 80 GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data); 81 handleSignInResult( result ) ; 82 } 83 } 84 85 @Override 86 public void onConnectionFailed(ConnectionResult connectionResult) { 87 88 } 89 90 @Override 91 public void onClick(View v) { 92 switch ( v.getId() ){ 93 case R.id.google_signIn_bt : //登录 94 signIn(); 95 break; 96 97 case R.id.google_loginOut_bt : 98 signOut(); 99 break; 100 } 101 } 102 103 /** 104 * 登录 105 */ 106 private void signIn() { 107 Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); 108 startActivityForResult(signInIntent, RequestCode ); 109 } 110 111 /** 112 * 退出 113 */ 114 private void signOut() { 115 Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback( 116 new ResultCallback<Status>() { 117 @Override 118 public void onResult(Status status) { 119 // ... 120 } 121 }); 122 } 123 124 private void handleSignInResult(GoogleSignInResult result) { 125 if (result.isSuccess()) { 126 // Signed in successfully, show authenticated UI. 127 GoogleSignInAccount acct = result.getSignInAccount(); 128 //获取用户名 129 String name = acct.getDisplayName() ; 130 String email = acct.getEmail() ; 131 String token = acct.getIdToken() ; 132 String id = acct.getId() ; 133 134 } else { 135 // Signed out, show unauthenticated UI. 136 } 137 } 138 139 }
6、Google SDK 二次封装
1 package com.pegasus.map.presentation.utils; 2 3 import android.content.Intent; 4 import android.support.v4.app.FragmentActivity; 5 import android.util.Log; 6 import android.widget.Toast; 7 8 import com.google.android.gms.auth.api.Auth; 9 import com.google.android.gms.auth.api.signin.GoogleSignInAccount; 10 import com.google.android.gms.auth.api.signin.GoogleSignInOptions; 11 import com.google.android.gms.auth.api.signin.GoogleSignInResult; 12 import com.google.android.gms.common.api.GoogleApiClient; 13 import com.google.android.gms.common.api.ResultCallback; 14 import com.google.android.gms.common.api.Status; 15 import com.pegasus.map.R; 16 17 /** 18 * Created by ${zyj} on 2016/3/30. 19 */ 20 public class GoogleLogin { 21 22 public int requestCode = 10 ; 23 private FragmentActivity activity ; 24 public GoogleSignInOptions gso ; 25 public GoogleApiClient mGoogleApiClient ; 26 public GoogleApiClient.OnConnectionFailedListener listener ; 27 private GoogleSignListener googleSignListener ; 28 29 public GoogleLogin(FragmentActivity activity , GoogleApiClient.OnConnectionFailedListener listener ){ 30 this.activity = activity ; 31 this.listener = listener ; 32 33 //初始化谷歌登录服务 34 gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) 35 .requestEmail() 36 .requestId() 37 .requestIdToken( activity.getString(R.string.google_server_client_id)) 38 .requestProfile() 39 .build(); 40 41 // Build a GoogleApiClient with access to GoogleSignIn.API and the options above. 42 mGoogleApiClient = new GoogleApiClient.Builder( activity ) 43 .enableAutoManage( activity , listener ) 44 .addApi(Auth.GOOGLE_SIGN_IN_API, gso) 45 .build(); 46 } 47 48 49 /** 50 * 登录 51 */ 52 public void signIn() { 53 Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient); 54 activity.startActivityForResult(signInIntent, requestCode); 55 } 56 57 /** 58 * 退出登录 59 */ 60 public void signOut() { 61 Auth.GoogleSignInApi.signOut(mGoogleApiClient).setResultCallback( 62 new ResultCallback<Status>() { 63 @Override 64 public void onResult(Status status) { 65 if ( status.isSuccess() ){ 66 if ( googleSignListener != null ){ 67 googleSignListener.googleLogoutSuccess(); 68 } 69 }else { 70 if ( googleSignListener!= null ){ 71 googleSignListener.googleLogoutFail(); 72 } 73 } 74 } 75 }); 76 } 77 78 public String handleSignInResult(GoogleSignInResult result) { 79 String res = "" ; 80 if (result.isSuccess()) { 81 //登录成功 82 GoogleSignInAccount acct = result.getSignInAccount(); 83 res = "登录成功" 84 + "用户名为:" + acct.getDisplayName() 85 + " 邮箱为:" + acct.getEmail() 86 + " token为:" + acct.getIdToken() 87 + " 头像地址为:" + acct.getPhotoUrl() 88 + " Id为:" + acct.getId() 89 + " GrantedScopes为:" + acct.getGrantedScopes() ; 90 Log.e("res", "res:"+res); 91 Toast.makeText( activity, res, Toast.LENGTH_SHORT).show(); 92 if ( googleSignListener != null ){ 93 googleSignListener.googleLoginSuccess(); 94 } 95 } else { 96 // Signed out, show unauthenticated UI. 97 res = "-1" ; //-1代表用户退出登录了 , 可以自定义 98 Toast.makeText( activity , "退出登录", Toast.LENGTH_SHORT).show(); 99 if ( googleSignListener != null ){ 100 googleSignListener.googleLoginFail(); 101 } 102 } 103 return res ; 104 } 105 106 107 public void setGoogleSignListener( GoogleSignListener googleSignListener ){ 108 this.googleSignListener = googleSignListener ; 109 } 110 111 public interface GoogleSignListener { 112 void googleLoginSuccess(); 113 void googleLoginFail() ; 114 void googleLogoutSuccess(); 115 void googleLogoutFail() ; 116 } 117 118 }
注意:当你把 GoogleLogin 类复制到你项目中的时候,activity.getString(R.string.google_server_client_id) 这一句会报错,可以先不用管,在6.5 部分会做说明
6.1 在activity里使用封装类
activity 实现 GoogleApiClient.OnConnectionFailedListener , GoogleLogin.GoogleSignListener 两个接口
6.2
//初始化谷歌登录服务 GoogleLogin googleLogin = new GoogleLogin( this , this ) ; googleLogin.setGoogleSignListener(this);
6.3
1 @Override 2 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 3 super.onActivityResult(requestCode, resultCode, data); 4 5 //谷歌登录成功回调 6 if (requestCode == googleLogin.requestCode ) { 7 GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data); 8 googleLogin.handleSignInResult( result ) ; 9 } 10 }
6.4
1 //登录 2 googleLogin.signIn(); 3 4 //退出 5 googleLogin.signOut();
6.5 获取 google_server_client_id , 并在strings 里面配置
https://console.developers.google.com/projectselector/apis/credentials
在上面的网站里选择
点击选择项目,然后选择你创建的app,进入下面一个界面,得到对应的Client ID