Prerequisites
Minimum environment:
- JDK 17
- Android SDK + platform tools (you need
adbon yourPATH) - An Android phone (USB debugging enabled)
- Android emulator (if you want to use the simulation mode)
- Python 3.9+ (if you use the CLI)
Platform-specific notes:
- Android: the SDK minSdk is 28. Meta support and the RayNeo glasses host require minSdk 29.
- iOS: the Swift Package requires iOS 16+.
- Frame (current implementation): Android source/CLI workflows require Flutter on the developer machine because the SDK embeds a Flutter module at build time. Frame on iOS is sample-only through Flutter add-to-app.
Installation
xg.glass 0.3.0 is available through three install channels. Choose the one that matches your target platform.
Android: Maven Central
Use Maven Central for normal Android apps. SDK artifacts use group io.github.hkust-spark, version 0.3.0, and prefixed artifact IDs such as xgglass-universal, xgglass-core, and xgglass-device-meta. Kotlin packages in code remain com.xgglass.*.
The main Android artifact is xgglass-universal. It includes Rokid, RayNeo, INMO Air3, Simulator, Omi, Even Realities G1, and the Frame bridge API. RayNeo also needs the vendor AARs from RayNeo DevDocs; see third_party/rayneo/aar/README.md in the SDK repository.
// settings.gradle.kts
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
exclusiveContent {
forRepository {
maven { url = uri("https://maven.rokid.com/repository/maven-public/") }
}
filter {
includeGroupByRegex("com\\.rokid(\\..+)?")
}
}
}
}
// your app module's build.gradle.kts
dependencies {
implementation("io.github.hkust-spark:xgglass-universal:0.3.0")
}
Meta is intentionally opt-in. Add xgglass-device-meta plus Meta's GitHub Packages repository, and provide a GitHub token with read:packages scope.
# ~/.gradle/gradle.properties
github_user=YOUR_GITHUB_USERNAME
github_token=ghp_xxxxxxxxxxxxx
// settings.gradle.kts
val metaGithubUser = providers.gradleProperty("github_user").orNull
?: providers.environmentVariable("GITHUB_ACTOR").orNull
?: ""
val metaGithubToken = providers.gradleProperty("github_token").orNull
?: providers.environmentVariable("GITHUB_TOKEN").orNull
?: ""
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven {
url = uri("https://maven.pkg.github.com/facebook/meta-wearables-dat-android")
credentials {
username = metaGithubUser
password = metaGithubToken
}
}
}
}
// your app module's build.gradle.kts
dependencies {
implementation("io.github.hkust-spark:xgglass-device-meta:0.3.0")
}
iOS: Swift Package
Add the SDK package from GitHub. XgGlass provides the core API plus Simulator, Omi, and Even Realities G1 adapters, and XgGlassMeta adds the Meta adapter with Meta DAT 0.8.0, including the iOS microphone path. The XgGlassKit binary downloads automatically from the GitHub Release for the version you depend on.
// Package.swift
dependencies: [
.package(url: "https://github.com/hkust-spark/xg-glass-sdk", from: "0.3.0")
],
targets: [
.target(
name: "YourApp",
dependencies: [
.product(name: "XgGlass", package: "xg-glass-sdk"),
.product(name: "XgGlassMeta", package: "xg-glass-sdk")
]
)
]
Rokid and RayNeo are not available on iOS today. Frame on iOS is sample-only through Flutter add-to-app. See the SDK repository's docs/swift-package.md for the current Swift Package details.
CLI: PyPI
Use the CLI for generated Android projects and source-based workflows, especially when you need the current Frame integration.
pip install xg-glass
xg-glass --help
Run xg-glass doctor to check the Python, JDK, Android SDK, adb, emulator, Flutter, SDK cache, and network setup that the CLI will use.
Inside an already-generated project that contains xg-glass.yaml, the PyPI CLI can build, install, and run without an SDK checkout:
xg-glass build
xg-glass install
xg-glass run
Creating a project or quick-running a single Kotlin file needs SDK source/templates. By default the PyPI CLI downloads the matching tagged SDK archive into ~/.xg-glass/sdk/ on first use; pass --sdk to force a local checkout instead:
git clone https://github.com/hkust-spark/xg-glass-sdk
xg-glass init ./myapp --sdk /path/to/xg-glass-sdk
xg-glass run /path/to/MyEntry.kt --sdk /path/to/xg-glass-sdk
The CLI also manages missing Java, Android SDK, and Frame/Flutter prerequisites where possible. Managed Android command-line tools downloads are checked against pinned SHA-256 hashes before extraction.
Device support in 0.3.0
| Device family | Android | iOS | Notes |
|---|---|---|---|
| Rokid | Yes | No | Android phone adapter. |
| RayNeo | Yes | No | Uses the xg.glass on-glasses runtime and RayNeo vendor AARs. |
| Frame | Source/CLI | Sample-only | Flutter add-to-app path; not part of the lean Maven aggregate. |
| Meta | Opt-in | Yes | Android uses xgglass-device-meta; iOS includes microphone capture in XgGlassMeta. |
| Omi | Yes | Yes | BLE adapter. |
| Even Realities G1 | Yes | Yes | Adapter shipped; hardware validation pending. |
| INMO Air3 | Yes | No | On-glasses Android runtime adapter shipped; hardware validation pending. |
| Simulator | Yes | Yes | Development/testing adapter. |
Generated apps default to the all-device demo path. For smaller production projects, choose the adapters up front:
xg-glass init ./myapp --devices even,simulator
xg-glass init ./myapp --devices rokid,rayneo
xg-glass init ./myapp --devices frame,simulator
Valid values are rokid, rayneo, meta, frame, omi, even, inmo, simulator, and all; --sim adds simulator to concrete selections. Quick mode supports the same filter only when a .kt file is provided:
xg-glass run /path/to/MyEntry.kt --devices even,simulator
Workflows (CLI)
Start with quick mode, then graduate to project mode when you want a stable workspace.
Quick mode: run a single Kotlin file
Let the CLI generate a temporary project and run it. The PyPI CLI resolves the matching SDK automatically; pass --sdk when you want to force a local checkout:
xg-glass run /path/to/MyEntry.kt
xg-glass run /path/to/MyEntry.kt --devices even,simulator
xg-glass run /path/to/MyEntry.kt --sdk /path/to/xg-glass-sdk
From a repository checkout, you can use the repo-local launcher:
/path/to/xg-glass-sdk/xg-glass run /path/to/MyEntry.kt
Your entry file must follow a small format contract (documented in the CLI Reference).
Project mode: xg-glass init
Generate a minimal Android project and iterate:
xg-glass init ./myapp --devices even,simulator
cd ./myapp
xg-glass build
xg-glass install
xg-glass run
Add --sdk /path/to/xg-glass-sdk to init when you want to force a local checkout instead of the managed SDK cache.
From a repository checkout, the local launcher can infer the SDK path:
/path/to/xg-glass-sdk/xg-glass init ./myapp
cd ./myapp
xg-glass build
xg-glass install
xg-glass run
Your app logic lives in:
xgglass_app_logic/src/main/java/.../ExampleAppEntry.kt
App logic
When you write your app logic (ExampleAppEntry.kt), you mainly use:
- Capture a photo:
capturePhoto(...) - Display text:
display(text, ...) - Stream video frames: call
startVideoStream(...)whencapabilities.canStreamVideois true; collectVideoStreamSession.frames. The stream buffer keeps latency low with drop-oldest behavior, anddroppedFrameCountreports evicted frames. - Display an image: call
displayImage(DisplayImage(bytes, ImageEncoding.PNG), ...)orImageEncoding.JPEGwhencapabilities.canDisplayImagesis true. - Record audio:
startMicrophone(...) - Observe device input and battery: collect
eventsforGlassesEvent.Tap(count),GlassesEvent.LongPresswhencapabilities.supportsLongPressEventsis true, andGlassesEvent.BatteryLevel(percent)whencapabilities.supportsBatteryEventsis true. - Handle Omi buttons: Omi tap capability is enabled only after button-service discovery; legacy firmware may still emit
GlassesEvent.LongPresswhilesupportsLongPressEventsremains false. - Watch event backpressure:
BaseGlassesClient.droppedEventCountreports rejected event emissions for adapters that use suspending event buffers.
The host app (generated/provided by the SDK template) owns the connection lifecycle and UI.
if (client.capabilities.canStreamVideo) {
val session = client.startVideoStream().getOrThrow()
try {
session.frames.collect { frame ->
if (!frame.endOfStream) {
// frame.bytes contains the encoded frame payload.
}
}
} finally {
session.stop()
}
val dropped = session.droppedFrameCount
}
During an active video stream, adapters that share the stream source can satisfy capturePhoto() from the latest streamed frame instead of opening a second camera path:
val stream = client.startVideoStream().getOrThrow()
val still = client.capturePhoto().getOrThrow()
stream.stop()
if (client.capabilities.canDisplayImages) {
client.displayImage(
DisplayImage(
bytes = pngOrJpegBytes,
encoding = ImageEncoding.PNG
)
).getOrThrow()
}
client.events.collect { event ->
when (event) {
is GlassesEvent.BatteryLevel -> updateBattery(event.percent)
else -> Unit
}
}
See the detailed API surface and code examples in API Reference. The generated API reference at https://hkust-spark.github.io/xg-glass-sdk/ is generated from KDoc on every release and stays in sync with the code.