Face Detection TADI SDK - Flutter Plugin
A Flutter plugin that integrates TADI Face Detection SDK for both iOS and Android platforms, providing face detection, liveness verification, and biometric identity verification capabilities.
Features
- Real-time Face Detection: Using Google ML Kit (Android) and TrueDepth camera (iOS)
- Liveness Verification: Prevents photo/video spoofing
- Biometric Identity Verification: Integration with government identity services
- Multi-language Support: English, Russian, and Uzbek
- Flexible Result Formats: Flat (simple) or Nested (structured)
- Security Features:
- JWT signature validation
- Nonce-based challenge-response
- Root/Jailbreak detection
- Mutual SSL/TLS support
- UI Customization: Full control over colors, fonts, and layout
Platform Support
| Platform | Minimum Version |
|---|---|
| Android | API 21 (Android 5.0) |
| iOS | iOS 13.0+ |
Installation
Add this to your package's pubspec.yaml file:
dependencies:
facedetect_tadi_sdk: ^0.0.1
Then run:
flutter pub get
Platform-Specific Setup
Android Setup
- Add Maven Repository: The native Android SDK needs access to the Nexus repository. Add credentials to your
gradle.propertiesfile (project root):
nexusUsername=romvn
nexusPassword=!QAZ1qaz
Security Note: Never commit credentials to version control. Add
gradle.propertiesto your.gitignore.
- Add Permissions: Add these permissions to your
AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
Optional hardware features:
<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
- Minimum SDK: Ensure your
android/app/build.gradlehas:
android {
defaultConfig {
minSdkVersion 21
}
}
iOS Setup
-
Add TGFISBIN Framework: You need to add the TGFISBIN.xcframework to your iOS project.
Option 1: Using Swift Package Manager (if available)
Add to your iOS project in Xcode:
https://gitlab.tadi.uz/tadi_public/TGFISBIN.gitOption 2: Manual Framework Integration
- Place
TGFISBIN.xcframeworkin yourios/folder orios/Frameworks/ - Update the podspec to include vendored frameworks (see ios/facedetect_tadi_sdk.podspec)
- Place
-
Add Permissions: Add these entries to your
Info.plist:
<key>NSCameraUsageDescription</key>
<string>We need camera access to verify your identity and scan your documents</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need photo library access to select identity documents</string>
- Update Deployment Target: Ensure your iOS deployment target is at least 13.0 in Xcode.
Quick Start
Basic Usage
import 'package:facedetect_tadi_sdk/facedetect_tadi_sdk.dart';
// Create SDK instance
final sdk = FacedetectTadiSdk();
// Configure SDK
final config = SdkConfig(
accessToken: 'YOUR_ACCESS_TOKEN',
language: 'en', // 'en', 'ru', or 'uz'
useNative: true,
);
// Start face detection
final result = await sdk.startFaceDetection(config);
if (result != null) {
print('Name: ${result.firstName} ${result.lastName}');
print('Document: ${result.docSeria} ${result.docNumber}');
print('PINFL: ${result.pinfl}');
print('Birth Date: ${result.birthDate}');
print('Score: ${result.score}');
} else {
print('Verification cancelled or failed');
}
Advanced Configuration
final config = SdkConfig(
accessToken: 'YOUR_ACCESS_TOKEN',
baseUrl: 'https://your-api-url.com/',
language: 'en',
useNative: true,
resultFormat: ResultFormat.flat,
privacyPolicyUrl: 'https://yourcompany.com/privacy',
// UI Customization
uiConfig: UiConfig(
logoUrl: 'https://yourcdn.com/logo.png',
fontFamily: 'YourFont-Regular',
inputShape: 'rounded',
inputBorderStyle: 'solid',
inputSize: 'medium',
inputColor: '#FFFFFF',
buttonColor: '#007AFF',
linkColor: '#007AFF',
elementColor: '#1C1C1E',
layoutScale: 'medium',
hideBackButton: false,
),
);
With Mutual SSL/TLS
For enhanced security with client certificates:
final config = SdkConfig(
accessToken: 'YOUR_ACCESS_TOKEN',
enableMutualSSL: true,
clientCertificateBase64: 'BASE64_ENCODED_P12_CERTIFICATE',
clientCertificatePassword: 'certificate_password',
);
API Reference
SdkConfig
Configuration object for the SDK:
| Parameter | Type | Required | Description |
|---|---|---|---|
accessToken |
String | ✅ | API authentication token |
baseUrl |
String | ❌ | Backend service URL (default: https://face.mbabm.uz/) |
language |
String | ❌ | UI language: 'en', 'ru', or 'uz' (default: 'uz') |
useNative |
bool | ❌ | Use native face detection (default: true) |
resultFormat |
ResultFormat | ❌ | Result format: flat or nested (default: flat) |
privacyPolicyUrl |
String | ❌ | Custom privacy policy URL |
jwtSecretKey |
String | ❌ | HMAC secret key for JWT validation |
jwtPublicKey |
String | ❌ | RSA public key for JWT validation |
clientCertificateBase64 |
String | ❌ | P12 certificate (Base64) for mTLS |
clientCertificatePassword |
String | ❌ | Password for P12 certificate |
enableMutualSSL |
bool | ❌ | Enable mutual SSL authentication |
uiConfig |
UiConfig | ❌ | UI customization options |
FaceDetectionResult
Result object containing verification data:
class FaceDetectionResult {
// Identity
String? id;
String? pin;
String? pinfl;
String? transactionId;
// Names
String? firstName;
String? lastName;
String? patronym;
String? name;
// Document Information
String? docSeria;
String? docNumber;
String? dateIssue;
String? dateExpiry;
// Demographics
String? gender;
String? genderName;
String? birthDate;
String? birthPlace;
String? citizenship;
String? citizenshipName;
// Verification
double? score; // Confidence score (0.0 - 1.0)
// Media (Base64 encoded)
String? photo;
String? signature;
String? capture;
// Additional Documents
List<DocumentInfo>? documents;
List<ForeignDocument>? foreignDocuments;
}
UiConfig
UI customization options:
UiConfig(
logoUrl: 'https://example.com/logo.png',
fontFamily: 'CustomFont-Regular',
inputShape: 'rounded', // 'rounded' or 'standard'
inputBorderStyle: 'solid', // 'solid', 'dashed', 'dotted'
inputSize: 'medium', // 'small', 'medium', 'large'
inputColor: '#FFFFFF',
buttonColor: '#007AFF',
linkColor: '#007AFF',
elementColor: '#1C1C1E',
layoutScale: 'medium', // 'small', 'medium', 'large'
hideBackButton: false,
hideDateOfBirthClear: false,
)
Result Formats
Flat Format (Default)
Returns a simple, flat structure with all fields at the top level:
final config = SdkConfig(
accessToken: 'TOKEN',
resultFormat: ResultFormat.flat,
);
final result = await sdk.startFaceDetection(config);
print(result?.firstName); // Direct access
print(result?.docNumber);
Nested Format
Returns a hierarchical, structured format (useful for complex integrations):
final config = SdkConfig(
accessToken: 'TOKEN',
resultFormat: ResultFormat.nested,
);
// Note: Nested format support is available on the native side
// but requires additional mapping in Flutter layer
Handling Results
Display Photo
import 'dart:convert';
import 'package:flutter/material.dart';
Widget buildPhoto(FaceDetectionResult result) {
if (result.photo != null && result.photo!.isNotEmpty) {
return Image.memory(
base64Decode(result.photo!),
height: 200,
fit: BoxFit.contain,
);
}
return Icon(Icons.person, size: 200);
}
Validate Score
void handleResult(FaceDetectionResult result) {
if (result.score != null) {
if (result.score! >= 0.9) {
print('✅ High confidence verification');
} else if (result.score! >= 0.7) {
print('⚠️ Medium confidence - manual review recommended');
} else {
print('❌ Low confidence - verification failed');
}
}
}
Error Handling
try {
final result = await sdk.startFaceDetection(config);
if (result == null) {
// User cancelled or verification failed
print('Verification cancelled');
} else {
// Success
print('Verification successful');
}
} on PlatformException catch (e) {
// Handle platform-specific errors
print('Error: ${e.code} - ${e.message}');
switch (e.code) {
case 'NO_ACTIVITY':
print('Activity not available');
break;
case 'ALREADY_RUNNING':
print('Face detection already in progress');
break;
case 'SDK_ERROR':
print('SDK initialization error');
break;
default:
print('Unknown error');
}
}
Example App
See the example directory for a complete demo app that shows:
- Configuration options
- Starting face detection
- Handling results
- Displaying photos
- Error handling
Run the example:
cd example
flutter run
Troubleshooting
Android Issues
Build fails with "Could not find uz.tadi:facedetectsdk:1.0.4"
- Ensure
gradle.propertieshas the correct Nexus credentials - Check your internet connection
Face detection doesn't start
- Verify camera permissions are granted
- Check that the device is not rooted
- Ensure access token is valid
iOS Issues
Build fails with "Module 'TGFISBIN' not found"
- Ensure TGFISBIN.xcframework is properly added to your project
- Run
pod installin the ios folder - Clean build folder in Xcode (Cmd+Shift+K)
Completion returns nil
- Check if running on a real device (not simulator)
- Verify device is not jailbroken
- Ensure camera permissions are granted
Platform-Native Documentation
For detailed information about the native SDKs:
- Android: See README.android.md
- iOS: See README.ios.md
Security Considerations
- Never hardcode access tokens in your app
- Store tokens securely using flutter_secure_storage or similar
- Use mutual SSL/TLS in production
- Validate JWT responses for additional security
- Never commit certificates or credentials to version control
License
See LICENSE file for details.
Support
For issues and questions:
- Create an issue in the repository
- Contact TADI support team