flutter_face_liveness 2.3.0
flutter_face_liveness: ^2.3.0 copied to clipboard
Production-ready Flutter SDK for face detection, liveness verification, and anti-spoof protection using ML Kit and TensorFlow Lite.
2.3.0 #
Improvements #
- Added Swift Package Manager (SPM) support for iOS —
ios/flutter_face_liveness/Package.swiftadded with correctSources/structure
Bug Fixes #
- Removed unnecessary
as List<double>cast inTFLiteService._runInference()(line 88) — type was already inferred correctly fromList.filled - Removed unused
_Float32Reshapeextension onFloat32List—reshape()call it depended on was already commented out
2.2.0 #
Improvements #
- Added banner image to README for pub.dev and GitHub documentation
- Upgraded Android Gradle Plugin to 8.9.1 (required by
androidx.camera:1.6.0) - Upgraded Gradle wrapper to 8.11.1
- Updated
permission_handlerto^12.0.1(requires Flutter 3.24+ / Dart 3.5+) - Example app Face ID history screen — locally stores and displays all registered Face IDs with match/new status
2.0.0 #
New Features #
Persistent Face Identity (Face ID)
FaceIdentityService— assigns a stableFID-XXXXidentifier to each unique face that persists across all app sessions usingSharedPreferencesFaceEmbeddingModel— wraps a FaceNet TFLite model (128-dim L2-normalised embeddings); model is auto-downloaded on first use (~23 MB, cached permanently)FaceModelDownloader— streaming HTTP download with progress callback; primary URL + fallback URL; re-downloads automatically if the cached file is corruptedFacePreprocessor— crops + resizes face region to 160×160, normalises pixels to[-1, 1]; runs in acompute()isolate; handles both NV21 (Android) and BGRA8888 (iOS) inputLivenessConfig.enableFaceIdflag (defaultfalse) — zero-config opt-in; no model file to bundleLivenessConfig.faceIdSimilarityThreshold(default0.65) — cosine-similarity cutoff for same-face matchingLivenessResult.faceId— returned alongsidesessionIdon successful verificationLivenessController.clearFaceIdentities()— removes all stored embeddings (e.g. on logout)- Embedding adaptation — stored embedding is updated toward each confirmed new observation (
75% old + 25% new, then re-normalised) so the template improves over time
Isolate-based ML Preprocessing
FrameProcessor— YUV→NV21 conversion, brightness, blur score, and FNV-1a hash all computed in a backgroundcompute()isolate; UI thread stays at 60 fps
Frame Quality Validation
- Per-frame brightness check with debounce (6 consecutive bad frames required before reporting
lowLight/overExposed, absorbing camera auto-exposure settling time) - Platform-correct brightness calculation: iOS BGRA8888 uses BT.601 luminance (
Y = (77R + 150G + 29B) >> 8); Android NV21 uses Y-plane directly - Blur detection via Y-plane variance
Anti-Spoof Engine
- 7-signal composite scoring: eye variance, face geometry, head pose naturalness, eye-open probability, face tracking continuity, micro-motion (yaw/pitch variance), and frame quality
- Rolling 12-frame history — no model file required
Security
SessionManager— cryptographically unique session IDs usingRandom.secure()(12-char timestamp hex + 8-char secure random hex, e.g.LV-018F3A2B9C4E-D7E31F08)FrameHasher— FNV-1a sliding-window replay detection- Fisher-Yates shuffle for randomised action sequences
New Liveness Action
LivenessAction.openMouth— detected via bounding-box height growth (>8%) with low smile probability
UI
LivenessStepIndicator— animated progress dots for current / completed / remaining steps- Download-progress loading screen — shows
%while FaceNet model downloads on first run - Dark / light theme support via
LivenessConfig.themeMode @Deprecated showDebugInfo— replaced byLivenessConfig.showDebugOverlay
New Exports
FaceIdentityService,FaceModelDownloader,FaceModelDownloadExceptionAntiSpoofEngine,AntiSpoofResult,TFLiteServiceSessionManager,RawFrameData
Bug Fixes #
- iOS brightness falsely reported as "too dark" — single-plane BGRA frames were being sampled as if they were NV21 Y-plane data (Blue channel average ≠ luminance); fixed with BT.601 per-pixel luminance
- iOS face crop height clamping —
_resampleBgrausedw-1for both axes; portrait/landscape frames could produce out-of-bounds crops; fixed toh-1for the Y axis - iOS raw frame bytes mismatch —
RawFrameDatastored NV21-converted bytes even on iOS whereFacePreprocessorexpects BGRA8888; now storesimage.planes[0].bytes(original BGRA) on iOS - Same face → different Face ID — similarity threshold
0.78was too strict for cross-session lighting/angle variation; lowered to0.65; stored embedding now adapts toward each confirmed match - Session ID collision — old generator used deterministic XOR of timestamp; replaced with
Random.secure() tflite_flutter 0.10.4compilation failure on Dart ≥ 3.4 —UnmodifiableUint8ListViewwas removed fromdart:typed_data; resolved by overriding totflite_fluttergitmain(v0.12.1)completedActions/remainingActionsnot defined onLivenessController— fixed broken_EngineSequenceextension; getters added directly to controllerbrightness > 0.90false overexposure — threshold raised to0.92to match real sensor output
Breaking Changes #
- Android
minSdkVersionraised from 21 → 26 — required bytflite_flutter 0.12.1 LivenessResultgains optionalfaceIdfield (non-breaking;nullwhenenableFaceIdisfalse)brightnessMindefault changed from0.20→0.12brightnessMaxdefault changed from0.90→0.92
Dependencies Added #
tflite_flutter: (git main — v0.12.1)
shared_preferences: ^2.2.2
http: ^1.2.1
path_provider: ^2.1.3
1.0.0 #
- Initial release
- Real-time face detection via Google ML Kit Face Detection
- Liveness actions: blink, turnLeft, turnRight, lookUp, lookDown, smile
- Anti-spoofing heuristic validator (5-signal composite score)
- Animated face overlay with status indicator and progress bar
- Clean architecture: Camera → ML → Liveness engine → UI layers
- Full null-safety support (Dart 3 / Flutter 3.10+)
- Android API 21+ and iOS 13+ support
- Example app with standard and custom challenge modes