Flutter
Use Nosmai Moderation in a Flutter app: image, video, text and live-camera moderation.
Install
Add the plugin to pubspec.yaml, then run 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 and NSCameraUsageDescription to Info.plist (the example uses permission_handler). For iOS App Store uploads also set ITSAppUsesNonExemptEncryption to NO in Info.plist, since the SDK only encrypts its own bundled models, which is export-compliance exempt.
NOTE
Distribute Android as an App Bundle (AAB). The SDK ships arm64-v8a only, so Play hides it from 32-bit-only devices, and it does not 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 (for example 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 or 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 and 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 or no camera
);
await NosmaiLive.start(facing: NosmaiCameraFacing.back); // .front is also supported, and
// 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.