Get hands-on experience with 20+ free Google Cloud products and $300 in free credit for new customers.

Unity Vertex Ai authorization on IOS build

I'm developing a Unity application that communicates with Google Vertex AI Gemini Flash for chatbot functionality. For authentication, I'm using OAuth 2.0 with a service account JSON file to obtain an access token. This approach works perfectly in the Unity Editor, but when I build the app for iOS, the authentication fails with the following error: "JSON is null or empty."

I've read that using Google Sign-In could be a solution, but I want to avoid requiring users to manually log in. The app should authenticate using the service account, without any user interaction.

Setup:

  • The service account JSON is stored in the StreamingAssets folder.

  • I use the Google.Apis.Auth.OAuth2 library to obtain the access token.

  • On iOS, I use UnityWebRequest to load the JSON file.

Despite including the JSON in the StreamingAssets, I receive the error "JSON is null or empty" on iOS when attempting to load the file. The JSON contains the correct data when building for iOS. Maybe there is issue with

using Google.Apis.Auth.OAuth2;

How can I authenticate using the service account JSON file on iOS without relying on Google Sign-In?

 

using Google.Apis.Auth.OAuth2;

public class GoogleCloudAuthHelper : MonoBehaviour
{
    public string apiKeyPath = "service-account";
    private GoogleCredential _credential;
    private string _accessToken;

    private async void Awake()
    {
        await InitializeCredential();
    }

    private async Task InitializeCredential()
    {
        try
        {
            Debug.Log($"Attempting to load service account JSON file from path: {apiKeyPath}");

            // Load the service-account.json file from StreamingAssets
            var resourcePath = Path.Combine(Application.streamingAssetsPath, apiKeyPath + ".json");

            // Check for platform-specific file access
            string jsonKey;
            if (Application.platform == RuntimePlatform.Android)
            {
                // For Android, use UnityWebRequest to load the file
                using (UnityWebRequest www = UnityWebRequest.Get(resourcePath))
                {
                    await www.SendWebRequest();
                    if (www.result != UnityWebRequest.Result.Success)
                    {
                        throw new FileNotFoundException($"Failed to load service account JSON file: {www.error}");
                    }
                    jsonKey = www.downloadHandler.text;
                }
            }
            else
            {
                // For other platforms (Windows, macOS, etc.), use File.ReadAllText
                jsonKey = File.ReadAllText(resourcePath);
            }

            Debug.Log("Service account JSON file loaded successfully.");

            // Create a memory stream from the JSON key string
            using (var jsonKeyStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(jsonKey)))
            {
                // Create Google Credential from the loaded JSON key
                _credential = GoogleCredential.FromStream(jsonKeyStream)
                    .CreateScoped(new[] { "https://www.googleapis.com/auth/cloud-platform" });
            }

            Debug.Log("Google Credential initialized successfully.");

            // Obtain the access token
            _accessToken = await GetAccessTokenAsync();
        }
        catch (Exception ex)
        {
            Debug.LogError($"Failed to initialize Google credentials: {ex.Message}");
        }
    }


    public async Task<string> GetAccessTokenAsync()
    {
        if (_credential == null)
        {
            Debug.LogError("Google Credential is not initialized.");
            return null;
        }

        if (_credential.UnderlyingCredential == null)
        {
            Debug.LogError("Underlying Credential is null.");
            return null;
        }

        try
        {
            // Get the access token from the underlying credential
            var tokenResponse = await _credential.UnderlyingCredential.GetAccessTokenForRequestAsync();
            Debug.Log("Access token obtained successfully.");
            return tokenResponse;
        }
        catch (Exception ex)
        {
            Debug.LogError($"Failed to obtain access token: {ex.Message}");
            throw;
        }
    }

    public GoogleCredential GetCredential()
    {
        if (_credential == null)
        {
            Debug.LogError("Google Credential is not initialized.");
        }
        return _credential;
    }

    public string GetStoredAccessToken()
    {
        return _accessToken;
    }
}
public class ChatClientUnity : MonoBehaviour
{
    private HttpClient _client;
    public string projectId;
    public string modelId;
    public string locationId;
    public string apiKeyPath;
    public string apiKey;

    private GoogleCloudAuthHelper _authHelper;

    private void Awake()
    {
        _client = new HttpClient();
        _authHelper = gameObject.AddComponent<GoogleCloudAuthHelper>();
        _authHelper.apiKeyPath = apiKeyPath;
    }

    private void OnDestroy()
    {
        _client?.Dispose();
    }

    public async Task<string> Chat(string text, string context, Example[] examples)
    {
        try
        {
            var accessToken = await _authHelper.GetAccessTokenAsync();
            var endpoint = $"https://us-central1-aiplatform.googleapis.com/v1/projects/{projectId}/locations/{locationId}/publishers/google/models/{modelId}:predict";

            if (string.IsNullOrEmpty(accessToken))
            {
                throw new Exception("Access token is null or empty.");
            }

            _client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

            var messages = new List<object>
            {
                new { author = "user", content = text }
            };

            var request = new
            {
                instances = new[]
                {
                    new
                    {
                        context = context,
                        examples = examples ?? Array.Empty<Example>(), // Ensure examples is not null
                        messages = messages
                    }
                }
            };

            var jsonContent = new StringContent(JsonConvert.SerializeObject(request));
            jsonContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

            var response = await _client.PostAsync(endpoint, jsonContent);

            if (response.IsSuccessStatusCode)
            {
                var responseContent = await response.Content.ReadAsStringAsync();
                var responseJson = JsonConvert.DeserializeObject<PredictionResponse>(responseContent);
                return responseJson.predictions[0].candidates[0].content.Trim();
            }
            else
            {
                var errorContent = await response.Content.ReadAsStringAsync();
                throw new Exception($"API communication error: {response.StatusCode}, {errorContent}");
            }
        }
        catch (Exception ex)
        {
            Debug.LogError("Exception: " + ex.Message);
            throw; // Consider if you want to rethrow or handle it differently
        }
    }

 

0 0 220
0 REPLIES 0