Moderation · Flutter
Use Nosmai Moderation in a Flutter app — image, video, text and live-camera moderation.
Install
Add the plugin to pubspec.yaml, then flutter pub get.
dependencies:
nosmai_moderation_sdk: ^1.0.0
Android — bundle the native AAR in your host app. Download nosmai-detection.aar from the Android releases, put it in android/app/libs/, and reference it:
android {
defaultConfig {
minSdk = 24
ndk { abiFilters += "arm64-v8a" }
}
}
dependencies {
implementation(files("libs/nosmai-detection.aar"))
}
iOS needs no extra step — pod install pulls the native SDK with the plugin.
Requirements: Flutter 3+, Android minSdk 24 (arm64-v8a), iOS 14+. For live camera add the camera permission to AndroidManifest.xml / NSCameraUsageDescription in Info.plist (the example uses permission_handler). For iOS App Store uploads also set ITSAppUsesNonExemptEncryption = NO in Info.plist (the SDK only encrypts its own bundled models — export-compliance exempt).
Distribute Android as an App Bundle (AAB) — the SDK ships
arm64-v8aonly, so Play hides it from 32-bit-only devices, and it won’t run on x86_64 emulators.
Initialize
Call once at startup with your license key. It runs natively on a background thread.
import 'package:nosmai_moderation_sdk/nosmai_moderation_sdk.dart';
final res = await NosmaiModeration.initialize('NOSMAI-XXXX');
if (!res.success) {
debugPrint('Nosmai init failed: ${res.error}');
}
Moderate an image
Pass a file path (e.g. from image_picker). Returns a NosmaiResult.
final r = await NosmaiModeration.analyzeImage(file.path);
if (r.isUnsafe) {
// r.detections -> [{category, confidence}], r.nsfw -> safe/warn/block
for (final d in r.detections) {
print('${d?.category?.name} ${(d!.confidence! * 100).round()}%');
}
}
Moderate a video
Samples one frame every frameIntervalMs and aggregates.
final v = await NosmaiModeration.analyzeVideo(file.path, 500);
if (v.isUnsafe) {
print('categories: ${v.categories}, frames: ${v.framesAnalyzed}');
}
Moderate text
Call initialize first (it validates the license), then load the text model once (it is larger), then moderate messages.
await NosmaiModeration.initializeText(); // after initialize()
final t = await NosmaiModeration.moderateText('some message');
if (t.blocked) {
// t.layer (blocklist/classifier), t.category, t.matchedWord
print('blocked: ${t.category?.name}');
}
Live camera
The camera, frame capture and detection all run natively; only the per-frame NosmaiResult crosses to Dart.
import 'package:permission_handler/permission_handler.dart';
// 1. show the native preview
const NosmaiCameraPreview();
// 2. start + listen, after granting camera permission
await Permission.camera.request();
final sub = NosmaiLive.results().listen(
(r) => setState(() => _verdict = r.isUnsafe ? 'UNSAFE' : 'SAFE'),
onError: (e) => debugPrint('camera failed to start: $e'), // permission / no camera
);
await NosmaiLive.start(facing: NosmaiCameraFacing.back); // .front also supported; falls
// back to the other if unavailable
// 3. on leave — always stop, the camera does not stop itself on widget dispose
await NosmaiLive.stop();
sub.cancel();
Thresholds
Adjust any object class or NSFW bar at runtime (lower is stricter).
NosmaiModeration.setThreshold(NosmaiCategory.weapon, 0.7);
NosmaiModeration.setNsfwThreshold(NosmaiNsfwClass.explicit, 0.45); // BLOCK
NosmaiModeration.setNsfwThreshold(NosmaiNsfwClass.sexy, 0.55); // WARN
Cleanup
NosmaiModeration.shutdown();
NOTE
analyzeImage, analyzeVideo, moderateText and initialize are async — they run native inference off the platform thread, so the UI never blocks.