facecore 0.3.0 copy "facecore: ^0.3.0" to clipboard
facecore: ^0.3.0 copied to clipboard

Self-contained Flutter plugin for camera-based face liveness, depth, and anti-spoof checks before capturing a photo on Android and iOS.

facecore #

A self-contained Flutter plugin with two native capture flows on Android and iOS:

  • Liveness capture — front-camera face liveness with challenge actions (blink, turn left, turn right) plus motion + depth anti-spoof gating.
  • Anti-spoof capture — generic capture on either lens with a shutter button gated by depth, moiré, refresh-banding, and screen-edge checks. Use it when you want to make sure the user is photographing a real-world scene and not a phone screen, monitor, or printed banner.

Your Dart code calls one method per flow; the platform side handles camera permission, preview, signal analysis, and image capture.

Features #

  • Native UI on Android (CameraX + ML Kit) and iOS (AVFoundation + Vision).
  • Generic anti-spoof flow with shutter gated by:
    • 2D-FFT moiré detection (catches screen subpixel patterns).
    • Row-mean refresh-banding detection (catches LCD/OLED refresh stripes).
    • Depth analysis — real AVDepthData on TrueDepth / LiDAR iOS devices, parallax-based depth proxy elsewhere.
    • Rectangular screen-edge detection.
  • Configurable fail-closed vs fail-open behaviour when the device has no depth sensor.
  • Returns the saved JPEG path plus per-signal telemetry.

Platform support #

Platform Minimum version
Android API 21
iOS 13.0

Installation #

dependencies:
  facecore: ^0.2.0

Android #

Camera permission is declared by the plugin. No additional setup required.

iOS #

Add a usage description to your app's ios/Runner/Info.plist:

<key>NSCameraUsageDescription</key>
<string>This app uses the camera to verify your identity.</string>

Liveness capture #

import 'package:facecore/facecore.dart';

final facecore = Facecore();

final result = await facecore.captureWithLiveness(
  config: const LivenessConfig(
    actions: [
      LivenessAction.blink,
      LivenessAction.turnLeft,
      LivenessAction.turnRight,
    ],
    title: 'Verify your identity',
    subtitle: 'Follow the prompts to confirm you are present.',
  ),
);

if (result == null) {
  return; // User cancelled.
}
print('Saved to: ${result.imagePath}');

Detecting depth-camera availability #

requireDepthHardware: true will refuse to enable the shutter on any device without a depth-capable lens. Decide which mode to use at runtime:

final hasDepth = await facecore.hasDepthCamera(lens: CameraLens.back);

final result = await facecore.captureWithAntiSpoof(
  config: AntiSpoofConfig(
    lens: CameraLens.back,
    requireDepthHardware: hasDepth, // fail-closed only if we can actually use depth
  ),
);

On iOS this checks for TrueDepth / LiDAR cameras; on Android it scans for a camera reporting the DEPTH_OUTPUT capability.

Anti-spoof capture #

final result = await facecore.captureWithAntiSpoof(
  config: const AntiSpoofConfig(
    lens: CameraLens.back,
    enableDepth: true,
    requireDepthHardware: false, // fail-open on non-depth devices
    enableMoire: true,
    enableBanding: true,
    enableScreenEdge: true,
    title: 'Capture',
    subtitle: 'Hold steady — verifying the scene is real.',
  ),
);

if (result == null) {
  return; // User cancelled.
}
print('Saved to: ${result.imagePath}');
print('Moiré score:   ${result.moireScore}');
print('Banding score: ${result.bandingScore}');
print('Depth range:   ${result.depthRange}');

The native screen shows a "Verifying…" overlay and keeps the shutter button disabled until every enabled signal passes for a few consecutive frames. The user then taps the shutter to capture. captureWithAntiSpoof returns null on cancel and throws FaceCaptureException on failure (permission denied, camera unavailable, depth hardware required but missing).

See example/ for a runnable demo with toggles for every signal.

AntiSpoofConfig knobs #

Field Default Purpose
lens back Which camera lens to use (front or back).
enableDepth true Run the depth analysis signal.
requireDepthHardware false Fail-closed on devices without a depth sensor.
enableMoire true Run 2D-FFT moiré detection.
enableBanding true Run row-mean refresh-banding detection.
enableScreenEdge true Run rectangular screen-edge detection.
minDepthRange 8.0 Minimum depth range across the scene.
maxMoireScore 0.45 Maximum moiré score (0 = none, 1 = strong).
maxBandingScore 0.40 Maximum banding score.
maxScreenEdgeFraction 0.70 Maximum frame fraction occupied by a detected screen edge.
jpegQuality 90 JPEG quality for the saved capture.
title, subtitle null Optional native screen labels.

⚠️ Tuning note: anti-spoof thresholds are starting points. Validate against your target hardware and adjust — a tight maxMoireScore can false-positive on patterned fabric; a loose maxBandingScore may miss high-refresh OLED screens.

LivenessConfig knobs #

Field Default Purpose
actions [blink, turnLeft, turnRight] Ordered list of liveness challenges to run.
requireDepth false Require depth data; rejects flat-image spoofs on supported devices.
minFaceFraction 0.18 Minimum face area as a fraction of the frame.
maxFaceFraction 0.85 Maximum face area (too close).
minMotionStdDev 1.5 Minimum motion variance to accept the capture.
minDepthRange 6.0 Minimum depth range when requireDepth is true.
holdFrames 6 Frames the user must hold the target pose.
jpegQuality 90 JPEG quality (1–100) for the saved capture.
title, subtitle null Optional native screen labels.

License #

MIT — see LICENSE.

0
likes
0
points
58
downloads

Publisher

unverified uploader

Weekly Downloads

Self-contained Flutter plugin for camera-based face liveness, depth, and anti-spoof checks before capturing a photo on Android and iOS.

Repository
View/report issues

Topics

#face-detection #liveness #camera #biometrics #anti-spoofing

License

unknown (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on facecore

Packages that implement facecore