Credman Helper#115
Conversation
There was a problem hiding this comment.
Code Review
This pull request replaces the legacy Google Sign-In V2 implementation with a new Credential Manager (CredMan) integration via a Java bridge (CredManBridge.java), updating AuthManager.cs to handle silent and interactive sign-in flows and manage session caching. The review feedback highlights several critical issues: a shadowed webClientId variable in AuthManager.cs that will fail authentication, an unhandled SilentFailed error that causes a soft-lock, invalid '#' comments and a non-existent hasResolution() method in the Java bridge that will cause compilation failures, and potential thread leaks from creating new executors on every sign-in call.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| string webClientId = ""; | ||
| AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); | ||
| AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity"); | ||
| AndroidJavaClass bridge = new AndroidJavaClass("com.gamesamples.trivialkartunity.CredManBridge"); | ||
|
|
||
| googleTaskComplete = true; | ||
| string methodName = interactive ? "signInInteractive" : "signInSilent"; | ||
| bridge.CallStatic(methodName, currentActivity, webClientId); |
There was a problem hiding this comment.
The local variable webClientId is declared as an empty string "", which shadows the class field webClientId (defined at line 61). This causes an empty client ID to be passed to the Java bridge, which will fail to authenticate or retrieve the server auth code. We should remove the local declaration and use the class field this.webClientId.
AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
AndroidJavaClass bridge = new AndroidJavaClass("com.gamesamples.trivialkartunity.CredManBridge");
string methodName = interactive ? "signInInteractive" : "signInSilent";
bridge.CallStatic(methodName, currentActivity, this.webClientId);| if (!string.IsNullOrEmpty(credManError)) | ||
| { | ||
| // --- Success case --- | ||
| Debug.Log($"Google Sign-In successful for: {this.googleUser.Email}"); | ||
| Debug.Log($"Retrieved Server Auth Code. Sending to backend..."); | ||
| statusText.text = "Connecting to game server..."; | ||
| StartCoroutine(ExchangeAuthcodeAndLink(authCodeToExchange)); | ||
| Debug.LogError("CredMan Error: " + credManError); | ||
| statusText.text = "Sign-in Failed."; | ||
| ShowStartPanel(); | ||
| } |
There was a problem hiding this comment.
If silent sign-in fails, OnSignInError is called with "SilentFailed". Currently, this error is ignored and does not trigger the main thread dispatcher to show the start panel. As a result, the game will soft-lock on the loading screen. We should handle "SilentFailed" gracefully by showing the start panel and updating the status text to "Please sign in.".
if (!string.IsNullOrEmpty(credManError))
{
Debug.LogError("CredMan Error: " + credManError);
statusText.text = credManError == "SilentFailed" ? "Please sign in." : "Sign-in Failed.";
ShowStartPanel();
}| public void OnSignInError(string error) | ||
| { | ||
| if (error == "SilentFailed") { Debug.Log("Silent failed. Idle."); return; } | ||
| credManError = error; googleTaskComplete = true; | ||
| } |
There was a problem hiding this comment.
Returning early when error == "SilentFailed" prevents the main thread from being notified of the failure, leading to a soft-lock. We should set credManError and googleTaskComplete for all errors so the main thread can handle them and show the appropriate UI.
public void OnSignInError(string error)
{
credManError = error;
googleTaskComplete = true;
}| Log.i("CredMan", "PGS v1: Existing grant found. Returning user detected. Auth Code retrieved."); | ||
| UnityPlayer.UnitySendMessage("AuthManager", "OnSignInSuccess", authorizationResult.getServerAuthCode()); | ||
| } | ||
| else if (authorizationResult.hasResolution()) { |
There was a problem hiding this comment.
There was a problem hiding this comment.
| public class CredManBridge { | ||
|
|
||
| // --- MODE 1: SILENT SIGN-IN (Called on Awake) --- | ||
| // Tries to auto-select an authorized account. If it fails, it does NOT show UI. | ||
| public static void signInSilent(Context context, String webClientId) { | ||
| CredentialManager credentialManager = CredentialManager.create(context); | ||
| CancellationSignal cancellationSignal = new CancellationSignal(); | ||
| Executor executor = Executors.newSingleThreadExecutor(); |
There was a problem hiding this comment.
Creating a new single-thread executor on every call to signInSilent (and signInInteractive) is inefficient and can lead to thread leaks since these executors are never shut down. We should define a single static Executor at the class level and reuse it.
public class CredManBridge {
private static final Executor executor = Executors.newSingleThreadExecutor();
// --- MODE 1: SILENT SIGN-IN (Called on Awake) ---
// Tries to auto-select an authorized account. If it fails, it does NOT show UI.
public static void signInSilent(Context context, String webClientId) {
CredentialManager credentialManager = CredentialManager.create(context);
CancellationSignal cancellationSignal = new CancellationSignal();| public static void signInInteractive(Context context, String webClientId) { | ||
| CredentialManager credentialManager = CredentialManager.create(context); | ||
| CancellationSignal cancellationSignal = new CancellationSignal(); | ||
| Executor executor = Executors.newSingleThreadExecutor(); |
| import java.util.concurrent.Executors; | ||
|
|
||
|
|
||
| # [START google_signin_credman_example] |
There was a problem hiding this comment.
We need to follow up with the DAC team, as this code will not compile
Can do a multiline comment (look below) , or a custom doclet (not 100% sure)
/*
[END google_signin_credman_example]
*/
There was a problem hiding this comment.
This was requested by our tech writing team for linking to DAC
| String email = credential.getId(); | ||
|
|
||
| Account account = new Account(email, "com.google"); | ||
| // Requesting GAMES_LITE scope to check for pre-existing V1 grants |
There was a problem hiding this comment.
Update the line to "pre-existing PGS V1 grants" + possible link
|
|
||
| Account account = new Account(email, "com.google"); | ||
| // Requesting GAMES_LITE scope to check for pre-existing V1 grants | ||
| List<Scope> requestedScopes = Collections.singletonList(new Scope("https://www.googleapis.com/auth/games_lite")); |
| Log.i("CredMan", "PGS v1: Existing grant found. Returning user detected. Auth Code retrieved."); | ||
| UnityPlayer.UnitySendMessage("AuthManager", "OnSignInSuccess", authorizationResult.getServerAuthCode()); | ||
| } | ||
| else if (authorizationResult.hasResolution()) { |
There was a problem hiding this comment.
| private GoogleSignInUser googleUser; | ||
|
|
||
| // --- NEW VARIABLES for main-thread dispatching --- | ||
| // V2 (CredMan) Specific Variables |
| private void Update() | ||
| { | ||
| #if PGS_V2 | ||
| // V2 Main Thread Dispatcher |
|
|
||
| GoogleSignIn.DefaultInstance.SignOut(); | ||
| ShowStartPanel(); | ||
| } |
There was a problem hiding this comment.
Not sure about this, mismatched braces?
Credman implementation in Java to support migration from PGS v1 to v2