Moderation · Android
Use Nosmai Moderation in a native Android (Kotlin) app — image, video, text and live-camera moderation.
Install
- Download the latest
nosmai-detection.aarfrom the releases page. - Put it in your app module’s
libs/folder (e.g.app/libs/nosmai-detection.aar). - Reference it in Gradle (below). The SDK is self-contained — everything runs on-device and all models are bundled, so there are no extra dependencies to add.
android {
defaultConfig {
minSdk = 24
ndk { abiFilters += "arm64-v8a" } // the SDK ships arm64-v8a
}
}
dependencies {
implementation(files("libs/nosmai-detection.aar"))
// CameraX — only needed for the live-camera path
val camerax = "1.4.2"
implementation("androidx.camera:camera-core:$camerax")
implementation("androidx.camera:camera-camera2:$camerax")
implementation("androidx.camera:camera-lifecycle:$camerax")
implementation("androidx.camera:camera-view:$camerax")
}
Permissions (AndroidManifest.xml): INTERNET (license check) and CAMERA (live only).
Initialize
init is blocking (network + model load) — call it off the main thread. Returns false if the license is invalid/expired.
import com.nosmai.detection.NosmaiSDK
Executors.newSingleThreadExecutor().execute {
val ok = NosmaiSDK.init(context, "NOSMAI-XXXX")
}
Moderate an image
val bitmap = BitmapFactory.decodeFile(path)
val r = NosmaiSDK.analyzeImage(bitmap) // NosmaiResult
if (r.isUnsafe) {
r.detections.forEach { Log.d("Mod", "${it.category} ${it.confidence}") }
// r.nsfw -> SAFE / WARN / BLOCK
}
Moderate a video
NosmaiSDK.analyzeVideo(
context, uri, frameIntervalMs = 500L,
onProgress = { p -> /* 0..1 */ },
onComplete = { v -> /* v.isUnsafe, v.categories, v.flags */ },
)
Moderate text
Call init first — it validates the license; initText needs that before it can load the (encrypted) text model.
NosmaiSDK.initText(context) // after init(), off the main thread
val t = NosmaiSDK.moderateText("some message") // NosmaiTextResult
if (t.blocked) Log.d("Mod", "${t.category} via ${t.layer} (${t.matchedWord})")
Live camera (CameraX)
Feed CameraX frames to pushFrame; results arrive on the main thread via NosmaiListener.
NosmaiSDK.startStream(object : NosmaiListener {
override fun onResult(r: NosmaiResult) { /* every frame */ }
override fun onUnsafe(r: NosmaiResult) { /* turned unsafe */ }
override fun onSafe() { /* recovered */ }
})
val analysis = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.setOutputImageRotationEnabled(true)
.build()
.also { it.setAnalyzer(executor) { proxy -> NosmaiSDK.pushFrame(proxy) } }
cameraProvider.bindToLifecycle(owner, CameraSelector.DEFAULT_BACK_CAMERA, preview, analysis)
// on leave
NosmaiSDK.stopStream()
Thresholds & performance
NosmaiSDK.setThreshold(NosmaiCategory.WEAPON, 0.7f)
NosmaiSDK.setNsfwThreshold(NosmaiNsfwClass.EXPLICIT, 0.45f) // BLOCK
NosmaiSDK.setNsfwThreshold(NosmaiNsfwClass.SEXY, 0.55f) // WARN
// Live-only: how often the (heavier) object detector runs. NSFW always runs
// every frame. HIGH = snappiest, LOW = battery saver.
NosmaiSDK.setPerformanceMode(NosmaiPerformanceMode.HIGH)
Cleanup
NosmaiSDK.shutdown()
NOTE
All NosmaiListener callbacks are delivered on the main thread, so you can update UI directly.