Skip to content

About

Android sample app to demonstrate basics of using Gate/AI.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

Β 

History

12 Commits

Folders and files

Repository files navigation

Gate/AI Android Sample App

Sample Android application demonstrating the Gate/AI SDK integration with Jetpack Compose.

Features

  • 🎨 Modern Jetpack Compose UI with configuration overview, actions, and response inspector
  • πŸ” Gate/AI SDK integration example
  • πŸ“± Material Design 3 components with custom theming
  • πŸ—οΈ MVVM architecture with ViewModel
  • βš™οΈ BuildConfig-based configuration
  • πŸ“Š Analytics properties (userIdentifier, appFeature, userStatus) set once on the client
  • πŸ“‰ Usage limits: userTier and quotaAnchorDay, per-metric quota meters from RawResponse.quotaStatus, and structured 429 handling via GateApiException.rateLimitInfo

Setup

1. Create Your Local Configuration

From this directory:

cp sample.local.properties.example sample.local.properties

Edit sample.local.properties with your settings (no quotes around values):

APPLICATION_ID=com.yourcompany.gateaisample
GATE_BASE_URL=https://your-gate.in.gate-ai.net
DEBUG_SIGNING_CERT_SHA256=YOUR_DEBUG_SHA256_FINGERPRINT
RELEASE_SIGNING_CERT_SHA256=YOUR_RELEASE_SHA256_FINGERPRINT
CLOUD_PROJECT_NUMBER=0
DEV_TOKEN=

This file is ignored by Git. You do not need to edit app/build.gradle.kts or rename the source package. APPLICATION_ID controls the installed app's package name; the code namespace stays com.gateai.sample. Register your application ID and signing certificate with your gate.

Set CLOUD_PROJECT_NUMBER to the numeric Google Cloud project number linked to Play Integrity in your Play Console (without an L suffix). 0 means unset. This is required for device testing with development builds (Android Studio / adb).

If the file is absent, builds use a generic application ID and placeholder gate URL with no credentials. Configure the file before making requests. Keep Android SDK paths in Android Studio's separate local.properties file.

Get Your SHA-256 Fingerprint

Debug keystore:

keytool -list -v -keystore ~/.android/debug.keystore \
  -alias androiddebugkey \
  -storepass android \
  -keypass android | grep SHA256

Release keystore:

keytool -list -v -keystore /path/to/your/release.keystore \
  -alias your-key-alias

Copy the SHA256 value (e.g., AA:BB:CC:...) to DEBUG_SIGNING_CERT_SHA256 or RELEASE_SIGNING_CERT_SHA256 in sample.local.properties. The debug build uses the standard Android debug keystore. Setting a release fingerprint does not configure release signing; release APKs still need to be signed with that certificate.

2. (Optional) Setup Development Token

For testing on emulators where Play Integrity is unavailable:

  1. Generate a development token in the Gate/AI Portal.
  2. Set DEV_TOKEN=your-dev-token-here in sample.local.properties.

The token is included only in debug builds; release builds always use an empty token. Local properties are compiled into the app, so keep token-bearing debug APKs private.

3. Build and Run

./gradlew assembleDebug
adb install app/build/outputs/apk/debug/app-debug.apk

Or open in Android Studio, sync Gradle, and click Run. Sync/rebuild after changing local settings.

Project Structure

app/src/main/
β”œβ”€β”€ AndroidManifest.xml
β”œβ”€β”€ java/com/gateai/sample/
β”‚   β”œβ”€β”€ GateSampleApp.kt         # Application class, SDK initialization
β”‚   β”œβ”€β”€ GateSampleActivity.kt    # Main activity
β”‚   └── ui/
β”‚       β”œβ”€β”€ GateSampleScreen.kt  # Compose UI with config/actions/response sections
β”‚       └── GateSampleViewModel.kt # Business logic and Gate/AI interactions
└── res/
    └── values/
        β”œβ”€β”€ themes.xml            # Material theme
        └── strings.xml           # String resources

How It Works

