本文亮点
1、不需要App上架google,任意APP都可以使用google登录
2、不需要google开发者账号,任意google账号都可以创建API项目
3、Unity与安卓通信不需要打aar包或jar包,完全不需要打开AndroidStudio
4、图文超多,细节满满、只要按照我的步骤来,一定能成功,(前提是一定要按照我的步骤来,每一步都是必要的)
接入环境
1、unity版本:2021.3.41f1
Credential Manager需要安卓目标版本34以上,所以unity最低版本是2021.3.41f1
开始接入
创建工程
1、新建Unity工程
2、创建UI,一个登录按钮,一个显示用文本,一个挂载脚本的空物体。
3、新建脚本GoogleLoginScript.cs,把脚本拖到SDKobj上,statusText拖过去进行赋值
代码如下
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GoogleLoginScript : MonoBehaviour
{
public Text statusText;
private static AndroidJavaObject googleSignObj;
void Awake()
{
GoogleSignInit();
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
//调用登录接口
public void OnSignIn()
{
googleSignObj.CallStatic("googleLogin");
AddStatusText("Calling SignIn");
}
//登录回调
public void OnGoogleLoginMessage(string message)
{
Debug.LogError("message: " + message);
//开始登录逻辑
AddStatusText("OnGoogleLoginMessage Callback:"+ message);
}
public static AndroidJavaObject GoogleSignObj()
{
if(Application.platform==RuntimePlatform.Android)
{
if(googleSignObj==null)
{
googleSignObj = new AndroidJavaObject("com.abc.def.googlelogin.AndroidBriage");
if (googleSignObj == null)
{
Debug.LogError("AndroidBriage init faild");
}
}
return googleSignObj;
}
else
{
return null;
}
}
public static void GoogleSignInit()
{
try
{
googleSignObj = GoogleSignObj();
if(googleSignObj != null)
{
googleSignObj.CallStatic("init");
}
}
catch(Exception e)
{
Debug.LogError("Failed:" + e.Message);
}
}
private List<string> messages = new List<string>();
void AddStatusText(string text)
{
if (messages.Count == 5)
{
messages.RemoveAt(0);
}
messages.Add(text);
string txt = "";
foreach (string s in messages)
{
txt += "\n" + s;
}
statusText.text = txt;
}
}
4、给按钮添加点击事件,绑定GoogleLoginScript的OnSignIn函数。
5、Assets\Plugins\Android\libs\java\com\abc\def\googlelogin路径下添加两个java脚本
GoogleCredentialManagerSign.java用于和API库交互
AndroidBriage.java用于和C#交互
GoogleCredentialManagerSign.java
package com.abc.def.googlelogin;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import com.google.android.libraries.identity.googleid.GetGoogleIdOption;
import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption;
import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.function.Consumer;
import androidx.annotation.NonNull;
import androidx.credentials.ClearCredentialStateRequest;
import androidx.credentials.Credential;
import androidx.credentials.CredentialManager;
import androidx.credentials.CredentialManagerCallback;
import androidx.credentials.CustomCredential;
import androidx.credentials.GetCredentialRequest;
import androidx.credentials.GetCredentialResponse;
import androidx.credentials.PasswordCredential;
import androidx.credentials.PublicKeyCredential;
import androidx.credentials.exceptions.ClearCredentialException;
import androidx.credentials.exceptions.GetCredentialException;
//谷歌凭据管理器登录
public class GoogleCredentialManagerSign {
private static Activity mActivity = null;
private static Context mContext = null;
private static CredentialManager credentialManager;
private static boolean oneTapStatus = false;
public static void init(Activity activity, Context context) {
mActivity = activity;
mContext = context;
}
public static void googleLogin() {
credentialManager = CredentialManager.Companion.create(mContext);
//WEB_CLIENT_ID Web 应用客户端ID
GetSignInWithGoogleOption googleIdOption = new GetSignInWithGoogleOption.Builder(AndroidBriage.WEB_CLIENT_ID).build();
//实例化
GetCredentialRequest request = new GetCredentialRequest.Builder()
.addCredentialOption(googleIdOption)
.build();
android.os.CancellationSignal cancellationSignal = new android.os.CancellationSignal();
cancellationSignal.setOnCancelListener(() -> {
if (oneTapStatus) oneTapStatus = false;
Log.e("GoogleLog", "Preparing credentials with Google was cancelled.");
});
credentialManager.getCredentialAsync(
mActivity,
request,
cancellationSignal,
Executors.newSingleThreadExecutor(),
new CredentialManagerCallback<GetCredentialResponse, GetCredentialException>() {
@Override
public void onResult(GetCredentialResponse result) {
handleSignIn(result);
}
@Override
public void onError(GetCredentialException e) {
Log.e("GoogleLog", "Unexpected type of credential." + e);
handleFailure(e);
}
});
}
public static void handleSignIn(GetCredentialResponse result) {
// Handle the successfully returned credential.
Credential credential = result.getCredential();
if (credential instanceof PublicKeyCredential) {
String responseJson = ((PublicKeyCredential) credential).getAuthenticationResponseJson();
// Share responseJson i.e. a GetCredentialResponse on your server to validate and authenticate
} else if (credential instanceof PasswordCredential) {
String username = ((PasswordCredential) credential).getId();
String password = ((PasswordCredential) credential).getPassword();
// Use id and password to send to your server to validate and authenticate
} else if (credential instanceof CustomCredential) {
if (GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL.equals(credential.getType())) {
// Use googleIdTokenCredential and extract id to validate and
// authenticate on your server
GoogleIdTokenCredential googleIdTokenCredential = GoogleIdTokenCredential.createFrom(((CustomCredential) credential).getData());
String idToken = googleIdTokenCredential.getIdToken();
try {
JSONObject googleLoginInfoReturn = new JSONObject();
googleLoginInfoReturn.put("userId", googleIdTokenCredential.getId());
googleLoginInfoReturn.put("displayName",googleIdTokenCredential.getDisplayName());
googleLoginInfoReturn.put("imageUrl",googleIdTokenCredential.getProfilePictureUri());
googleLoginInfoReturn.put("givenName",googleIdTokenCredential.getGivenName());
googleLoginInfoReturn.put("familyName",googleIdTokenCredential.getFamilyName());
googleLoginInfoReturn.put("phoneNumber",googleIdTokenCredential.getPhoneNumber());
googleLoginInfoReturn.put("IdToken",idToken);
//返回相关信息
AndroidBriage.SendInfo(googleLoginInfoReturn.toString());
} catch (JSONException e) {
e.printStackTrace();
}
} else {
// Catch any unrecognized custom credential type here.
Log.e("GoogleLog", "Unexpected type of credential");
}
} else {
// Catch any unrecognized credential type here.
Log.e("GoogleLog", "Unexpected type of credential");
}
}
@SuppressLint("RestrictedApi")
private static void handleFailure(@NonNull GetCredentialException e) {
Logger logger = Logger.getLogger(Thread.currentThread().getStackTrace()[1].getClassName());
logger.log(Level.SEVERE, "Error getting (or preparing) credential: " + e);
}
/**
* 注销登录
*/
public static void googleLoginOut() {
ClearCredentialStateRequest clearCredentialStateRequest = new ClearCredentialStateRequest();
android.os.CancellationSignal cancellationSignal = new android.os.CancellationSignal();
cancellationSignal.setOnCancelListener(() -> {
if (oneTapStatus) oneTapStatus = false;
Log.e("GoogleLog", "Preparing credentials with Google was cancelled.");
});
if (credentialManager != null) {
credentialManager.clearCredentialStateAsync(
clearCredentialStateRequest,
cancellationSignal,
Executors.newSingleThreadExecutor(),
new CredentialManagerCallback<Void, ClearCredentialException>() {
@Override
public void onResult(Void unused) {
Log.e("GoogleLog", "google注销登录成功");
}
@Override
public void onError(@NonNull ClearCredentialException e) {
Log.e("GoogleLog","注销出错"+e);
}
}
);
}
}
}
AndroidBriage.java
package com.abc.def.googlelogin;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import com.unity3d.player.UnityPlayer;
import java.lang.reflect.Field;
import java.util.Map;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class AndroidBriage {
public static String WEB_CLIENT_ID = "110374893644-hm7kbef5vntgke1ig9dhpomrhsq1aslv.apps.googleusercontent.com";
//初始化
public static void init()
{
Activity mActivity = getCurrentActivity();
Context context = getApplication().getApplicationContext();
GoogleCredentialManagerSign.init(mActivity, context);
}
//登录
public static void googleLogin()
{
GoogleCredentialManagerSign.googleLogin();
}
//登出
public static void googleLoginOut()
{
GoogleCredentialManagerSign.googleLoginOut();
}
//打印Log
public static void SendInfo(String result)
{
UnityPlayer.UnitySendMessage("SDKobj", "OnGoogleLoginMessage", result);
}
public static Activity getCurrentActivity()
{
try
{
Class activityThreadClass = Class.forName("android.app.ActivityThread");
Object activityThread = activityThreadClass.getMethod("currentActivityThread", new Class[0]).invoke(new Object[]{}, new Object[0]);
Field activitiesField = activityThreadClass.getDeclaredField("mActivities");
activitiesField.setAccessible(true);
Map activities = (Map)activitiesField.get(activityThread);
for (Object activityRecord : activities.values())
{
Class activityRecordClass = activityRecord.getClass();
Field pausedField = activityRecordClass.getDeclaredField("paused");
pausedField.setAccessible(true);
if (!pausedField.getBoolean(activityRecord))
{
Field activityField = activityRecordClass.getDeclaredField("activity");
activityField.setAccessible(true);
return (Activity)activityField.get(activityRecord);
}
}
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
catch (InvocationTargetException e)
{
e.printStackTrace();
}
catch (NoSuchMethodException e)
{
e.printStackTrace();
}
catch (NoSuchFieldException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
return null;
}
public static Application getApplication()
{
Application application = null;
try
{
Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
Method method2 = activityThreadClass.getMethod("currentActivityThread", new Class[0]);
Object localObject = method2.invoke(new Object[]{}, new Object[]{});
Method method = activityThreadClass.getMethod("getApplication", new Class[0]);
application = (Application)method.invoke(localObject, new Object[]{});
}
catch (ClassNotFoundException e)
{
e.printStackTrace();
}
catch (NoSuchMethodException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
catch (IllegalArgumentException e)
{
e.printStackTrace();
}
catch (InvocationTargetException e)
{
e.printStackTrace();
}
return application;
}
}
其中需要的脚本就这些,需要注意的地方如下
打包设置
1、包名和目标版本
2、Keystore,自定义打包设置
3、包名
4、gradle版本
5、依赖
6、properties
WebClientId获取
1,新建Google Cloud项目
进入这个地址:谷歌API控制台,如果没有cloud项目的话需要新建cloud项目,如果已有直接选择项目进入。
2、开启Identity API
3、创建OAuth 同意屏幕,如果已有可以忽略。
4、在“凭据”页面上,创建 Web 类型的凭据
5、在“凭据”页面上,创建一个 Android 类型的客户端凭据
6、找到创建完成的凭据,复制出WebClientId
7、把这个WebClientId赋值到AndroidBriage.java的WEB_CLIENT_ID字段
参考链接
接入谷歌最新登录SDK凭据管理器Credential Manager
Google官方文档
谷歌API控制台
整个工程已上传,点击下面的链接下载,keystore密码是123456,可以直接用测试工程打包测试
1、测试工程下载