BioPass ID Face Liveness SDK Flutter
Quick Start Guide • Prerequisites • Installation • How to use • LicenseKey • FaceLivenessConfig • Something else • Changelog • Support
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:
- In Xcode, select the Project navigator.
- Drag your fonts from a Finder window into your project. This copies the fonts to your project.
- 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:
- In the Project navigator, select an asset catalog: a file with a .xcassets file extension.
- 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.
- Face SDK
- Fingerprint SDK
- Signature SDK
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.