1. SDK Initialization (GateSampleApp.kt)

class GateSampleApp : Application() {
    lateinit var gateAIClient: GateAIClient
        private set

    lateinit var gateAIConfiguration: GateAIConfiguration
        private set

    override fun onCreate() {
        super.onCreate()

        gateAIClient = setupGateAIClient()
    }

    private fun setupGateAIClient(): GateAIClient {
        val config = GateAIConfiguration(
            baseUrl = BuildConfig.GATE_BASE_URL,
            packageName = packageName,
            signingCertSha256 = BuildConfig.SIGNING_CERT_SHA256,
            developmentToken = BuildConfig.DEV_TOKEN.takeIf { it.isNotBlank() },
            logLevel = if (BuildConfig.DEBUG) {
                GateAIConfiguration.LogLevel.DEBUG
            } else {
                GateAIConfiguration.LogLevel.INFO
            }
        )
        gateAIConfiguration = config
        return GateAIClient.create(
            context = this,
            configuration = config
        )
    }
}

2. Using the SDK (GateSampleViewModel.kt)

The ViewModel exposes convenient actions that the UI can trigger:

fun testAuthentication() { /* request auth headers & show preview */ }
fun testProxyRequest() { /* call proxy with sample payload */ }
fun clearCache() { /* clear cached Gate/AI state */ }

Each action updates GateSampleUiState, which contains configuration metadata, loading indicators, and response/error strings for display.

3. UI (GateSampleScreen.kt)

The Compose UI mirrors the iOS sample with distinct sections:

  • Header with icon and description
  • Configuration card showing base URL, package name, environment, dev token status, and log level
  • Action buttons for auth test, proxy request, and cache clearing
  • Response card with progress indicator, success and error styling

Customizing the Sample

Change the API Endpoint

Modify the request path in GateSampleViewModel.kt:

val response = gateAIClient.performProxyRequest(
    path = "v1beta/models/gemini-2.5-flash:generateContent",
    method = HttpMethod.POST,
    body = requestBody,
    additionalHeaders = mapOf("Content-Type" to "application/json")
)

Add Actual API Calls

Use the headers with your preferred HTTP client:

// With OkHttp
val request = Request.Builder()
    .url("${BuildConfig.GATE_BASE_URL}/v1/models")
    .apply {
        headers.forEach { (key, value) -> addHeader(key, value) }
    }
    .build()

// With Ktor
val response = client.get("${BuildConfig.GATE_BASE_URL}/v1/models") {
    headers {
        headers.forEach { (key, value) -> append(key, value) }
    }
}

Change UI Theme

Edit app/src/main/java/com/gateai/sample/ui/theme/ to adjust colors and typography.

Troubleshooting

App Crashes on Startup

  • Check that GATE_BASE_URL is valid
  • Verify SIGNING_CERT_SHA256 is correct
  • Ensure your package name and cert are registered in Gate/AI Portal

"Play Integrity Error" on Device

  • Your app's package name must be registered in Gate/AI Portal
  • SHA-256 certificate fingerprint must match registration
  • App must be signed with the registered certificate

"Play Integrity Error" on Emulator

  • Use development token for emulator testing
  • Set DEV_TOKEN in debug build variant
  • Ensure dev token is valid and not expired

"401 Unauthorized"

  • Check that your Gate/AI base URL is correct
  • Verify device clock is synchronized
  • Check logs for DPoP nonce handling

Dependencies

This sample uses:

  • Gate/AI SDK com.github.GateAI-net:gate-android:v1.1.0 via JitPack (see settings.gradle.kts)
  • Jetpack Compose for UI
  • ViewModel for state management
  • Kotlin Coroutines for async operations

Learning Resources

Next Steps

  1. Integrate with real AI API endpoints (OpenAI, Anthropic, etc.)
  2. Add error handling UI feedback
  3. Implement streaming responses
  4. Add conversation history
  5. Customize theme and branding

For more information, see the main SDK documentation.

About

Android sample app to demonstrate basics of using Gate/AI.

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages