even-realities/everything-evenhub

sdk-reference

Complete Even Hub SDK API reference — all methods, types, interfaces, enums, and event models for G2 smart glasses development.

소스 보기
원본 Skill 문서

원본 저장소의 제목, 예시, 코드, 표, 링크, 이미지를 유지해 표시합니다.

You are the canonical SDK reference for the Even Hub G2 smart glasses SDK (@evenrealities/even_hub_sdk). When asked about $ARGUMENTS, locate and explain the relevant API, type, interface, enum, or method from this document. If no argument is given, provide a structured overview of all available APIs.


Architecture

Web App (your code) <-> EvenAppBridge (SDK) <-> Even App (host) <-> G2 Glasses

Your app is a standard HTML + TypeScript web page running inside a Flutter WebView hosted by the Even companion app. No special framework is required — plain Vite + TypeScript works perfectly.


Installation

bash
npm install @evenrealities/even_hub_sdk

Current version: 0.0.12


Initialization

waitForEvenAppBridge() — async, recommended

Resolves when the native bridge is ready. Always prefer this over the sync singleton.

typescript
import { waitForEvenAppBridge } from '@evenrealities/even_hub_sdk'

const bridge = await waitForEvenAppBridge()

EvenAppBridge.getInstance() — sync singleton

Only call this after the bridge has already been initialized (e.g. inside a callback that fires after waitForEvenAppBridge() resolves).

typescript
import { EvenAppBridge } from '@evenrealities/even_hub_sdk'

const bridge = EvenAppBridge.getInstance()

Required Call Order

  1. waitForEvenAppBridge() — wait for the bridge
  2. bridge.createStartUpPageContainer(container) — call exactly once at startup (required for glasses-mic audio and IMU)
  3. Everything else: audioControl, imuControl, rebuildPageContainer, event listeners, location, photo picker / camera, etc.

audioControl(true, AudioInputSource.Glasses) and imuControl will fail if createStartUpPageContainer has not succeeded first. audioControl(true, AudioInputSource.Phone), location APIs, pickImageFromAlbum, and captureImageFromCamera do not require the startup page — they route through the phone, not the glasses.


Complete Method Reference

MethodReturnsDescription
bridge.getUserInfo()Promise<UserInfo>Get the signed-in user's uid, name, avatar URL, and country
bridge.getDeviceInfo()`Promise<DeviceInfo \null>`Get connected glasses model, serial number, and status. Returns null if no device.
bridge.setLocalStorage(key, value)Promise<boolean>Persist a key-value string pair to the companion app's storage
bridge.getLocalStorage(key)Promise<string>Read a stored string by key; returns empty string if key does not exist
bridge.createStartUpPageContainer(container)Promise<StartUpPageCreateResult>One-shot startup call to define all UI containers. 0=success, 1=invalid, 2=oversize, 3=outOfMemory
bridge.rebuildPageContainer(container)Promise<boolean>Tear down and fully redraw all containers
bridge.textContainerUpgrade(container)Promise<boolean>In-place text update without full redraw (max 2000 chars per call)
bridge.updateImageRawData(data)Promise<ImageRawDataUpdateResult>Send raw pixel data to fill an image container. LZ4-compressed internally by the SDK (0.0.12+) — pass raw pixels as before. Calls must be serial — await each before the next.
bridge.shutDownPageContainer(exitMode?)Promise<boolean>Close the app. exitMode 0=exit immediately, 1=show confirmation dialog
bridge.onLaunchSource(cb)() => voidSubscribe to launch source event. Fires exactly once: 'appMenu' or 'glassesMenu'. Returns unsubscribe function.
bridge.onDeviceStatusChanged(cb)() => voidSubscribe to device status updates (connect type, battery, wearing, charging). Returns unsubscribe function.
bridge.onEvenHubEvent(cb)() => voidSubscribe to all hub events: listEvent, textEvent, sysEvent, audioEvent. Returns unsubscribe function.
bridge.audioControl(isOpen, source?)Promise<boolean>Open (true) or close (false) the microphone. source is an AudioInputSource value — Glasses (default, G2 four-mic array) or Phone (phone mic). Audio delivered as PCM via audioEvent with the source field set.
bridge.imuControl(isOpen, reportFrq?)Promise<boolean>Enable/disable IMU sensor. reportFrq is an ImuReportPace value (P100–P1000).
bridge.getAppLocation(options?)`Promise<AppLocation \null>`One-shot location read. options accepts accuracy, timeoutMs. Returns null if no fix in time, permission denied, or invalid coords.
bridge.startAppLocationUpdates(options?)Promise<boolean>Begin continuous location updates. options accepts accuracy, intervalMs, distanceFilter. Subscribe with onAppLocationChanged to receive pushes.
bridge.stopAppLocationUpdates()Promise<boolean>Stop continuous location updates started via startAppLocationUpdates.
bridge.onAppLocationChanged(cb)() => voidSubscribe to continuous-location updates. Callback receives an AppLocation. Returns an unsubscribe function.
bridge.pickImageFromAlbum()`Promise<AppImageAsset \null>`Open the phone's photo album for single-image selection. Returns null if the user cancels or denies the album permission.
bridge.captureImageFromCamera()`Promise<AppImageAsset \null>`Open the phone camera and capture one image. Returns null if the user cancels or denies the camera permission. The G2 has no on-glasses camera.
bridge.callEvenApp(method, params?)Promise<any>Low-level direct call to native bridge method. Use when higher-level methods aren't available.

