当前位置: 首页 > article >正文

Unity Google登录

目录

一:导入java文件💦

二:创建按钮和绑定编写的cs文件💦

三:获取Web客户端id 💦

 四:打包配置相关 💦

五:注意:

后言


👑👑👑

版本:Unity 2021.3.44f1c1(低版本可能不支持❗️ )

前提条件:你要有Google(邮箱)账户(非GooglePlay 开发者账户)登录Google Cloud要用到❗️ 

查看项目包名

Edit -> Project Settings -> Player -> Other Settings

我的项目是安卓打包平台(需要签名证书❗️ )(如何创建签名证书 点击跳转)👈

一:导入java文件💦

在Assets\Plugins\Android文件夹下导入两个java文件

例如图所示

如果你的java文件第一行报错 

 可以试着放在根据你的包名的文件目录下Assets\Plugins\Android\libs\java\com\my(你的包名)\game\googlelogin

AndroidBriage.java

package com.my.game.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 = "这里填写Web客户端id";
 
    //初始化
    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("你Unity上挂载脚本的对象名字", "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;
    }
}

 注意这两处是填写根据你们的(继续看后续,看该填写什么)❗️ 

GoogleCredentialManagerSign.java

package com.my.game.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();
                //这里是给服务器发送的东西 发什么取决于你们
                //AndroidBriage.SendInfo(idToken);
                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);
                        }
                    }
            );
        }
    }
}

二:创建按钮和绑定编写的cs文件💦

创建按钮不用我说了吧,将下面的cs文件绑定(拖)到按钮身上

GoogleLoginScript.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class GoogleLoginScript : MonoBehaviour
{

    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");
    }

    //调用登出接口
    public void OnSignOut()
    {
        googleSignObj.CallStatic("googleLoginOut");
    }

    //登录回调
    public void OnGoogleLoginMessage(string message)
    {
        Debug.LogError("message: " + message);


        //给服务器发消息 发message
    }
    

    public static AndroidJavaObject GoogleSignObj()
    {
        if(Application.platform==RuntimePlatform.Android)
        {
            if(googleSignObj==null)
            {
                googleSignObj = new AndroidJavaObject("com.my.game.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);
        }
    }
   
}

 我这用的NGUI

按钮对象上绑定这个脚本GoogleLoginScript,那么AndroidBriage.java这里就要填写这个按钮对象的名字,反正谁绑定填谁的就完事

 双引号里替换掉。

 记得按钮绑定事件OnSignIn方法,懒得写代码就像上上图一样在OnClick上选选就行

三:获取Web客户端id 💦

Google Cloud平台 (点击跳转)

1.创建项目

2.启用 identity toolkit api  API

 

 

搜索  identity toolkit api  启用它

 

 

 3.创建Web类型的凭据

 

 

4.创建Android类型的凭据

需要包名和证书指纹

 证书指纹怎么获取(点击跳转)!!!👈😄

 

 5.获取Web客户端id 找到Web应用类型复制他的客户端ID,然后放到AndroidBriage.java文件的指定位置

 

 四:打包配置相关 💦

圈住的都是重点❗️ 

Edit -> Project Settings -> Player -> Publishing Settings

1.settingsTemplate.gradle文件

配置了多个 Maven 仓库,包括 JitPack 和阿里云 Maven 仓库,因为用国外的可能访问不到某些

pluginManagement {
    repositories {
        maven { url "https://jitpack.io" }
        maven { url 'https://maven.aliyun.com/repository/releases' }
        maven { url 'https://maven.aliyun.com/repository/jcenter' }
        maven { url 'https://maven.aliyun.com/repository/google' }
        maven { url 'https://maven.aliyun.com/repository/central' }
        maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
        maven { url 'https://maven.aliyun.com/repository/public' }
        gradlePluginPortal()
        google()
        mavenCentral()
    }
}

include ':launcher', ':unityLibrary'
**INCLUDES**

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
    repositories {
        maven { url "https://jitpack.io" }
        maven { url 'https://maven.aliyun.com/repository/releases' }
        maven { url 'https://maven.aliyun.com/repository/jcenter' }
        maven { url 'https://maven.aliyun.com/repository/google' }
        maven { url 'https://maven.aliyun.com/repository/central' }
        maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
        maven { url 'https://maven.aliyun.com/repository/public' }
        google()
        mavenCentral()
// Android Resolver Repos Start
        def unityProjectPath = $/file:///**DIR_UNITYPROJECT**/$.replace("\\", "/")
        maven {
            url (unityProjectPath + "/Assets/GeneratedLocalRepo/Firebase/m2repository") // Assets/Firebase/Editor/AppDependencies.xml:22, Assets/Firebase/Editor/AuthDependencies.xml:20
        }
        mavenLocal()
// Android Resolver Repos End
        flatDir {
            dirs "${project(':unityLibrary').projectDir}/libs"
        }
    }
}

