CactusBrain Vision for Android

Add the dependency, configure a project key, prepare a model, and run detection or OCR locally. Version 0.1.0.

Android

Requirements

  • minSdk 24 or later
  • compileSdk 36
  • JDK 21
  • An arm64-v8a device or emulator image. The native runtime is built and validated for arm64 only; x86_64 is not supported.
Android

1. Add the dependency

// settings.gradle.kts
dependencyResolutionManagement {
  repositories {
    google()
    mavenCentral()
    maven { url = uri("https://cactusbrainlabs.com/maven") }
  }
}

// app/build.gradle.kts
dependencies {
  implementation("ai.cactusbrain:cactusbrain-vision:0.1.0")
}

The AAR carries its own native runtime. There is no .so to copy, no JNI to wire up, and no separate engine download.

android {
  defaultConfig {
    ndk {
      // The runtime is built and validated for arm64 only.
      abiFilters += "arm64-v8a"
    }
  }
}

Setting abiFilters keeps your APK from advertising an architecture the runtime cannot serve, which otherwise surfaces as an install-time failure on a user device rather than a build-time one on yours.

Android

2. Configure

import ai.cactusbrain.vision.CactusBrainVision

val session = CactusBrainVision.configure(
  context = applicationContext,
  projectKey = BuildConfig.CACTUSBRAIN_PROJECT_KEY,
)

Keep the key out of source control by reading it from local.properties:

// local.properties  (gitignored)
cactusbrain.projectKey=cb_live_replace_me

// app/build.gradle.kts
val projectKey: String = gradleLocalProperties(rootDir, providers)
  .getProperty("cactusbrain.projectKey", "")

android {
  defaultConfig {
    buildConfigField("String", "CACTUSBRAIN_PROJECT_KEY", "\"$projectKey\"")
  }
}
Where to get a key

Dashboard → your project → Quickstart. A live key begins cb_live_. It is displayed once.

Android

3. Prepare a model

prepare resolves, downloads, verifies and installs the model your project is entitled to, emitting progress as it goes. It is a no-op once the model is installed.

session.prepare(ModelRequest.Detect).collect { event ->
  // Checking, Downloading(received, total), Installing, Ready
  update(event)
}
Android

4. Detect objects

val output = session.detect(jpegBytes)

output.objects.forEach { obj ->
  println("${obj.label} ${obj.confidence} ${obj.boundingBox}")
}

Detection takes encoded image bytes, so your app controls the conversion. Apply the EXIF rotation before encoding, or returned coordinates will not line up with the image as the user sees it.

Android

5. Read text

val result = session.ocr(jpegBytes)
println(result.text)

// Or read with a specific model:
val premium = session.ocr(jpegBytes, using = TextModel.Premium)

Two OCR models are available: a small fast English model, and a larger multilingual one. Selecting a model does not download it — it arrives when you prepare or run it.

Android

Handling errors

try {
  session.prepare(ModelRequest.Detect).collect { update(it) }
} catch (e: ModelDeliveryError.NotEntitled) {
  // Retrying will not help. Check entitlements in the dashboard.
  showUpgradePath()
} catch (e: ModelDeliveryError.Network) {
  showRetry()
} catch (e: ModelDeliveryError.IntegrityCheckFailed) {
  // The artifact was discarded rather than installed.
  showIntegrityFailure()
} catch (e: ModelDeliveryError.UnsupportedRuntime) {
  showUnsupportedDevice()
}

Distinguish "not entitled" from "network failed". The first is a permanent answer; the second is worth a retry.

Android

Offline

Once installed, inference runs with no network connection and no per-inference server call. The network is needed to install a model, upgrade it, or install on a new device.

Android

Complete example

Android sample application →

Back to the Vision overview →