TypeScript Interfaces

TextContainerProperty

Defines a text display container.

All fields are optional in the SDK constructor (accepts Partial<T>). Populate the fields your layout requires.

typescript
class TextContainerProperty {
  xPosition?: number        // 0–576, horizontal offset from left edge
  yPosition?: number        // 0–288, vertical offset from top edge
  width?: number            // 0–576, container width
  height?: number           // 0–288, container height
  borderWidth?: number      // 0–5, border thickness in pixels
  borderColor?: number      // 0–15, greyscale colour index
  borderRadius?: number     // 0–10, corner radius
  paddingLength?: number    // 0–32, inner padding in pixels
  containerID?: number      // unique integer ID for this container
  containerName?: string    // max 16 characters
  isEventCapture?: number   // 0 or 1; exactly one container per page must be 1
  zOrderIndex?: number      // stacking order, larger = front; all-or-nothing per page (0.0.12+, see Z-Order Rules)
  content?: string          // initial text content, max 1000 characters
}

ListContainerProperty

Defines a scrollable list container.

typescript
class ListContainerProperty {
  xPosition?: number        // 0–576
  yPosition?: number        // 0–288
  width?: number            // 0–576
  height?: number           // 0–288
  borderWidth?: number      // 0–5
  borderColor?: number      // 0–15
  borderRadius?: number     // 0–10
  paddingLength?: number    // 0–32
  containerID?: number
  containerName?: string    // max 16 characters
  isEventCapture?: number   // 0 or 1
  zOrderIndex?: number      // stacking order, larger = front; all-or-nothing per page (0.0.12+, see Z-Order Rules)
  itemContainer?: ListItemContainerProperty
}

ListItemContainerProperty

Defines the items within a list container.

typescript
class ListItemContainerProperty {
  itemCount?: number        // 1–20, number of items
  itemWidth?: number        // item width; 0 = auto (fills container)
  isItemSelectBorderEn?: number  // 0 or 1; 1 = show selection border around highlighted item
  itemName?: string[]       // array of item label strings; max 20 items, max 64 chars each
}

ImageContainerProperty

Defines a placeholder image container. Must be populated with updateImageRawData after creation. Image containers do not support isEventCapture — use a text container as the event-capture layer when combining with images.

typescript
class ImageContainerProperty {
  xPosition?: number        // 0–576
  yPosition?: number        // 0–288
  width?: number            // 20–288
  height?: number           // 20–144
  containerID?: number
  containerName?: string    // max 16 characters
  zOrderIndex?: number      // stacking order, larger = front; all-or-nothing per page (0.0.12+, see Z-Order Rules)
}

TextContainerUpgrade

Payload for bridge.textContainerUpgrade().

typescript
class TextContainerUpgrade {
  containerID?: number
  containerName?: string    // max 16 characters
  contentOffset?: number    // character offset to begin writing
  contentLength?: number    // number of characters to replace
  content?: string          // replacement text, max 2000 characters total
}

ImageRawDataUpdate

Payload for bridge.updateImageRawData().

typescript
class ImageRawDataUpdate {
  containerID?: number
  containerName?: string
  imageData?: number[] | string | Uint8Array | ArrayBuffer  // raw pixel data in 4-bit greyscale
}

Since 0.0.12 the SDK compresses image raw data with LZ4 internally before transfer to reduce size and update latency. Pass raw pixel data exactly as before — there is no compression flag to set.

CreateStartUpPageContainer

Parameter type for bridge.createStartUpPageContainer().

