SDKAndroid

Install the Android SDK

Add the Extentos Android SDK to your Gradle project from Maven Central. Coordinates, minSdk 31, Kotlin/AGP/Gradle floors, and the assistant runtime.

The Extentos Android SDK ships five artifacts on Maven Central. Most apps need the first two:

  • com.extentos:glasses — the core runtime (ExtentosGlasses, capability clients, transports)
  • com.extentos:glasses-ui — the prebuilt connection page (ExtentosConnectionPage). Optional on a voice-only app, which renders no connection page.
  • com.extentos:glasses-metaoptional; the Meta Ray-Ban transport (camera, display, the DAT device session). Only apps that use camera or display need it.
  • com.extentos:glasses-localoptional; on-device text models for the local tier.
  • com.extentos:glasses-local-voiceoptional; on-device speech for the local tier.

The Extentos artifacts resolve from the default mavenCentral() repository. com.extentos:glasses and glasses-ui have no vendor dependency, so a voice-only app needs nothing beyond a normal Gradle dependency — no extra repository, no token.

The Meta DAT dependencies (com.meta.wearable:mwdat-*) come in through com.extentos:glasses-meta only. They live on Meta's GitHub Packages, which needs one extra repo declaration plus a GitHub token (step 1). Skip that step entirely if your app doesn't use camera or display.

1. Declare the repositories

Voice-only apps can skip this whole step. Extentos resolves from Maven Central, which is already in the default Android template.

If you add com.extentos:glasses-meta for camera or display, its Meta DAT artifacts resolve from Meta's GitHub Packages, which requires a GitHub personal access token with the read:packages scope. Add both to your settings.gradle.kts:

settings.gradle.kts
// pluginManagement MUST be the first block in a settings script — Gradle
// aborts configuration otherwise. Without it, `id("com.android.application")`
// can't resolve: AGP lives on google(), and Gradle's default plugin repo is
// gradlePluginPortal() only.
pluginManagement {
    repositories { google(); mavenCentral(); gradlePluginPortal() }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        // Transitive Meta DAT artifacts (com.meta.wearable:mwdat-*) live here:
        maven {
            url = uri("https://maven.pkg.github.com/facebook/meta-wearables-dat-android")
            credentials {
                username = "token"
                password = (providers.gradleProperty("github_token").orNull
                    ?: System.getenv("GITHUB_TOKEN")) ?: ""
            }
        }
    }
}

…followed by your module declarations:

settings.gradle.kts (continued)
rootProject.name = "myapp"
include(":app")

FAIL_ON_PROJECT_REPOS means a repositories { } block in app/build.gradle.kts becomes a hard build failure — declare every repository here instead.

Create the token at github.com → Settings → Developer settings → Personal access tokens with the read:packages scope, then export it as GITHUB_TOKEN. That is the one location every surface agrees on — the block above reads it, the scaffold's variant reads it, and extentos-mcp setup checks it. (~/.gradle/gradle.properties as github_token=... also satisfies the block above, but the scaffold's variant and the diagnostic don't look there, so you can end up with a working build and a diagnostic that reports it missing — or the reverse.) To check your setup, run npx -p @extentos/mcp-server extentos-mcp setup from the project root — a read-only diagnostic that validates the token against GitHub Packages and prints exact remediation; it reads GITHUB_TOKEN or the project's local.properties and does not store the token for you. (generateConnectionModule emits a variant of this repo block that reads local.properties/env instead of the Gradle property — same URL, same key names.) Without the token the build fails at first sync with Could not resolve com.meta.wearable:mwdat-core.

2. Add the dependency

app/build.gradle.kts
dependencies {
    implementation("com.extentos:glasses:2.1.2")
    implementation("com.extentos:glasses-ui:2.1.2")

    // ONLY if your app uses the camera or the display. This is what brings the
    // Meta DAT artifacts (and therefore the repository + token in step 1).
    // Voice-only apps omit it entirely.
    implementation("com.extentos:glasses-meta:2.1.2")
}

You don't declare the Meta DAT SDK (com.meta.wearable) yourself — it comes in transitively through com.extentos:glasses-meta, and only through that module. It resolves from the GitHub Packages repo added in step 1, so the read:packages token must be in place for a camera/display build to succeed. A voice-only app never pulls those artifacts and needs no token.

glasses-meta registers itself at app start, so adding the dependency is the whole integration — TransportChoice.Auto resolves to real glasses with no extra code.

3. Set the build floors

The library is built against these versions. Match or exceed them.

