BioPass ID

BioPass ID Face Liveness SDK Flutter

Flutter Pub Instagram BioPass ID Contact us

Quick Start GuidePrerequisitesInstallationHow to useLicenseKeyFaceLivenessConfigSomething elseChangelogSupport

Quick Start Guide

First, you will need a license key to use the biopassid_face_liveness_sdk. To get your license key contact us through our website BioPass ID.

Check out our official documentation for more in depth information on BioPass ID.

1. Prerequisites:

Android iOS
Support SDK 24+ iOS 15+
- A device with a camera
- License key
- Internet connection is required to verify the license

2. Installation

First, add biopassid_face_liveness_sdk as a dependency in your pubspec.yaml file.

Android

Change the minimum Android sdk version to 24 (or higher) in your android/app/build.gradle file.

minSdkVersion 24

iOS

Requires iOS 15.0 or higher.

Add to the ios/Info.plist:

  • the key Privacy - Camera Usage Description and a usage description.

If editing Info.plist as text, add:

<key>NSCameraUsageDescription</key>
<string>Your camera usage description</string>

Then go into your project's ios folder and run pod install.

# Go into ios folder
$ cd ios

# Install dependencies
$ pod install

Privacy manifest file

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>NSPrivacyCollectedDataTypes</key>
	<array>
		<dict>
			<key>NSPrivacyCollectedDataType</key>
			<string>NSPrivacyCollectedDataTypeOtherUserContent</string>
			<key>NSPrivacyCollectedDataTypeLinked</key>
			<false/>
			<key>NSPrivacyCollectedDataTypeTracking</key>
			<false/>
			<key>NSPrivacyCollectedDataTypePurposes</key>
			<array>
				<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
			</array>
		</dict>
		<dict>
			<key>NSPrivacyCollectedDataType</key>
			<string>NSPrivacyCollectedDataTypeDeviceID</string>
			<key>NSPrivacyCollectedDataTypeLinked</key>
			<false/>
			<key>NSPrivacyCollectedDataTypeTracking</key>
			<false/>
			<key>NSPrivacyCollectedDataTypePurposes</key>
			<array>
				<string>NSPrivacyCollectedDataTypePurposeAppFunctionality</string>
			</array>
		</dict>
	</array>
	<key>NSPrivacyTracking</key>
	<false/>
	<key>NSPrivacyAccessedAPITypes</key>
	<array>
		<dict>
			<key>NSPrivacyAccessedAPITypeReasons</key>
			<array>
				<string>CA92.1</string>
			</array>
			<key>NSPrivacyAccessedAPIType</key>
			<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
		</dict>
	</array>
</dict>
</plist>

3. How to use

Basic Example

To call Face Liveness in your Flutter project is as easy as follow:

import 'package:biopassid_face_liveness_sdk/biopassid_face_liveness_sdk.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Face Liveness Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late FaceLivenessController controller;

  @override
  void initState() {
    super.initState();
    final config = FaceLivenessConfig(licenseKey: 'your-license-key');
    controller = FaceLivenessController(
      config: config,
      onFaceCapture: (image, faceAttributes) {
        print('onFaceCapture: ${image.first}');
        print('onFaceCapture: $faceAttributes');
      },
      onFaceDetected: (faceAttributes) {
        print('onFaceDetected: $faceAttributes');
      },
      debug: false,
    );
  }

  void takeFace() async {
    await controller.takeFace();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Face Liveness Demo')),
      body: Center(
        child: ElevatedButton(
          onPressed: takeFace,
          child: const Text('Capture Face'),
        ),
      ),
    );
  }
}

Example using http package to call the BioPass ID API

For this example we used the Liveness from the Multibiometrics plan.

First, add the http package. To install the http package, add it to the dependencies section of the pubspec.yaml file. You can find the latest version of the http package the pub.dev.

dependencies:
  http: <latest_version>

Additionally, in your AndroidManifest.xml file, add the Internet permission.

<!-- Required to fetch data from the internet. -->
<uses-permission android:name="android.permission.INTERNET" />

Here, you will need an API key to be able to make requests to the BioPass ID API. To get your API key contact us through our website BioPass ID.

import 'dart:convert';