typescript
class CreateStartUpPageContainer {
  containerTotalNum?: number                    // 1–12, total number of containers
  widgetId?: number                             // auto-assigned; omit to let SDK assign
  listObject?: ListContainerProperty[]          // list containers
  textObject?: TextContainerProperty[]          // text containers, max 8
  imageObject?: ImageContainerProperty[]        // image containers, max 4
}

RebuildPageContainer

Parameter type for bridge.rebuildPageContainer(). Same shape as CreateStartUpPageContainer but without widgetId.

typescript
class RebuildPageContainer {
  containerTotalNum?: number                    // 1–12, total number of containers
  listObject?: ListContainerProperty[]          // list containers
  textObject?: TextContainerProperty[]          // text containers, max 8
  imageObject?: ImageContainerProperty[]        // image containers, max 4
}

Z-Order Rules (0.0.12+)

zOrderIndex controls front/back stacking across all containers on a page. The SDK validates these rules before the payload reaches the native bridge:

  • All-or-nothing per page — either every list/text/image container on the page sets zOrderIndex, or none do. Omitting it everywhere keeps pre-0.0.12 behavior (declaration order determines overlap).
  • Unique per page — no two containers on the same page may share a value. There is no tie-break.
  • Larger = closer to the front.

On violation the SDK logs an EvenHubPageContainerValidationErrorCode error and never calls native: createStartUpPageContainer returns StartUpPageCreateResult.invalid and rebuildPageContainer returns false.

typescript
enum EvenHubPageContainerValidationErrorCode {
  MissingZOrderIndex = 'MISSING_Z_ORDER_INDEX',     // some containers set zOrderIndex, others omit it
  InvalidZOrderIndex = 'INVALID_Z_ORDER_INDEX',     // value is not a valid number
  DuplicateZOrderIndex = 'DUPLICATE_Z_ORDER_INDEX'  // two containers share a value
}

// Run the same validation yourself before sending a page payload:
function validateEvenHubPageContainerZOrder(container: EvenHubPageContainerLike): EvenHubPageContainerValidationResult

// Human-readable message for an invalid result:
function formatEvenHubPageContainerValidationError(result): string

UserInfo

typescript
interface UserInfo {
  uid: number              // numeric user ID
  name: string             // display name
  avatar: string           // URL to avatar image
  country: string          // ISO country code or name
}

DeviceInfo

typescript
interface DeviceInfo {
  readonly model: DeviceModel    // glasses model identifier
  readonly sn: string            // serial number
  status: DeviceStatus           // current connection status object
}

DeviceStatus

typescript
interface DeviceStatus {
  sn: string
  connectType: DeviceConnectType
  isWearing?: boolean            // true if glasses are being worn
  batteryLevel?: number          // 0–100, battery percentage
  isCharging?: boolean           // true if glasses are charging
  isInCase?: boolean             // true if glasses are in the charging case

  // Instance helpers
  isNone(): boolean
  isConnected(): boolean
  isConnecting(): boolean
  isDisconnected(): boolean
  isConnectionFailed(): boolean

  // Static factory methods
  static fromJson(json: Record<string, any>): DeviceStatus
  static createDefault(sn?: string): DeviceStatus
}

AppLocation

Location payload returned by getAppLocation and pushed via onAppLocationChanged.

typescript
interface AppLocation {
  latitude: number      // degrees
  longitude: number     // degrees
  accuracy?: number     // horizontal accuracy in meters
  altitude?: number     // meters above sea level
  speed?: number        // meters per second
  heading?: number      // degrees from true north
  timestamp?: number    // Unix milliseconds
}

AppLocationOptions

Options object accepted by getAppLocation and startAppLocationUpdates. All fields optional.

typescript
interface AppLocationOptions {
  accuracy?: AppLocationAccuracy   // Low | Medium | High
  timeoutMs?: number               // one-shot only
  intervalMs?: number              // continuous only
  distanceFilter?: number          // continuous only; meters — host skips smaller pushes
}

AppImageAsset

Image payload returned by pickImageFromAlbum and captureImageFromCamera.

typescript
interface AppImageAsset {
  path: string         // host-side path; opaque to the WebView
  name: string         // original filename
  mimeType: string     // e.g. "image/jpeg", "image/png"
  size: number         // bytes
  base64: string       // inline data, ready for <img src="data:..."> or further processing
}

Event Models

EvenHubEvent

The callback type for bridge.onEvenHubEvent(cb).

typescript
interface EvenHubEvent {
  listEvent?: List_ItemEvent
  textEvent?: Text_ItemEvent
  sysEvent?: Sys_ItemEvent
  audioEvent?: AudioEventPayload
  jsonData?: Record<string, any>     // raw payload passthrough
}

