full_identity_verification 2.1.8
full_identity_verification: ^2.1.8 copied to clipboard
Flutter plugin for Blusalt Full Identity Verification SDK that supports both Android and iOS platforms.
full_identity_verification #
Full Identity Verification SDK for Android and iOS — document scanning combined with liveness detection.
Get your credentials from Blusalt
Features #
SDK Modes #
1. Full Identity SDK (Document Present)
The user physically scans their document. The SDK extracts document data and runs a liveness check in a single flow. Optionally filter which document types are available.
2. Document Absent — Custom Selector
No physical document is available. The user selects their document type from a list you provide, enters their ID number, and completes a liveness check.
3. Document Absent — ID Number
No physical document is available. You already know the document type and number; pass them directly and the SDK runs only the liveness check.
Liveness Types (LivenessFacialComparisonType) #
| Value | Description |
|---|---|
dynamic |
User performs head movements (open mouth, shake head). Strictest — static images are detected and rejected. |
action |
User performs a prompted action. High security. |
varifocal |
Camera-based depth detection. Good balance of speed and security. |
flash |
Screen-flash method. Works well in low-light conditions. |
Usage #
dependencies:
full_identity_verification: ^2.1.4
import 'package:full_identity_verification/full_identity_verification.dart';
import 'package:full_identity_verification/enums.dart';
import 'package:full_identity_verification/model.dart';
Initialize #
final _plugin = BlusaltFullIdentityVerification();
1. Full Identity SDK (Document Present) #
/// [documentTypeList] filters which document types appear in the SDK.
/// Pass null to show all types.
///
/// [timeoutDurationInSec] overrides the network timeout (default 120 s).
///
/// [enableEncryption] enables bi-directional payload encryption (default false).
///
/// [metadata] optional key-value pairs forwarded to the native SDK as-is.
startFullIdentitySDK() async {
final result = await _plugin.startFullIdentitySDK(
apiKey: 'your_api_key',
appName: 'your_app_name',
clientId: 'your_client_id',
isDev: true, // set false for production
reference: 'unique_reference', // optional
webhookUrl: 'https://your-webhook.com', // optional
documentTypeList: [
DocumentType.bvn,
DocumentType.nin,
DocumentType.passport,
DocumentType.driverLicense,
DocumentType.pvc,
],
timeoutDurationInSec: 120,
enableEncryption: false,
livenessFacialComparisonType: LivenessFacialComparisonType.dynamic,
showLivenessResult: false,
metadata: {'userId': 'user_001', 'sessionId': 'abc-456'}, // optional
);
if (result?.blusaltFullIdentityProcess == BlusaltFullIdentityProcess.completed) {
final doc = result!.fullIdentitySuccessData?.extractedDocumentData;
final live = result.fullIdentitySuccessData?.livenessSuccessData;
debugPrint('Name: ${doc?.firstName} ${doc?.lastName}');
debugPrint('Liveness passed: ${live?.isPassProcedureValidation}');
} else {
debugPrint('Error ${result?.code}: ${result?.message}');
}
}
2. Document Absent — Custom Selector #
/// [documentTypeList] defines which document types the user can pick from.
///
/// [livenessFacialComparisonType] controls the liveness method used.
///
/// [thresholdConfig] controls face-comparison strictness.
/// Pass null to use the SDK server default.
///
/// [metadata] optional key-value pairs forwarded to the native SDK as-is.
startDocAbsentWithCustomSelector() async {
final result = await _plugin.startDocAbsentWithCustomSelector(
apiKey: 'your_api_key',
appName: 'your_app_name',
clientId: 'your_client_id',
isDev: true,
documentTypeList: [DocumentType.bvn, DocumentType.nin],
reference: 'unique_reference',
webhookUrl: 'https://your-webhook.com',
livenessFacialComparisonType: LivenessFacialComparisonType.dynamic,
showLivenessResult: false,
thresholdConfig: ThresholdConfig(
localThreshold: 85.0,
priority: ThresholdPriority.serverWithLocalFallback,
),
timeoutDurationInSec: 120,
enableEncryption: false,
metadata: {'userId': 'user_001', 'sessionId': 'abc-456'}, // optional
);
if (result?.blusaltFullIdentityProcess == BlusaltFullIdentityProcess.completed) {
// handle success
} else {
debugPrint('Error ${result?.code}: ${result?.message}');
}
}
3. Document Absent — ID Number #
/// [documentType] specifies the document type to verify against.
///
/// [documentNumber] is the ID number (e.g. BVN, NIN, passport number).
///
/// [startProcessOnGettingToFirstScreen] skips the "Continue" button on the
/// SDK's first screen and starts the process automatically.
///
/// [metadata] optional key-value pairs forwarded to the native SDK as-is.
startDocAbsentWithIdNumber() async {
final result = await _plugin.startDocAbsentWithIdNumber(
apiKey: 'your_api_key',
appName: 'your_app_name',
clientId: 'your_client_id',
isDev: true,
documentType: DocumentType.bvn,
documentNumber: '12345678901',
reference: 'unique_reference',
webhookUrl: 'https://your-webhook.com',
startProcessOnGettingToFirstScreen: false,
livenessFacialComparisonType: LivenessFacialComparisonType.dynamic,
showLivenessResult: false,
thresholdConfig: ThresholdConfig(
localThreshold: 85.0,
priority: ThresholdPriority.serverWithLocalFallback,
),
timeoutDurationInSec: 120,
enableEncryption: false,
metadata: {'userId': 'user_001', 'sessionId': 'abc-456'}, // optional
);
if (result?.blusaltFullIdentityProcess == BlusaltFullIdentityProcess.completed) {
// handle success
} else {
debugPrint('Error ${result?.code}: ${result?.message}');
}
}
Models #
ThresholdConfig #
Controls face-comparison strictness for doc-absent flows.
| Property | Type | Required | Description |
|---|---|---|---|
localThreshold |
double |
No | Threshold value 0–100. Higher = stricter. |
priority |
ThresholdPriority |
No | How the threshold is applied (default: serverWithLocalFallback) |
ThresholdConfig(
localThreshold: 85.0,
priority: ThresholdPriority.serverWithLocalFallback,
)
Pass null to use the SDK's server-side default.
BlusaltFullIdentityResultResponse #
| Field | Type | Description |
|---|---|---|
blusaltFullIdentityProcess |
BlusaltFullIdentityProcess |
completed or notImplemented |
fullIdentitySuccessData |
FullIdentitySuccessData? |
Document + liveness data on success |
reference |
String? |
The reference you passed in |
code |
String? |
Error code on failure |
message |
String? |
Error message on failure |
exception |
PlatformException? |
Raw platform exception if available |
FullIdentitySuccessData #
| Field | Type | Description |
|---|---|---|
extractedDocumentData |
dynamic |
Parsed document fields (see below) |
livenessSuccessData |
dynamic |
Liveness check results (see below) |
Common document fields: firstName, lastName, middleName, dateOfBirth, gender, documentNumber, documentType, imageByte
Common liveness fields: isPassProcedureValidation, isPassFaceComparison, isPassFaceGenuiness, livenessImage, originalLivenessImage, originalImage
Enums #
DocumentType #
| Value | Description |
|---|---|
bvn |
Bank Verification Number |
nin |
National Identification Number |
passport |
International Passport |
driverLicense |
Driver's License |
pvc |
Permanent Voter's Card |
LivenessFacialComparisonType #
| Value | Description |
|---|---|
dynamic |
Head-movement liveness (recommended) |
action |
Prompted-action liveness |
varifocal |
Camera depth detection |
flash |
Screen-flash detection |
ThresholdPriority #
| Value | Description |
|---|---|
serverWithLocalFallback |
Use server threshold; fall back to localThreshold if unavailable (default) |
localOnly |
Always use localThreshold |
serverOnly |
Always use the server threshold; ignores localThreshold |
BlusaltFullIdentityProcess #
| Value | Description |
|---|---|
completed |
Verification completed successfully |
notImplemented |
Platform not supported or an error occurred |
Parameters Reference #
Common (all three methods) #
| Parameter | Type | Required | Description |
|---|---|---|---|
apiKey |
String |
Yes | Your Blusalt API key |
appName |
String |
Yes | Your application name |
clientId |
String |
Yes | Your Blusalt client ID |
isDev |
bool |
Yes | true for sandbox, false for production |
reference |
String? |
No | Your unique reference for this transaction |
webhookUrl |
String? |
No | URL to receive webhook notifications |
timeoutDurationInSec |
int? |
No | Network timeout in seconds (default: 120) |
enableEncryption |
bool |
No | Enable bi-directional payload encryption (default: false) - Encryption must be enabled on API key to use |
thresholdConfig |
ThresholdConfig? |
No | Face-comparison threshold config |
livenessFacialComparisonType |
LivenessFacialComparisonType |
No | Liveness method (default: dynamic) |
showLivenessResult |
bool |
No | Show the SDK's built-in result screen (default: true) |
metadata |
Map<String, dynamic>? |
No | Optional key-value pairs forwarded to the native SDK as-is |
Full Identity SDK only #
| Parameter | Type | Required | Description |
|---|---|---|---|
documentTypeList |
List<DocumentType>? |
No | Filter available document types; null = all types |
Doc Absent — Custom Selector only #
| Parameter | Type | Required | Description |
|---|---|---|---|
documentTypeList |
List<DocumentType> |
Yes | Document types the user can choose from |
Doc Absent — ID Number only #
| Parameter | Type | Required | Description |
|---|---|---|---|
documentType |
DocumentType |
Yes | Document type to verify against |
documentNumber |
String |
Yes | The ID number |
startProcessOnGettingToFirstScreen |
bool |
No | Auto-start on first screen (default: false) |
Example #
See the example/ directory for a complete sample app demonstrating all three SDK modes with all configurable options.
import 'package:full_identity_verification/full_identity_verification.dart';
import 'package:full_identity_verification/enums.dart';
import 'package:full_identity_verification/model.dart';
final _plugin = BlusaltFullIdentityVerification();
Future<void> runVerification() async {
final result = await _plugin.startFullIdentitySDK(
apiKey: 'API_KEY',
appName: 'MyApp',
clientId: 'CLIENT_ID',
isDev: false,
documentTypeList: [DocumentType.nin, DocumentType.passport],
);
if (result?.blusaltFullIdentityProcess == BlusaltFullIdentityProcess.completed) {
final doc = result!.fullIdentitySuccessData?.extractedDocumentData;
final live = result.fullIdentitySuccessData?.livenessSuccessData;
print('${doc?.firstName} ${doc?.lastName}');
print('Liveness passed: ${live?.isPassProcedureValidation}');
} else {
print('Failed — ${result?.code}: ${result?.message}');
}
}
Installation #
Android #
Step 1 — GitHub credentials
Create a github.properties file in the root of your /android folder:
USERNAME_GITHUB=YourGitHubUsername
TOKEN_GITHUB=YourClassicPersonalAccessToken
Grant the token access to read packages at minimum. If you see "Unauthorized" during a Gradle sync, regenerate the token and tick all package-related boxes.
Step 2 — Project-level build.gradle
buildscript {
ext.kotlin_version = '1.9.+'
dependencies {
classpath 'com.android.tools.build:gradle:7.3.+'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
def githubPropertiesFile = rootProject.file("github.properties")
def githubProperties = new Properties()
githubProperties.load(new FileInputStream(githubPropertiesFile))
repositories {
maven {
name "GitHubPackages"
url 'https://maven.pkg.github.com/Blusalt-FS/Liveness-Only-Android-Package'
credentials {
username githubProperties['USERNAME_GITHUB']
password githubProperties['TOKEN_GITHUB']
}
}
maven {
name "GitHubPackages"
url 'https://maven.pkg.github.com/Blusalt-FS/Blusalt_Document_Verification-Android-Package'
credentials {
username githubProperties['USERNAME_GITHUB']
password githubProperties['TOKEN_GITHUB']
}
}
maven {
name "GitHubPackages"
url 'https://maven.pkg.github.com/Blusalt-FS/Full-Identity-SDK-Android-Package'
credentials {
username githubProperties['USERNAME_GITHUB']
password githubProperties['TOKEN_GITHUB']
}
}
}
}
Step 3 — Minimum SDK version
In /android/app/build.gradle:
android {
defaultConfig {
minSdkVersion 24
}
}
Step 4 — ProGuard (if minify is enabled)
In /android/app/proguard-rules.pro:
-keep public class com.megvii.**{*;}
-keep class net.blusalt.liveness_native.** { *; }
-keep class net.blusalt.identityverify.** { *; }
-keep class net.blusalt.fullidentity.** { *; }
Enable it in /android/app/build.gradle:
android {
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
iOS #
Minimum deployment target: iOS 14.0
cd ios && pod install
Add camera permission to ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>Required for identity document scanning and liveness detection</string>
📱 Note on iOS #
-
Physical device only — iOS Simulators are not supported.
-
Ensure
FullIdentityFramework.xcframeworkis linked In your Xcode workspace, navigate toPods > FullIdentityFramework.xcframeworkand confirm it is linked to your app's build target. -
Add required system frameworks If you encounter build errors related to
MediaPlayerorWebKit:- Open Xcode → Targets → Runner → General → Frameworks, Libraries, and Embedded Content
- Add:
AVFoundation.framework,CoreMedia.framework,CoreMotion.framework,MediaPlayer.framework,SystemConfiguration.framework,WebKit.framework
Error Handling #
The SDK never throws — it always returns a BlusaltFullIdentityResultResponse. Check the blusaltFullIdentityProcess field:
final result = await _plugin.startFullIdentitySDK(...);
if (result == null) {
// unexpected null — treat as failure
return;
}
switch (result.blusaltFullIdentityProcess) {
case BlusaltFullIdentityProcess.completed:
// success — read result.fullIdentitySuccessData
break;
case BlusaltFullIdentityProcess.notImplemented:
// failure — read result.code and result.message
debugPrint('Code: ${result.code}');
debugPrint('Message: ${result.message}');
break;
}
Support #
For issues or questions contact Blusalt support or raise an issue in this repository.