laligence_ekyc 0.2.5
laligence_ekyc: ^0.2.5 copied to clipboard
Official Laligence eKYC SDK for Flutter. Drop-in identity verification with document capture, liveness detection, and face matching.
import 'package:flutter/material.dart';
import 'package:laligence_ekyc/laligence_ekyc.dart';
void main() => runApp(const ExampleApp());
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'eKYC Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF1976D2)),
useMaterial3: true,
),
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
VerificationResult? _result;
bool _loading = false;
Future<void> _startVerification() async {
setState(() => _loading = true);
final result = await LaligenceEKYC.verify(
config: const EKYCConfig(
apiKey: 'lal_your_api_key_here', // replace with your key
baseUrl: 'https://ekyc.laligence.com', // or your self-hosted URL
),
context: context,
);
setState(() {
_result = result;
_loading = false;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Laligence eKYC Demo')),
body: SafeArea(
child: _loading
? const Center(child: CircularProgressIndicator())
: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: 32),
const Icon(Icons.verified_user, size: 80, color: Colors.blue),
const SizedBox(height: 16),
const Text(
'Identity Verification',
style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
const Text(
'Verify your identity using your government-issued ID and a selfie.',
style: TextStyle(color: Colors.black54),
textAlign: TextAlign.center,
),
const SizedBox(height: 40),
ElevatedButton.icon(
icon: const Icon(Icons.camera_alt),
label: const Text('Start Verification'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 14),
),
onPressed: _startVerification,
),
// ── Result card ──────────────────────────────────────
if (_result != null) ...[
const SizedBox(height: 40),
_ResultCard(result: _result!),
],
],
),
),
),
);
}
}
class _ResultCard extends StatelessWidget {
final VerificationResult result;
const _ResultCard({required this.result});
@override
Widget build(BuildContext context) {
if (result.cancelled) {
return const _StatusBanner(
icon: Icons.cancel_outlined,
color: Colors.grey,
title: 'Cancelled',
subtitle: 'Verification was not completed.',
);
}
if (!result.passed) {
return _StatusBanner(
icon: Icons.error_outline,
color: Colors.red,
title: 'Verification Failed',
subtitle: result.failureReason ?? 'Unknown error.',
);
}
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const _StatusBanner(
icon: Icons.check_circle_outline,
color: Colors.green,
title: 'Verification Passed',
subtitle: null,
),
// MRZ data card
if (result.mrzData != null) ...[
const SizedBox(height: 16),
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Document Data',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 15)),
const Divider(),
_MrzRow('Name',
'${result.mrzData!.givenNames ?? ''} ${result.mrzData!.surname ?? ''}'.trim()),
_MrzRow('Date of Birth', result.mrzData!.dateOfBirth),
_MrzRow('Nationality', result.mrzData!.nationality),
_MrzRow('Document No.', result.mrzData!.documentNumber),
_MrzRow('Expiry Date', result.mrzData!.expiryDate),
_MrzRow('Document Type', result.mrzData!.documentType),
],
),
),
),
],
// Scores
const SizedBox(height: 12),
Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Verification Scores',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 15)),
const Divider(),
if (result.faceDistance != null)
_MrzRow('Face Distance',
result.faceDistance!.toStringAsFixed(3)),
if (result.livenessScore != null)
_MrzRow('Liveness Score',
result.livenessScore!.toStringAsFixed(3)),
if (result.sessionId != null)
_MrzRow('Session ID', result.sessionId),
],
),
),
),
],
);
}
}
class _StatusBanner extends StatelessWidget {
final IconData icon;
final Color color;
final String title;
final String? subtitle;
const _StatusBanner({
required this.icon,
required this.color,
required this.title,
required this.subtitle,
});
@override
Widget build(BuildContext context) {
return Column(
children: [
Icon(icon, size: 72, color: color),
const SizedBox(height: 8),
Text(title,
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold, color: color)),
if (subtitle != null) ...[
const SizedBox(height: 4),
Text(subtitle!,
style: const TextStyle(color: Colors.black54),
textAlign: TextAlign.center),
],
],
);
}
}
class _MrzRow extends StatelessWidget {
final String label;
final String? value;
const _MrzRow(this.label, this.value);
@override
Widget build(BuildContext context) {
if (value == null || value!.isEmpty) return const SizedBox.shrink();
return Padding(
padding: const EdgeInsets.symmetric(vertical: 3),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 110,
child: Text(label,
style: const TextStyle(
color: Colors.black45, fontSize: 13)),
),
Expanded(
child: Text(value!,
style: const TextStyle(
fontWeight: FontWeight.w500, fontSize: 13)),
),
],
),
);
}
}