AudioEventPayload

Microphone audio payload on event.audioEvent. source identifies which mic the buffer came from — useful when toggling audioControl(true, ...) between sources at runtime.

typescript
interface AudioEventPayload {
  source: AudioInputSource     // Glasses | Phone
  audioPcm: Uint8Array         // PCM 16 kHz, signed 16-bit little-endian, mono
}

Text_ItemEvent

Fires when a text container receives a user interaction.

typescript
interface Text_ItemEvent {
  containerID?: number
  containerName?: string
  eventType?: OsEventTypeList
}

List_ItemEvent

Fires when a list item is selected or scrolled.

typescript
interface List_ItemEvent {
  containerID?: number
  containerName?: string
  currentSelectItemName?: string     // label of the currently selected item
  currentSelectItemIndex?: number    // 0-based index of the selected item
  eventType?: OsEventTypeList
}

Sys_ItemEvent

System-level events including IMU data and lifecycle signals.

typescript
interface Sys_ItemEvent {
  eventType?: OsEventTypeList
  eventSource?: EventSourceType
  imuData?: IMU_Report_Data
  systemExitReasonCode?: number
}

IMU_Report_Data

Raw accelerometer/gyro values from the glasses' IMU sensor.

typescript
interface IMU_Report_Data {
  x?: number    // X-axis value
  y?: number    // Y-axis value
  z?: number    // Z-axis value
}

LaunchSource

typescript
type LaunchSource = 'appMenu' | 'glassesMenu'

Enums

typescript
enum OsEventTypeList {
  CLICK_EVENT = 0,
  SCROLL_TOP_EVENT = 1,
  SCROLL_BOTTOM_EVENT = 2,
  DOUBLE_CLICK_EVENT = 3,
  FOREGROUND_ENTER_EVENT = 4,
  FOREGROUND_EXIT_EVENT = 5,
  ABNORMAL_EXIT_EVENT = 6,
  SYSTEM_EXIT_EVENT = 7,
  IMU_DATA_REPORT = 8
}

enum DeviceConnectType {
  None = 'none',
  Connecting = 'connecting',
  Connected = 'connected',
  Disconnected = 'disconnected',
  ConnectionFailed = 'connectionFailed'
}

enum StartUpPageCreateResult {
  success = 0,
  invalid = 1,
  oversize = 2,
  outOfMemory = 3
}

enum ImageRawDataUpdateResult {
  success = "success",
  imageException = "imageException",
  imageSizeInvalid = "imageSizeInvalid",
  imageToGray4Failed = "imageToGray4Failed",
  sendFailed = "sendFailed"
}

enum EvenAppMethod {
  GetUserInfo = 'getUserInfo',
  GetGlassesInfo = 'getGlassesInfo',
  SetLocalStorage = 'setLocalStorage',
  GetLocalStorage = 'getLocalStorage',
  GetAppLocation = 'getAppLocation',
  StartAppLocationUpdates = 'startAppLocationUpdates',
  StopAppLocationUpdates = 'stopAppLocationUpdates',
  PickImageFromAlbum = 'pickImageFromAlbum',
  CaptureImageFromCamera = 'captureImageFromCamera',
  CreateStartUpPageContainer = 'createStartUpPageContainer',
  RebuildPageContainer = 'rebuildPageContainer',
  UpdateImageRawData = 'updateImageRawData',
  TextContainerUpgrade = 'textContainerUpgrade',
  AudioControl = 'audioControl',
  ImuControl = 'imuControl',
  ShutDownPageContainer = 'shutDownPageContainer'
}

enum AudioInputSource {
  Glasses = 'glasses',     // G2 four-mic array (default; requires createStartUpPageContainer first)
  Phone = 'phone'          // phone microphone (no startup-page requirement)
}

enum AppLocationAccuracy {
  Low = 'low',             // city-level — cheapest, kindest to battery
  Medium = 'medium',       // block-level — balanced default
  High = 'high'            // best available fix — most battery
}

// ImuReportPace — reporting frequency for IMU sensor data
// Value = milliseconds between reports (P100 = 100 ms = 10 Hz, P1000 = 1000 ms = 1 Hz)
enum ImuReportPace {
  P100 = 100,
  P200 = 200,
  P300 = 300,
  P400 = 400,
  P500 = 500,
  P600 = 600,
  P700 = 700,
  P800 = 800,
  P900 = 900,
  P1000 = 1000
}