2.AndroidManifest.xml文件

需要有网络权限,里面还有package包名,这个一般Unity会自动设置为你的包名

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.my.game"
    xmlns:tools="http://schemas.android.com/tools">
    <application>
        <activity android:name="com.unity3d.player.UnityPlayerActivity"
                  android:theme="@style/UnityThemeSelector">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <meta-data android:name="unityplayer.UnityActivity" android:value="true" />
        </activity>
    </application>
	
  <uses-permission android:name="android.permission.INTERNET" />
</manifest>

3.gradleTemplate.properties文件

org.gradle.jvmargs=-Xmx**JVM_HEAP_SIZE**M
org.gradle.parallel=true
unityStreamingAssets=**STREAMING_ASSETS**
# Android Resolver Properties Start
android.useAndroidX=true
android.enableJetifier=true
# Android Resolver Properties End
**ADDITIONAL_PROPERTIES**

 4.mainTemplate.gradle文件

注意四个依赖必须有❗️ ❗️ ❗️ 

apply plugin: 'com.android.library'
**APPLY_PLUGINS**

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation "androidx.credentials:credentials:1.3.0"
    implementation "androidx.credentials:credentials-play-services-auth:1.3.0"
    implementation "com.google.android.libraries.identity.googleid:googleid:1.1.1"
**DEPS**}

android {
    namespace "com.unity3d.player"
    ndkPath "**NDKPATH**"
    compileSdkVersion **APIVERSION**
    buildToolsVersion '**BUILDTOOLS**'

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_11
        targetCompatibility JavaVersion.VERSION_11
    }

    defaultConfig {
        minSdkVersion **MINSDKVERSION**
        targetSdkVersion **TARGETSDKVERSION**
        ndk {
            abiFilters **ABIFILTERS**
        }
        versionCode **VERSIONCODE**
        versionName '**VERSIONNAME**'
        consumerProguardFiles 'proguard-unity.txt'**USER_PROGUARD**
    }

    lintOptions {
        abortOnError false
    }

    aaptOptions {
        noCompress = **BUILTIN_NOCOMPRESS** + unityStreamingAssets.tokenize(', ')
        ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~"
    }**PACKAGING_OPTIONS**
}
**IL_CPP_BUILD_SETUP**
**SOURCE_BUILD_SETUP**
**EXTERNAL_SOURCES**

五:注意:

 签名证书(点击跳转)👈

测试的时候用真机测,真机要有Google三件套,要开VPN(魔法)🌟 

后言

👉💓👈  😁😁

你努力不一定会成功,但你不努力一定会失败。

环境不会改变,解决之道在于改变自我。


http://www.kler.cn/a/589802.html

相关文章:

  • 深入解析音频编解码器(Audio CODEC):硬件、接口与驱动开发
  • WireShark自动抓包
  • 【ProjectDiscovery 生态中核心工具 Subfinder、Httpx、Katana 和 Nuclei 的基础使用教程】
  • 【协作开发】低成本一键复刻github的gitea
  • 二、vtkCommand的使用
  • 2025-03-17 学习记录--C/C++-PTA 习题4-3 求分数序列前N项和
  • 大语言模型中的 Function Calling
  • Navicat又放大招,接入DeepSeek后AI写SQL
  • 2025-03-17 NO.1 Quest3 开发环境配置教程
  • 蓝桥杯备考:贪心+思维题 之 zzc种田
  • 理解矩阵乘以向量如何“将空间进行了扭曲”
  • 极客天成 NVFile 并行文件存储:端到端无缓存新范式,为 AI 训练按下“快进键”
  • 一文掌握 PostgreSQL 的各种指令(PostgreSQL指令备忘)
  • springboot441-基于SpringBoot的校园自助交易系统(源码+数据库+纯前后端分离+部署讲解等)
  • 网络工程安全从入门到“入魂“教学案
  • C++基础系列【24】STL迭代器和算法
  • leetcode501-二叉搜索树中的众数
  • Blender-MCP服务源码4-初始化项目解读
  • c++ 类和对象 —— 中 【复习笔记】
  • 物联网中RFID标签需要人为赋予信息和手动粘贴/挂载的问题