import 'package:biopassid_face_liveness_sdk/biopassid_face_liveness_sdk.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Face Liveness Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late FaceLivenessController controller;

  @override
  void initState() {
    super.initState();
    final config = FaceLivenessConfig(licenseKey: 'your-license-key');
    controller = FaceLivenessController(
      config: config,
      onFaceCapture: (image, faceAttributes) async {
        // Encode image to base64 string
        final imageBase64 = base64Encode(image);

        // Create url
        final url =
            Uri.https('api.biopassid.com', 'multibiometrics/v2/liveness');

        // Create headers passing your api key
        final headers = {
          'Content-Type': 'application/json',
          'Ocp-Apim-Subscription-Key': 'your-api-key'
        };

        // Create json body
        final body = json.encode({
          'Spoof': {'Image': imageBase64}
        });

        // Execute request to BioPass ID API
        final response = await http.post(
          url,
          headers: headers,
          body: body,
        );

        // Handle API response
        print('Response status: ${response.statusCode}');
        print('Response body: ${response.body}');
      },
      onFaceDetected: (faceAttributes) {
        print('onFaceDetected: $faceAttributes');
      },
      debug: false,
    );
  }

  void takeFace() async {
    await controller.takeFace();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Face Liveness Demo')),
      body: Center(
        child: ElevatedButton(
          onPressed: takeFace,
          child: const Text('Capture Face'),
        ),
      ),
    );
  }
}

4. LicenseKey

First, you will need a license key to use the biopassid_face_liveness_sdk. To get your license key contact us through our website BioPass ID.

To use biopassid_face_liveness_sdk you need a license key. To set the license key needed is simple as setting another attribute. Simply doing:

final config = FaceLivenessConfig(licenseKey: 'your-license-key');

5. Getting face capture

You can pass a function callback to receive the captured image. You can write you own callback following this example:

final config = FaceLivenessConfig(licenseKey: 'your-license-key');
final controller = FaceLivenessController(
    config: config,
    onFaceCapture: (image, faceAttributes) {
      print('onFaceCapture: ${image.first}');
      print('onFaceCapture: $faceAttributes');
    },
    onFaceDetected: (faceAttributes) {
      print('onFaceDetected: $faceAttributes');
    },
    debug: false,
);
await controller.takeFace();

LivenessFaceAttributes

Name Type Description
faceProp double Proportion of the area occupied by the face in the image, in percentage
faceWidth int Face width, in pixels
faceHeight int Face height, in pixels
ied int Distance between left eye and right eye, in pixels
bbox Rect Face bounding box
rollAngle double The Euler angle X of the head. Indicates the rotation of the face about the axis pointing out of the image. Positive z euler angle is a counter-clockwise rotation within the image plane
pitchAngle double The Euler angle X of the head. Indicates the rotation of the face about the horizontal axis of the image. Positive x euler angle is when the face is turned upward in the image that is being processed
yawAngle double The Euler angle Y of the head. Indicates the rotation of the face about the vertical axis of the image. Positive y euler angle is when the face is turned towards the right side of the image that is being processed
leftEyeOpenProbability // Android only double? Probability that the face’s left eye is open, in percentage
rightEyeOpenProbability // Android only double? Probability that the face’s right eye is open, in percentage
smilingProbability // Android only double? Probability that the face is smiling, in percentage
averageLightIntensity double The average intensity of the pixels in the image

FaceLivenessConfig

You can also use pre-build configurations on your application, so you can automatically start using multiples services and features that better suit your application. You can instantiate each one and use it's default properties, or if you prefer you can change every config available. Here are the types that are supported right now:

FaceLivenessConfig

Name Type Default value
licenseKey String ''
resolutionPreset FaceLivenessResolutionPreset FaceLivenessResolutionPreset.veryHigh
fontFamily String 'facelivenesssdk_opensans_bold'
faceDetection FaceLivenessDetectionOptions
mask FaceLivenessMaskOptions
titleText FaceLivenessTextOptions
loadingText FaceLivenessTextOptions
helpText FaceLivenessTextOptions
feedbackText FaceLivenessFeedbackTextOptions
backButton FaceLivenessButtonOptions

Default configs:

final defaultConfig = FaceLivenessConfig(
  licenseKey: '',
  resolutionPreset: FaceLivenessResolutionPreset.veryHigh,
  fontFamily: 'facelivenesssdk_ic_close',
  faceDetection: FaceLivenessDetectionOptions(
    timeToCapture: 3000,
    maxFaceDetectionTime: 60000,
    minFaceProp: 0.1,
    maxFaceProp: 0.4,
    minFaceWidth: 150,
    minFaceHeight: 150,
    ied: 90,
    bboxPad: 20,
    faceDetectionThresh: 0.5,
    rollThresh: 4.0,
    pitchThresh: 4.0,
    yawThresh: 4.0,
    closedEyesThresh: 0.7, // Android only
    smilingThresh: 0.7, // Android only
    tooDarkThresh: 50,
    tooLightThresh: 170,
    faceCentralizationThresh: 0.05,
  ),
  mask: FaceLivenessMaskOptions(
    enabled: true,
    backgroundColor: const Color(0xCC000000),
    frameColor: const Color(0xFFFFFFFF),
    frameEnabledColor: const Color(0xFF16AC81),
    frameErrorColor: const Color(0xFFE25353),
  ),
  titleText: FaceLivenessTextOptions(
    enabled: true,
    content: 'Capturing Face',
    textColor: const Color(0xFFFFFFFF),
    textSize: 20,
  ),
  loadingText: FaceLivenessTextOptions(
    enabled: true,
    content: 'Processing...',
    textColor: const Color(0xFFFFFFFF),
    textSize: 14,
  ),
  helpText: FaceLivenessTextOptions(
    enabled: true,
    content: 'Fit your face into the shape below',
    textColor: const Color(0xFFFFFFFF),
    textSize: 14,
  ),
  feedbackText: FaceLivenessFeedbackTextOptions(
    enabled: true,
    messages: FaceLivenessFeedbackTextMessages(
      noDetection: 'No faces detected',
      multipleFaces: 'Multiple faces detected',
      faceCentered: 'Face centered. Do not move',
      tooClose: 'Turn your face away',
      tooFar: 'Bring your face closer',
      tooLeft: 'Move your face to the right',
      tooRight: 'Move your face to the left',
      tooUp: 'Move your face down',
      tooDown: 'Move your face up',
      invalidIED: 'Invalid inter-eye distance',
      faceAngleMisaligned: 'Misaligned face angle',
      closedEyes: 'Open your eyes', // Android only
      smiling: 'Do not smile', // Android only
      tooDark: 'Too dark',
      tooLight: 'Too light',
    ),
    textColor: const Color(0xFFFFFFFF),
    textSize: 14,
  ),
  backButton: FaceLivenessButtonOptions(
    enabled: true,
    backgroundColor: const Color(0x00000000),
    buttonPadding: 0,
    buttonSize: const Size(56, 56),
    iconOptions: FaceLivenessIconOptions(
      enabled: true,
      iconFile: 'facelivenesssdk_ic_close',
      iconColor: const Color(0xFFFFFFFF),
      iconSize: const Size(32, 32),
    ),
    labelOptions: FaceLivenessTextOptions(
      enabled: false,
      content: 'Back',
      textColor: const Color(0xFFFFFFFF),
      textSize: 14,
    ),
  ),
);

FaceLivenessDetectionOptions

Name Type Default value Description
timeToCapture int 3000 Time it takes to perform an automatic capture, in miliseconds
maxFaceDetectionTime int 60000 Maximum facial detection attempt time, in miliseconds
minFaceProp double 0.1 Minimum limit of the proportion of the area occupied by the face in the image, in percentage
maxFaceProp double 0.4 Maximum limit on the proportion of the area occupied by the face in the image, in percentage
minFaceWidth int 150 Minimum face width, in pixels
minFaceHeight int 150 Minimum face height, in pixels
ied int 90 Minimum distance between left eye and right eye, in pixels
bboxPad int 20 Padding the face's bounding box to the edges of the image, in pixels
faceDetectionThresh double 0.5 Minimum trust score for a detection to be considered valid. Must be a number between 0 and 1, which 0.1 would be a lower face detection trust level and 0.9 would be a higher trust level
rollThresh double 4.0 The Euler angle X of the head. Indicates the rotation of the face about the axis pointing out of the image. Positive z euler angle is a counter-clockwise rotation within the image plane
pitchThresh double 4.0 The Euler angle X of the head. Indicates the rotation of the face about the horizontal axis of the image. Positive x euler angle is when the face is turned upward in the image that is being processed
yawThresh double 4.0 The Euler angle Y of the head. Indicates the rotation of the face about the vertical axis of the image. Positive y euler angle is when the face is turned towards the right side of the image that is being processed
closedEyesThresh // Android only double 0.7 Minimum probability threshold that the left eye and right eye of the face are closed, in percentage. A value less than 0.7 indicates that the eyes are likely closed
smilingThresh // Android only double 0.7 Minimum threshold for the probability that the face is smiling, in percentage. A value of 0.7 or more indicates that a person is likely to be smiling
tooDarkThresh int 50 Minimum threshold for the average intensity of the pixels in the image
tooLightThresh int 170 Maximum threshold for the average intensity of the pixels in the image
faceCentralizationThresh double 0.05 Threshold to consider the face centered, in percentage

FaceLivenessMaskOptions

Name Type Default value
enabled bool true
backgroundColor Color Color(0xCC000000)
frameColor Color Color(0xFFFFFFFF)
frameEnabledColor Color Color(0xFF16AC81)
frameErrorColor Color Color(0xFFE25353)

FaceLivenessFeedbackTextOptions

Name Type Default value
enabled bool true
messages FaceLivenessFeedbackTextMessages FaceLivenessFeedbackTextMessages()
textColor Color Color(0xFFFFFFFF)
textSize int 14