enum EventSourceType {
  TOUCH_EVENT_FORM_DUMMY_NULL = 0,
  TOUCH_EVENT_FROM_GLASSES_R = 1,
  TOUCH_EVENT_FROM_RING = 2,
  TOUCH_EVENT_FROM_GLASSES_L = 3
}

enum DeviceModel {
  G1 = 'g1',
  G2 = 'g2',
  Ring1 = 'ring1'
}

Result Codes

createStartUpPageContainer / StartUpPageCreateResult

CodeNameMeaning
0successContainers created successfully
1invalidInvalid container configuration
2oversizeTotal container size exceeds display limits
3outOfMemoryInsufficient memory on device

updateImageRawData / ImageRawDataUpdateResult

NameMeaning
successImage data accepted and rendered
imageExceptionGeneric image processing error
imageSizeInvalidImage dimensions do not match container dimensions
imageToGray4FailedCould not convert image to 4-bit greyscale
sendFailedTransport error sending data to glasses

Critical Rules

  1. `createStartUpPageContainer` is one-shot — call it exactly once at startup; calling it again will not work. Use rebuildPageContainer for subsequent full redraws.
  2. Exactly one container must have `isEventCapture: 1` — this designates which container receives user input. Having zero or more than one causes undefined behavior.
  3. `zOrderIndex` is all-or-nothing per page (0.0.12+) — if any container sets it, every list/text/image container on that page must set a unique value; larger renders in front. Violations fail SDK-side validation: createStartUpPageContainer returns invalid, rebuildPageContainer returns false.
  4. Container limitscontainerTotalNum must be 1–12; textObject array max 8 items; imageObject array max 4 items.
  5. Image sends must be serialupdateImageRawData calls must be queued and awaited one at a time; concurrent calls are not supported and will cause errors.
  6. Image containers are placeholders — after createStartUpPageContainer succeeds, image containers are empty until populated via updateImageRawData.
  7. Glasses-mic `audioControl` and `imuControl` require startup to succeedaudioControl(true, AudioInputSource.Glasses) and imuControl will fail if called before createStartUpPageContainer returns StartUpPageCreateResult.success. audioControl(true, AudioInputSource.Phone), location APIs, pickImageFromAlbum, and captureImageFromCamera route through the phone and do not require the startup page.
  8. Always unsubscribe event listeners on teardownonEvenHubEvent, onDeviceStatusChanged, and onLaunchSource all return an unsubscribe function; call it when your component/page is destroyed.
  9. `onLaunchSource` fires only once — register the listener early (before or immediately after waitForEvenAppBridge) to avoid missing the event.

Canvas Specifications

PropertyValue
Resolution576 × 288 px
Colour depth4-bit greyscale (16 shades, 0 = black, 15 = white)
Coordinate origin(0, 0) at top-left
X axisIncreases rightward
Y axisIncreases downward

Host Push Format (Simulator / Testing)

The companion app (and simulator) push events into the WebView via window.postMessage. You generally do not need to handle these directly — the SDK processes them internally — but the formats are useful when writing tests or a custom simulator.

javascript
// Format 1 — named event type with jsonData wrapper
{ type: 'listen_even_app_data', method: 'evenHubEvent', data: { type: 'listEvent', jsonData: { /* event payload */ } } }

// Format 2 — snake_case event type with data wrapper
{ type: 'listen_even_app_data', method: 'evenHubEvent', data: { type: 'list_event', data: { /* event payload */ } } }

// Format 3 — array format [eventType, payload]
{ type: 'listen_even_app_data', method: 'evenHubEvent', data: ['list_event', { /* event payload */ }] }

// Audio event — audioPcm is an array of PCM sample integers; source identifies the mic
{ type: 'listen_even_app_data', method: 'evenHubEvent', data: { type: 'audioEvent', jsonData: { source: 'glasses', audioPcm: [/* numbers */] } } }

// Device status changed
{ type: 'listen_even_app_data', method: 'deviceStatusChanged', data: { sn: 'ABC123', connectType: 'connected', isWearing: true, batteryLevel: 80, isCharging: false } }

// Launch source (fires once on app open)
{ method: 'evenAppLaunchSource', data: { launchSource: 'appMenu' } }

// App location changed (pushed continuously after startAppLocationUpdates)
{ method: 'appLocationChanged', data: { latitude: 37.7749, longitude: -122.4194, accuracy: 5, timestamp: 1750000000000 } }

Task

Look up SDK reference for: $ARGUMENTS

같은 저장소의 Skills

더 많은 Skills

모든 Skills