flutter_pua_auth 1.0.0
flutter_pua_auth: ^1.0.0 copied to clipboard
Flutter plugin for The Whisper Company PUA SDK integration with biometric authentication and continuous face monitoring
Flutter PUA Auth Plugin #
A Flutter plugin that integrates The Whisper Company's PUA SDK for iOS and Android, providing biometric authentication and continuous face monitoring capabilities for enhanced security.
📋 Table of Contents #
- Overview
- Features
- Platform Support
- Installation
- Native Setup Requirements
- Setup & Configuration
- API Reference
- Usage Examples
- Architecture & Communication
- Important Notes
- Troubleshooting
- License
Overview #
The Flutter PUA Auth plugin serves as a bridge between Flutter applications and native PUA SDKs (iOS and Android), offering:
- Biometric Authentication: Face ID, Touch ID, Fingerprint authentication
- Continuous Face Monitoring: Real-time face detection and counting from camera feed
- Automatic Screen Locking: Lock/unlock based on face detection state
- Multi-Face Detection: Detect and handle multiple faces (shoulder surfing protection)
- Configurable Settings: Customize refresh rate, eyes-off-screen time, and maximum allowed faces
Features #
🔐 Biometric Authentication #
- iOS: Face ID, Touch ID
- Android: Fingerprint, Face Unlock
- Automatic fallback to platform biometric APIs when PUA SDK is unavailable
👁️ Continuous Face Monitoring #
- Real-time face count detection from camera feed
- Automatic screen locking when:
- No face detected (user left)
- Multiple faces detected (shoulder surfing)
- Automatic unlocking when authorized user returns
- Configurable monitoring parameters
⚙️ Configurable Parameters #
- Refresh Rate:
Instant,fast,medium,light(default:Instant) - Eyes Off Screen Time: 0.25-30.0 seconds (default: 10.0)
- Number of Faces Allowed: Minimum 1, no maximum (default: 1)
- Low Light Threshold: 200-2000 lux (default: 400.0)
Platform Support #
| Platform | Status | Notes |
|---|---|---|
| iOS (Real Device) | ✅ Fully Supported | All features work: PUA SDK face monitoring, biometric auth |
| Android (Real Device) | ✅ Fully Supported | All features work: PUA SDK face monitoring, biometric auth |
| iOS Simulator | ⚠️ Limited Support | See Simulator/Emulator Behavior below |
| Android Emulator | ⚠️ Limited Support | See Simulator/Emulator Behavior below |
Platform Feature Comparison #
| Feature | iOS | Android | Notes |
|---|---|---|---|
| Version Detection | ✅ Working | ❌ Not Available | Android SDK doesn't expose method |
refreshRate |
✅ Working | ⚠️ Partial | May not be set correctly |
eyesOffScreenTime |
✅ Working (2.0) | ❌ Not Supported | Android uses eyeClosedProbabilityThreshold |
eyeClosedProbabilityThreshold |
❌ Not Available | ✅ Working | iOS uses timeout-based approach |
numberOfFacesAllowed |
✅ Working (2.0) | ✅ Working | Set via PUAOne/PWATwo sub-objects |
lowLightThreshold |
✅ Working | ⚠️ Partial | May not be set correctly |
onLightWarning callback |
✅ Working | ❌ Not Available | Android SDK doesn't have this method |
onAuthSuccess |
✅ Working | ✅ Working | Both platforms fully supported |
onAuthFailed |
✅ Working | ✅ Working | Both platforms fully supported |
| Face count accuracy | ✅ Exact | ⚠️ Estimated | Android estimates for IntruderFaceDetected |
authenticateUser() face auth |
✅ Working | ⚠️ Partial | Android requires startFaceMonitoring() active |
| BiometricPrompt face unlock | N/A | ⚠️ Limited | Cannot force face unlock when both available |
Simulator/Emulator Behavior #
iOS Simulator
What Works:
- ✅ Basic biometric authentication (
authenticateUser()) - UsesLocalAuthenticationframework - ✅
isBiometricAvailable()- Returns true if Face ID/Touch ID is enabled in simulator settings - ✅
getAvailableBiometrics()- Returns available biometric types - ✅
configureApiKey()- API key can be configured (but PUA SDK won't be used) - ✅
isApiKeyConfigured()- Returns true if API key is set
What Doesn't Work:
- ❌ PUA SDK Face Monitoring - PUA.framework is device-only (arm64), not available on simulator (x86_64/arm64 simulator)
- ❌ Continuous face detection -
startFaceMonitoring()will not detect faces - ❌ Real-time face counting - Face count callbacks won't be triggered
- ❌ Screen locking based on face detection - Not available
What Happens:
- When you call
startFaceMonitoring(), the plugin detects it's running on a simulator - It falls back to
LocalAuthenticationand basic platform APIs - The
onFaceCountChangedcallback may receive initial values (0 or 1) but won't update continuously - You'll see logs indicating "PUA SDK not available on simulator - using fallback"
To Test Face Monitoring:
- You must use a physical iOS device - PUA SDK requires device hardware
- Enable Face ID in device settings
- Grant camera permission when prompted
Android Emulator
What Works:
- ✅ Basic biometric authentication (
authenticateUser()) - Uses Android BiometricPrompt API - ✅
isBiometricAvailable()- Returns true if biometric hardware is emulated - ✅
getAvailableBiometrics()- Returns available biometric types - ✅
configureApiKey()- API key can be configured - ✅
isApiKeyConfigured()- Returns true if API key is set
What Doesn't Work:
- ❌ PUA SDK Face Monitoring - PUA SDK requires physical device with real camera
- ❌ Continuous face detection -
startFaceMonitoring()will not detect faces from camera - ❌ Real-time face counting - Face count callbacks won't be triggered
- ❌ Screen locking based on face detection - Not available
What Happens:
- When you call
startFaceMonitoring(), the plugin attempts to use PUA SDK - If PUA SDK fails (common on emulator), it may fall back to ML Kit face detection (if available)
- However, camera access on emulator is limited and may not work properly
- You'll see logs indicating "PUA SDK not available" or camera-related errors
To Test Face Monitoring:
- You must use a physical Android device - PUA SDK requires device hardware
- Device must have biometric hardware (fingerprint or face unlock)
- Grant camera permission when prompted
Real Device Behavior (iOS & Android)
What Works:
- ✅ Full PUA SDK Integration - All features work as intended
- ✅ Continuous Face Monitoring - Real-time face detection from camera
- ✅ Automatic Screen Locking - Locks when no face or multiple faces detected
- ✅ Biometric Authentication - Full Face ID/Touch ID/Fingerprint support
- ✅ Configurable Settings - Refresh rate, eyes-off-screen time, max faces
- ✅ Multiple Face Detection - Detects and reports multiple faces (exact count on iOS, estimated on Android)
Requirements:
- Physical device with camera
- Biometric hardware (Face ID, Touch ID, or Fingerprint)
- Camera permission granted
- Valid PUA API key configured
- Internet connection (for initial PUA SDK authentication)
Expected Behavior:
- Face monitoring starts immediately after
startFaceMonitoring()is called onFaceCountChangedcallback receives continuous updates:0when no face detected1when authorized user present>1when multiple faces detected
- Screen automatically locks/unlocks based on face detection state
- Biometric authentication prompts appear when needed
Installation #
1. Add Dependencies #
Add the following to your pubspec.yaml:
dependencies:
flutter_pua_auth:
path: ../flutter_pua_auth # or use git/pub.dev if published
# Platform packages - MUST be explicitly added for auto-registration
flutter_pua_auth_android:
path: ../flutter_pua_auth/flutter_pua_auth_android
flutter_pua_auth_ios:
path: ../flutter_pua_auth/flutter_pua_auth_ios
⚠️ Important: You must add all three packages (flutter_pua_auth, flutter_pua_auth_android, flutter_pua_auth_ios) to your pubspec.yaml. The platform packages are required for auto-registration of native implementations.
2. Install Flutter Dependencies #
flutter pub get
3. Platform-Specific Setup #
iOS Setup
-
Add PUA Framework:
- Download
PUA.frameworkfrom The Whisper Company - Place it in
flutter_pua_auth_ios/ios/Frameworks/PUA.framework - The framework is automatically linked via
podspec
- Download
-
Add Permissions to
ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>Camera access required for face monitoring and authentication</string>
<key>NSFaceIDUsageDescription</key>
<string>Face ID authentication required for secure access</string>
- Install Pods:
cd ios
pod install
cd ..
Android Setup
-
Add PUA AAR File:
- Download the PUA SDK AAR from PUA SDK Android
- Place the AAR file in
flutter_pua_auth_android/android/libs/ - The
build.gradleis already configured to use it
-
Add Permissions to
android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.camera.any" />
- Required Dependencies (already included in
build.gradle):- CameraX
- ML Kit Face Detection
- Biometric API
- Room Database
- Retrofit
Native Setup Requirements #
⚠️ Important: After adding the package dependencies, you must configure the native iOS and Android projects to properly integrate the PUA SDK. These changes are required for the plugin to work correctly.
iOS Native Configuration #
1. Update Podfile
Edit ios/Podfile and ensure:
# Set minimum iOS version to 13.0 (required by PUA SDK)
platform :ios, '13.0'
target 'Runner' do
use_frameworks!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
# Manually add flutter_pua_auth_ios plugin
pod 'flutter_pua_auth_ios', :path => '../../flutter_pua_auth_ios/ios'
target 'RunnerTests' do
inherit! :search_paths
end
end
Key Changes:
- Set
platform :ios, '13.0'(not 12.0) - Add manual pod entry:
pod 'flutter_pua_auth_ios', :path => '../../flutter_pua_auth_ios/ios'
2. Update AppDelegate.swift
Edit ios/Runner/AppDelegate.swift:
import Flutter
import UIKit
import flutter_pua_auth_ios
#if !targetEnvironment(simulator)
import PUA
#endif
@main
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
// Register Flutter PUA Auth plugin manually
FlutterPuaAuthPlugin.register(with: self.registrar(forPlugin: "flutter_pua_auth")!)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Key Changes:
- Add
import flutter_pua_auth_ios - Add conditional
import PUA(device-only, not for simulator) - Add manual plugin registration:
FlutterPuaAuthPlugin.register(...)
3. Update Info.plist
Edit ios/Runner/Info.plist and add:
<key>NSCameraUsageDescription</key>
<string>Camera access required for face monitoring and security</string>
<key>NSFaceIDUsageDescription</key>
<string>Face ID authentication required for secure access</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Photo library access may be needed for certain features</string>
4. Update Xcode Project Deployment Target
In Xcode:
- Open
ios/Runner.xcworkspace(not.xcodeproj) - Select the Runner target
- Go to Build Settings
- Search for "iOS Deployment Target"
- Set it to 13.0 (not 12.0)
Or edit ios/Runner.xcodeproj/project.pbxproj and replace all occurrences:
IPHONEOS_DEPLOYMENT_TARGET = 12.0;→IPHONEOS_DEPLOYMENT_TARGET = 13.0;
5. Update AppFrameworkInfo.plist
Edit ios/Flutter/AppFrameworkInfo.plist:
<key>MinimumOSVersion</key>
<string>13.0</string>
6. Run Pod Install
After making changes:
cd ios
pod install
cd ..
Android Native Configuration #
1. Update build.gradle (or build.gradle.kts)
Edit android/app/build.gradle (or build.gradle.kts):
For Groovy (build.gradle):
android {
namespace "com.example.your_app"
compileSdkVersion 35
ndkVersion "27.0.12077973"
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
defaultConfig {
applicationId "com.example.your_app"
minSdkVersion 26 // CRITICAL: PUA SDK requires minimum SDK 26
targetSdkVersion 35
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
}
// Add flatDir repository for AAR files from plugin
repositories {
flatDir {
dirs '../../flutter_pua_auth_android/android/libs'
}
}
dependencies {
// PUA SDK required dependencies (CRITICAL - all must be included)
// CameraX - default implementation required by PUA SDK
implementation "androidx.camera:camera-camera2:1.1.0-alpha07"
implementation "androidx.camera:camera-lifecycle:1.1.0-alpha07"
implementation "androidx.camera:camera-view:1.0.0-alpha27"
// ML Kit for face detection
implementation 'com.google.mlkit:face-detection:16.1.2'
// Biometric authentication
implementation 'androidx.biometric:biometric:1.2.0-alpha03'
// Retrofit for network calls (required by PUA SDK)
implementation "com.squareup.retrofit2:retrofit:2.9.0"
implementation "com.squareup.retrofit2:converter-gson:2.9.0"
// Kotlin coroutines (required by PUA SDK)
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
// Room database (required by PUA SDK)
def room_version = "2.3.0"
implementation("androidx.room:room-runtime:$room_version")
annotationProcessor "androidx.room:room-compiler:$room_version"
implementation("androidx.room:room-ktx:$room_version")
}
For Kotlin DSL (build.gradle.kts):
android {
namespace = "com.example.your_app"
compileSdk = 35
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
defaultConfig {
applicationId = "com.example.your_app"
minSdk = 26 // CRITICAL: PUA SDK requires minimum SDK 26
targetSdk = 35
versionCode = flutter.versionCode
versionName = flutter.versionName
}
}
// Add flatDir repository for AAR files from plugin
repositories {
flatDir {
dirs("../../flutter_pua_auth_android/android/libs")
}
}
dependencies {
// PUA SDK required dependencies (CRITICAL - all must be included)
// CameraX - default implementation required by PUA SDK
implementation("androidx.camera:camera-camera2:1.1.0-alpha07")
implementation("androidx.camera:camera-lifecycle:1.1.0-alpha07")
implementation("androidx.camera:camera-view:1.0.0-alpha27")
// ML Kit for face detection
implementation("com.google.mlkit:face-detection:16.1.2")
// Biometric authentication
implementation("androidx.biometric:biometric:1.2.0-alpha03")
// Retrofit for network calls (required by PUA SDK)
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
// Kotlin coroutines (required by PUA SDK)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1")
// Room database (required by PUA SDK)
val room_version = "2.3.0"
implementation("androidx.room:room-runtime:$room_version")
annotationProcessor("androidx.room:room-compiler:$room_version")
implementation("androidx.room:room-ktx:$room_version")
}
Key Changes:
- Set
minSdkVersion(orminSdk) to 26 (PUA SDK requirement) - Set
compileSdkVersion(orcompileSdk) to 35 - Set Java/Kotlin compatibility to 1.8 (not 11)
- Add
flatDirrepository pointing to plugin'slibsdirectory - Add all PUA SDK required dependencies (CameraX, ML Kit, Biometric, Retrofit, Coroutines, Room)
2. Update AndroidManifest.xml
Edit android/app/src/main/AndroidManifest.xml and add permissions:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application ...>
<!-- Your app configuration -->
</application>
<!-- Required permissions for PUA SDK -->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-feature android:name="android.hardware.camera.any" />
</manifest>
Key Changes:
- Add
INTERNETpermission (for PUA SDK authentication) - Add
CAMERApermission (for face monitoring) - Add
USE_BIOMETRICandUSE_FINGERPRINTpermissions (for biometric authentication) - Add
uses-featurefor camera hardware
3. Sync Gradle Files
After making changes:
cd android
./gradlew clean
cd ..
Or in Android Studio: File → Sync Project with Gradle Files
Flutter Code Configuration #
Import Platform Packages
In your app's main.dart, you must import the platform packages to trigger auto-registration:
import 'package:flutter/material.dart';
// Import platform packages to trigger auto-registration
// ignore: unused_import
import 'package:flutter_pua_auth_android/flutter_pua_auth_android.dart';
// ignore: unused_import
import 'package:flutter_pua_auth_ios/flutter_pua_auth_ios.dart';
import 'package:flutter_pua_auth/flutter_pua_auth.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Configure PUA API key
const String puaApiKey = "your-api-key-here";
await FlutterPuaAuth.instance.configureApiKey(puaApiKey);
runApp(MyApp());
}
Why This Is Required:
- The platform packages contain auto-registration code that runs when imported
- Without these imports, the native implementations won't register with Flutter
- You'll get
MissingPluginExceptionerrors if these imports are missing
Verification Checklist #
After completing all native setup steps, verify:
iOS:
- ✅ Podfile has
platform :ios, '13.0' - ✅ Podfile has manual pod entry for
flutter_pua_auth_ios - ✅ AppDelegate.swift imports and registers the plugin
- ✅ Info.plist has camera and Face ID permissions
- ✅ Xcode project deployment target is 13.0
- ✅ Ran
pod installsuccessfully
Android:
- ✅
build.gradlehasminSdkVersion 26 - ✅
build.gradlehas all PUA SDK dependencies - ✅
build.gradlehasflatDirrepository - ✅
AndroidManifest.xmlhas all required permissions - ✅ Gradle files synced successfully
Flutter:
- ✅
pubspec.yamlincludes all three packages (flutter_pua_auth,flutter_pua_auth_android,flutter_pua_auth_ios) - ✅
main.dartimports platform packages - ✅ API key configured in
main()
Common Setup Errors #
Error: MissingPluginException: No implementation found for method configureApiKey
Solution:
- Ensure platform packages are imported in
main.dart - Ensure platform packages are in
pubspec.yamldependencies - Run
flutter clean && flutter pub get - Rebuild the app (not just hot reload)
Error: Could not find module 'PUA' (iOS)
Solution:
- Ensure
PUA.frameworkis influtter_pua_auth_ios/ios/Frameworks/ - Run
pod installinios/directory - Check Podfile has manual pod entry
Error: CameraX is not configured properly (Android)
Solution:
- Ensure
camera-camera2dependency is inbuild.gradle - Ensure all PUA SDK dependencies are added
- Sync Gradle files
Error: Compiling for iOS 12.0, but module has minimum deployment target of iOS 13.0
Solution:
- Update Podfile:
platform :ios, '13.0' - Update Xcode project deployment target to 13.0
- Update
AppFrameworkInfo.plistMinimumOSVersion to 13.0 - Run
pod installagain
Setup & Configuration #
API Key Configuration #
Why PUA API Key is Important
The PUA API key is essential for the plugin to function properly. Here's why:
-
SDK Authentication: The PUA SDK requires a valid API key to authenticate and initialize
- Without a valid API key, the PUA SDK will not start
- Face monitoring will fail with "PUA API key not configured" error
-
License Validation: The API key serves as a license to use the PUA SDK
- Each API key is tied to your application/account
- Invalid or expired keys will be rejected by the SDK
-
Security: The API key ensures only authorized applications can use the PUA SDK
- Protects The Whisper Company's intellectual property
- Prevents unauthorized usage
-
Feature Access: Valid API key enables all PUA SDK features:
- Continuous face monitoring
- Real-time face detection
- Advanced authentication capabilities
⚠️ Important:
- You must obtain a valid API key from The Whisper Company before using this plugin
- The API key must be configured before calling
startFaceMonitoring() - Without a valid API key, the plugin will fall back to basic platform biometric APIs (limited functionality)
How to Get PUA API Key
Contact The Whisper Company to obtain your PUA API key:
- Website: https://gitlab.com/the_whisper_company/twc.pua
- The API key is typically provided as part of your SDK license agreement
Configuration Methods
The PUA SDK requires an API key for authentication. You can configure it in two ways:
Method 1: Programmatic Configuration (Recommended)
Configure the API key in your app's main.dart:
import 'package:flutter_pua_auth/flutter_pua_auth.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Configure PUA API key
const String puaApiKey = "your-api-key-here";
await FlutterPuaAuth.instance.configureApiKey(puaApiKey);
runApp(MyApp());
}
Method 2: Android Resource File (Fallback)
For Android, you can also add the API key to android/app/src/main/res/values/pua_license.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="pua_api_key" translatable="false">your-api-key-here</string>
</resources>
Priority Order:
- Programmatic configuration (Method 1) - takes precedence
- Android resource file (Method 2) - used as fallback if Method 1 not called
- Error - if neither is configured, face monitoring will fail
Note: iOS only supports Method 1 (programmatic configuration).
API Reference #
FlutterPuaAuth #
The main class for interacting with PUA authentication and face monitoring. Access via singleton: FlutterPuaAuth.instance.
Core Methods #
configureApiKey(String apiKey)
Configures the PUA API key. Must be called before using any PUA SDK features.
isApiKeyConfigured()
Checks if the PUA API key has been configured. Returns Future<bool>.
authenticateUser({String? reason, bool allowCredentials = false})
Performs biometric authentication. Returns Future<bool>.
Platform Notes:
- iOS: Uses Face ID/Touch ID via LocalAuthentication
- Android: Uses BiometricPrompt (fingerprint/face unlock). If
startFaceMonitoring()is active, returns success immediately.
startFaceMonitoring({required Function(int) onFaceCountChanged, ...})
Starts continuous face monitoring from camera feed.
Parameters:
onFaceCountChanged(required): Callback with face count (0= no face,1= authorized,>1= multiple,-1= eyes off)refreshRate:'Instant','fast','medium', or'light'(default:'Instant')eyesOffScreenTime: 0.25-30.0 seconds (default: 10.0) - iOS only, Android useseyeClosedProbabilityThresholdnumberOfFacesAllowed: Minimum 1, no maximum (default: 1)lowLightThreshold: 200-2000 lux (default: 400.0)onLowLightWarning: Optional callback - iOS only, Android SDK doesn't support thisonError: Optional callback for PUA SDK errors
Face Count Values:
0: No face detected → Lock screen1: Authorized user → Unlock screen (auto re-authenticated)>1: Multiple faces → Lock if exceedsnumberOfFacesAllowed-1: Eyes off screen → Lock screen
stopFaceMonitoring()
Stops face monitoring and releases camera resources. Always call in dispose().
isBiometricAvailable()
Checks if biometric authentication is available. Returns Future<bool>.
getAvailableBiometrics()
Gets available biometric types: ["face"], ["fingerprint"], or ["face", "fingerprint"].
getPuaVersion()
Gets PUA SDK version. Returns Future<String> (e.g., "2.0"). iOS only - Android returns default "2.0".
inspectNativeSdk()
Inspects native SDK classes to see all available methods/fields. Logs to native console (logcat/Xcode). Useful for debugging SDK integration. See HOW_TO_USE_SDK_INSPECTION.md for details.
Usage Examples #
Basic Setup #
In your app's main.dart, you must import the platform packages to trigger auto-registration:
import 'package:flutter/material.dart';
// Import platform packages to trigger auto-registration
// ignore: unused_import
import 'package:flutter_pua_auth_android/flutter_pua_auth_android.dart';
// ignore: unused_import
import 'package:flutter_pua_auth_ios/flutter_pua_auth_ios.dart';
import 'package:flutter_pua_auth/flutter_pua_auth.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Configure PUA API key
const String puaApiKey = "your-api-key-here";
await FlutterPuaAuth.instance.configureApiKey(puaApiKey);
runApp(MyApp());
}
⚠️ Important: The platform package imports are required for the plugin to work. Without them, you'll get MissingPluginException errors. See Native Setup Requirements for complete setup instructions.
Basic Authentication #
import 'package:flutter_pua_auth/flutter_pua_auth.dart';
class AuthScreen extends StatefulWidget {
@override
_AuthScreenState createState() => _AuthScreenState();
}
class _AuthScreenState extends State<AuthScreen> {
bool _isAuthenticated = false;
Future<void> _authenticate() async {
final authenticated = await FlutterPuaAuth.instance.authenticateUser(
reason: 'Please authenticate to continue',
);
setState(() {
_isAuthenticated = authenticated;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: _isAuthenticated
? Text('Authenticated!')
: ElevatedButton(
onPressed: _authenticate,
child: Text('Authenticate'),
),
),
);
}
}
Continuous Face Monitoring #
import 'package:flutter_pua_auth/flutter_pua_auth.dart';
class SecureScreen extends StatefulWidget {
@override
_SecureScreenState createState() => _SecureScreenState();
}
class _SecureScreenState extends State<SecureScreen> {
int _faceCount = 0;
bool _isLocked = true;
@override
void initState() {
super.initState();
_startMonitoring();
}
Future<void> _startMonitoring() async {
await FlutterPuaAuth.instance.startFaceMonitoring(
onFaceCountChanged: (count) {
setState(() {
_faceCount = count;
_isLocked = count != 1;
});
},
refreshRate: 'Instant',
eyesOffScreenTime: 2.0,
numberOfFacesAllowed: 1,
);
}
@override
void dispose() {
FlutterPuaAuth.instance.stopFaceMonitoring();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: _isLocked
? Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.lock, size: 64),
Text('Screen Locked'),
Text('Face count: $_faceCount'),
],
),
)
: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.lock_open, size: 64, color: Colors.green),
Text('Screen Unlocked'),
Text('Face count: $_faceCount'),
],
),
),
);
}
}
Complete Example with API Key Configuration #
import 'package:flutter/material.dart';
// Import platform packages to trigger auto-registration
// ignore: unused_import
import 'package:flutter_pua_auth_android/flutter_pua_auth_android.dart';
// ignore: unused_import
import 'package:flutter_pua_auth_ios/flutter_pua_auth_ios.dart';
import 'package:flutter_pua_auth/flutter_pua_auth.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Configure PUA API key
const String puaApiKey = "your-api-key-here";
try {
await FlutterPuaAuth.instance.configureApiKey(puaApiKey);
print('✅ PUA API key configured');
} catch (e) {
print('❌ Error configuring API key: $e');
}
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
bool _isMonitoring = false;
int _faceCount = 0;
String _status = 'Not monitoring';
Future<void> _checkApiKey() async {
final isConfigured = await FlutterPuaAuth.instance.isApiKeyConfigured();
if (!isConfigured) {
setState(() {
_status = 'API key not configured';
});
}
}
Future<void> _startMonitoring() async {
final isConfigured = await FlutterPuaAuth.instance.isApiKeyConfigured();
if (!isConfigured) {
_status = 'Please configure API key first';
return;
}
await FlutterPuaAuth.instance.startFaceMonitoring(
onFaceCountChanged: (count) {
setState(() {
_faceCount = count;
if (count == 0) {
_status = 'No face detected - Screen locked';
} else if (count == 1) {
_status = 'Face detected - Screen unlocked';
} else {
_status = '$count faces detected - Screen locked';
}
});
},
refreshRate: 'Instant',
eyesOffScreenTime: 2.0,
numberOfFacesAllowed: 1,
);
setState(() {
_isMonitoring = true;
_status = 'Monitoring started';
});
}
Future<void> _stopMonitoring() async {
await FlutterPuaAuth.instance.stopFaceMonitoring();
setState(() {
_isMonitoring = false;
_status = 'Monitoring stopped';
_faceCount = 0;
});
}
@override
void dispose() {
if (_isMonitoring) {
FlutterPuaAuth.instance.stopFaceMonitoring();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('PUA Auth Demo')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Status: $_status', style: TextStyle(fontSize: 18)),
SizedBox(height: 20),
Text('Face Count: $_faceCount', style: TextStyle(fontSize: 24)),
SizedBox(height: 40),
ElevatedButton(
onPressed: _isMonitoring ? _stopMonitoring : _startMonitoring,
child: Text(_isMonitoring ? 'Stop Monitoring' : 'Start Monitoring'),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: _checkApiKey,
child: Text('Check API Key'),
),
],
),
),
);
}
}
Architecture #
This plugin follows Flutter's federated plugin architecture:
Flutter App → FlutterPuaAuth → Platform Interface → Platform Implementation → Native PUA SDK
Communication:
- Method Channel: One-time operations (
configureApiKey,authenticateUser, etc.) - Event Channel: Continuous face count updates during monitoring
Platform Implementations:
- iOS:
flutter_pua_auth_ios→ PUA.framework (device-only) - Android:
flutter_pua_auth_android→ PUA AAR library
See docs/ARCHITECTURE.md for detailed architecture documentation.
Simulator/Emulator Support #
| Feature | iOS Simulator | Android Emulator | Real Device |
|---|---|---|---|
| API Key Configuration | ✅ | ✅ | ✅ |
| Biometric Auth UI | ✅ | ✅ | ✅ |
| Basic Authentication | ✅ (LocalAuth) | ✅ (BiometricPrompt) | ✅ (PUA SDK) |
| Face Monitoring | ❌ | ❌ | ✅ |
| Face Count Detection | ❌ | ❌ | ✅ |
| Screen Locking | ❌ | ❌ | ✅ |
Note: Face monitoring features require physical devices with camera and biometric hardware.
Important Notes #
⚠️ API Key Configuration #
Critical: The PUA API key is required for the plugin to work properly.
- Must be configured before use: Call
configureApiKey()inmain()before using any PUA SDK features - Required for face monitoring: Without a valid API key,
startFaceMonitoring()will fail - SDK Authentication: The API key authenticates your app with the PUA SDK servers
- License Validation: The API key validates your license to use the PUA SDK
- iOS: Only supports programmatic configuration
- Android: Supports both programmatic and resource file configuration (with fallback)
What Happens Without API Key:
- ❌ Face monitoring will not work
- ❌ PUA SDK will not initialize
- ❌ You'll see "PUA API key not configured" errors
- ⚠️ Plugin may fall back to basic platform APIs (limited functionality)
Always verify API key is configured:
final isConfigured = await FlutterPuaAuth.instance.isApiKeyConfigured();
if (!isConfigured) {
// Show error or configure API key
}
📱 Device Requirements #
Real Device (Recommended)
- Physical Devices Only: PUA SDK requires physical devices with biometric hardware
- iOS: iPhone/iPad with Face ID or Touch ID
- Android: Device with fingerprint sensor or face unlock
- Camera: Front-facing camera required for face monitoring
- Internet: Required for initial PUA SDK authentication (one-time)
Why Physical Device?
- PUA SDK uses device-specific hardware features
- Camera access and face detection require real hardware
- Simulators/emulators don't have the necessary hardware capabilities
Simulator/Emulator (Limited Testing Only)
iOS Simulator:
- ✅ Can test basic biometric authentication UI
- ✅ Can test API key configuration
- ❌ Cannot test face monitoring - PUA SDK not available
- ❌ Cannot test continuous face detection
- Use for: UI testing, authentication flow testing
- Don't use for: Face monitoring, real security testing
Android Emulator:
- ✅ Can test basic biometric authentication UI
- ✅ Can test API key configuration
- ❌ Cannot test face monitoring - PUA SDK requires real camera
- ❌ Cannot test continuous face detection
- Use for: UI testing, authentication flow testing
- Don't use for: Face monitoring, real security testing
⚠️ Important: Always test face monitoring features on real devices before deploying to production.
🔒 Permissions #
- Camera Permission: Required for face monitoring (requested automatically on Android, via Info.plist on iOS)
- Biometric Permission: Required for authentication (handled automatically by platform)
👥 Multiple Face Detection #
- iOS: Provides exact face count (2, 3, 4, etc.) via
onMultipleFacesDetectedcallback - Android: Provides estimated count based on
lastKnownFaceCount + 1when multiple faces detected (SDK limitation)- The Android PUA SDK's
IntruderFaceDetectedcallback doesn't provide the exact face count - The plugin attempts to retrieve the actual count using reflection, but if unavailable, estimates it
- If
numberOfFacesAllowed = 2and 2 faces are detected, Android will report2(within limit, won't lock) - If
numberOfFacesAllowed = 2and 3+ faces are detected, Android will report3or more (exceeds limit, will lock)
- The Android PUA SDK's
Note:
numberOfFacesAllowedhas no maximum limit. You can set it to any value >= 1 (e.g., 5, 10, etc.)- The app will NOT lock when
faceCount <= numberOfFacesAllowed- this is handled in the Flutter BLoC logic - Use
inspectNativeSdk()to see what methods are available in the native SDK for face count detection
Lifecycle Management #
Always call stopFaceMonitoring() in dispose() to prevent camera resource leaks.
Performance #
- Use
'light'or'medium'refresh rate for better battery life - Face monitoring stops when app goes to background (platform limitation)
Troubleshooting #
Common Issues #
API Key Not Configured
- Ensure
configureApiKey()is called inmain()before use - Verify API key is valid
Face Monitoring Not Working
- Check API key:
await FlutterPuaAuth.instance.isApiKeyConfigured() - Verify camera permission granted
- Must run on physical device (not simulator/emulator)
- Check logs for PUA SDK errors
Build Errors
- iOS: Ensure
PUA.frameworkis present, runpod install - Android: Ensure all dependencies in
build.gradle, sync Gradle
Multiple Faces Not Detected (Android)
- Android SDK limitation:
IntruderFaceDetecteddoesn't provide exact count - Plugin estimates using
lastKnownFaceCount + 1 - Use
inspectNativeSdk()to see available methods
SDK Inspection Not Working
- Check logcat (Android):
adb logcat | grep "SDK_INSPECTION" - Check Xcode console (iOS): search for
[SDK_INSPECTION] - Ensure API key configured before inspection
License #
Copyright © The Whisper Company. All rights reserved.
This plugin integrates with proprietary PUA SDKs from The Whisper Company. Please refer to The Whisper Company's licensing terms for SDK usage.
Support #
For issues, questions, or contributions:
- PUA SDK: Contact The Whisper Company
- Plugin Issues: Open an issue in the project repository
Demo App #
See the example/ directory for a complete demo application showcasing:
- API key configuration
- Biometric authentication
- Continuous face monitoring
- Settings screen for configuration
- Screen locking/unlocking based on face detection