FaceLivenessFeedbackTextMessages

Name Type Default value
noDetection String 'No faces detected'
multipleFaces String 'Multiple faces detected'
faceCentered String 'Face centered. Do not move'
tooClose String 'Turn your face away'
tooFar String 'Bring your face closer'
tooLeft String 'Move your face to the right'
tooRight String 'Move your face to the left'
tooUp String 'Move your face down'
tooDown String 'Move your face up'
invalidIED String 'Invalid inter-eye distance'
faceAngleMisaligned String 'Misaligned face angle'
closedEyes // Android only String 'Open your eyes'
smiling // Android only String 'Do not smile'
tooDark String 'Too dark'
tooLight String 'Too light'

FaceLivenessButtonOptions

Name Type Default value
enabled bool true
backgroundColor Color Color(0xFFFFFFFF)
buttonPadding int 0
buttonSize Size Size(56, 56)
iconOptions FaceLivenessIconOptions
labelOptions FaceLivenessTextOptions

FaceLivenessIconOptions

Name Type Default value
enabled bool true
iconFile String 'facelivenesssdk_ic_close'
iconColor Color Color(0xFF323232)
iconSize Size Size(32, 32)

FaceLivenessTextOptions

Name Type Default value
enabled bool true
content String ''
textColor Color Color(0xFF323232)
textSize int 14

FaceLivenessResolutionPreset (enum)

Name Resolution
FaceLivenessResolutionPreset.high 720p (1280x720)
FaceLivenessResolutionPreset.veryHigh 1080p (1920x1080)

How to change font family

on Android side

You can use the default font family or set one of your own. To set a font family, create a folder font under res directory in your android/app/src/main/res. Download the font which ever you want and paste it inside font folder. All font file names must be only: lowercase a-z, 0-9, or underscore. The structure should be some thing like below.

on iOS side

To add the font files to your Xcode project:

  1. In Xcode, select the Project navigator.
  2. Drag your fonts from a Finder window into your project. This copies the fonts to your project.
  3. Select the font or folder with the fonts, and verify that the files show their target membership checked for your app’s targets.

Then, add the "Fonts provided by application" key to your app’s Info.plist file. For the key’s value, provide an array of strings containing the relative paths to any added font files.

In the following example, the font file is inside the fonts directory, so you use fonts/roboto_mono_bold_italic.ttf as the string value in the Info.plist file.

on Dart side

Finally, just set the font family passing the name of the font file when instantiating FaceLivenessConfig in your Flutter app.

final config = FaceLivenessConfig(
  licenseKey: 'your-license-key',
  fontFamily: 'roboto_mono_bold_italic',
);

How to change icon

on Android side

You can use the default icons or define one of your own. To set a icon, download the icon which ever you want and paste it inside drawable folder in your android/app/src/main/res. All icon file names must be only: lowercase a-z, 0-9, or underscore. The structure should be some thing like below.

on iOS side

To add icon files to your Xcode project:

  1. In the Project navigator, select an asset catalog: a file with a .xcassets file extension.
  2. Drag an image from the Finder to the outline view. A new image set appears in the outline view, and the image asset appears in a well in the detail area.

on Dart side

Finally, just set the icon passing the name of the icon file when instantiating FaceLivenessConfig in your Flutter app.

final config = FaceLivenessConfig(licenseKey: 'your-license-key');
// Changing back button icon
config.backButton.iconOptions.iconFile = 'ic_baseline_camera';

Something else

Do you like the Face SDK and would you like to know about our other products? We have solutions for fingerprint detection and digital signature capture.

Changelog

v1.0.5

  • Documentation update;
  • Connection timeout for license activation removed on Android;
  • Added face detection on iOS;
  • Added auto capture on iOS.

v1.0.4

  • Documentation update;
  • Fixed a bug where the maximum detection time was reset even after the SDK was closed.

v1.0.3

  • Documentation update;
  • Fixed validation of facial angles.

v1.0.2

  • Documentation update;
  • Fix in the drawing of the face's bounding box, which was inverted on the X axis, on Android.

v1.0.1

  • Documentation update;
  • Upgrade from Camera2 to CameraX on Android;
  • FaceLivenessFaceCaptureResult renamed to LivenessFaceAttributes;
  • New feedback message specific to invalid IED;
  • New faceCentralizationThresh in FaceLivenessDetectionOptions;
  • New debug parameter:
    • If debug=true, the facial detection attributes that result in an invalid face will be printed in the UI;
    • If debug=true, the face rectangle will be drawn in the UI.
  • Bug fixes for face centering on Android;
  • Fixed a bug that caused the onFaceCapture callback to crash on some devices on Android.

v1.0.0

  • Added documentation;
  • Added face detection on Android;
  • Added auto capture on Android.