RequirementValueWhy
minSdk31 (Android 12)Meta DAT mandates it. The Bluetooth runtime-permission model the SDK uses is Android 12+.
compileSdk35Transitive deps require it.
Kotlin2.1.20The AAR is compiled with 2.1.20; older Kotlin emits Class file was compiled with a newer version metadata warnings.
Android Gradle Plugin8.6.0+Compose deps in glasses-ui declare an AGP 8.6 floor.
Gradle8.7+Required by AGP 8.6.
Java/Kotlin target17The library targets JVM 17.

The library does not declare a targetSdk — your app's targetSdk is inherited as-is. targetSdk 34 or 35 both work for most apps. (getPermissions reports 34 as the value it derived its permission advice against; that's the floor it reasoned from, not a requirement on you.)

You also need two build features that a fresh AGP 8 project leaves off by default:

app/build.gradle.kts
plugins {
    id("com.android.application") version "8.6.0"
    id("org.jetbrains.kotlin.android") version "2.1.20"
    // Required if you use ExtentosConnectionPage or any Compose UI. From Kotlin
    // 2.0 the Compose compiler is a separate plugin — same version as Kotlin.
    id("org.jetbrains.kotlin.plugin.compose") version "2.1.20"
}

android {
    // AGP 8 removed the manifest-package fallback: without a namespace the build
    // fails with "Namespace not specified."
    namespace = "com.example.myapp"
    compileSdk = 35

    defaultConfig {
        minSdk = 31
        // targetSdk = 35  // your choice; the library doesn't impose one
    }

    buildFeatures {
        // AGP 8 defaults this to false. The SDK's own initialization snippet
        // reads BuildConfig.DEBUG, and the MCP scaffold emits buildConfigField
        // entries (EXTENTOS_SESSION_URL), so this must be on.
        buildConfig = true
        compose = true   // only if you use Compose / ExtentosConnectionPage
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
    kotlinOptions { jvmTarget = "17" }
}

buildConfig = true is not optional. Every canonical initialization snippet branches on BuildConfig.DEBUG to pick the environment, and the browser-simulator loop reads BuildConfig.EXTENTOS_SESSION_URL. On AGP 8 with the feature off, BuildConfig does not exist and those lines don't resolve.

The project key (production gateway attribution)

If your app uses the assistant, add your account-bound project key as a buildConfigField so production gateway usage attributes to your Extentos account:

app/build.gradle.kts
android {
    defaultConfig {
        buildConfigField("String", "EXTENTOS_PROJECT_KEY", "\"pk_your_project_key\"")
    }
}

The SDK reads it reflectively and sends it as the x-extentos-project-key header. (Meta's App ID and Client Token go through resValue / R.string instead, not buildConfigField — those rotate, and BuildConfig string constants are compile-time-inlined so a stale one can survive a rotation. The project key is regenerated by re-running the scaffold, which rewrites this line, so the same hazard doesn't apply.) generateConnectionModule mints the key and emits this exact line for you (it appears in the response's buildConfigFields[]); if you are wiring the project by hand, get the key from your dashboard project. In the simulator it is unused — attribution there comes from the session token. On a sideloaded development build on a real phone it is load-bearing: such a build can't attest (Play Integrity doesn't recognise it), so the key is how the gateway identifies the caller. Without it, and without a simulator-session binding, assistant.start(...) fails with AssistantError.NoApiKey. It never causes a build error, so the only symptom is at runtime — see gateway identity. Don't commit it to a public repo; re-run generateConnectionModule to rotate.

Some dependencies are yours, not the SDK's. glasses-ui brings the Compose runtime it needs, not the ones your UI code uses:

app/build.gradle.kts
// The SDK's suspend surface needs a dispatcher from your side
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")
// Only if you follow the docs' Compose idiom (collectAsStateWithLifecycle)
implementation("androidx.lifecycle:lifecycle-runtime-compose:2.8.6")
// Your own Compose stack, if you have UI of your own
implementation(platform("androidx.compose:compose-bom:2024.09.03"))   // any recent BOM works — declare only one
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material3:material3")
implementation("androidx.activity:activity-compose:1.9.2")

If you started from the Android Studio template, its root build.gradle.kts already declares these plugins with apply false and a version. Declaring a version in both places fails with "plugin request must not include a version" — keep one. Either drop the version from the block above, or delete the root declarations. A libs.versions.toml catalog works too; the SDK doesn't care which you pick.

4. Sync and verify

Run a Gradle sync (or ./gradlew :app:dependencies) and confirm com.extentos:glasses resolves. Next, wire it up:

The assistant runtime

The end-to-end voice assistant (glasses.assistant.* — wake/sleep state machine, barge-in, session.say(...)) ships in the stable 1.4.0 release on Maven Central — the standard dependency above includes it. No snapshot, no extra repository, no special setup. See the assistant page for the API surface and the voice-assistant guide for an end-to-end build.

Source