Verifier Flutter SDK
Dart/Flutter SDK for verifying driver custody credentials via QR code-based OID4VP flows on iOS and Android.
Stable Release
Currently v0.1.2.
Quick Start
1. Install
Add to your pubspec.yaml:
dependencies:
vecu_verifier_flutter_sdk:
git:
url: https://ghe.coxautoinc.com/VehicleCustody/vecu-verifier-flutter-sdk.git
ref: v0.1.2
Then run:
flutter pub get
2. Widget-Based (Recommended)
Use VerificationView for the full verification flow with built-in UI:
import 'package:vecu_verifier_flutter_sdk/vecu_verifier_flutter_sdk.dart';
final sdk = createVerifierSDK(VerifierConfig(
stage: DeploymentStage.sandbox,
bearerToken: 'your-vecu-api-token',
));
class VerifyScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return VerificationView(
sdk: sdk,
vin: '1HGBH41JXMN109186',
proximity: const ProximityConfig(thresholdMiles: 5.0),
onApproved: (result) {
print('Verified! ${result.requestId}');
print('Proximity: ${result.proximityCheck?.status}');
},
onDenied: (result) {
print('DO NOT RELEASE ${result.requestId}');
},
onExpired: (result) {
print('Session expired');
},
onError: (error) {
print('${error.code}: ${error.message}');
},
);
}
}
VerificationView handles all states: loading, QR code display with countdown timer, approved (with proximity pass/fail/unchecked), denied, expired, and error.
3. Headless (Custom UI)
Use VerificationController for full control over the UI while the controller manages the verification flow (API calls, polling, state transitions):
final sdk = createVerifierSDK(VerifierConfig(
stage: DeploymentStage.sandbox,
bearerToken: 'your-vecu-api-token',
));
final controller = VerificationController(
sdk: sdk,
vin: '1HGBH41JXMN109186',
proximity: const ProximityConfig(thresholdMiles: 5.0),
onApproved: (result) => print('Verified! ${result.requestId}'),
onDenied: (result) => print('DO NOT RELEASE'),
onExpired: (_) => print('Expired'),
onError: (error) => print('Error: ${error.displayCode}'),
);
Build your UI with ListenableBuilder and pattern matching on controller.state:
ListenableBuilder(
listenable: controller,
builder: (context, _) {
return switch (controller.state) {
LoadingState() => const CircularProgressIndicator(),
QRState(:final qrContent, :final expiresAt) =>
MyQRWidget(qrContent, expiresAt),
ApprovedState(:final result) => MyApprovedWidget(result),
DeniedState(:final result, :final vin) => MyDeniedWidget(result, vin),
ExpiredState() => const Text('Session expired'),
QRExpiredState() => TextButton(
onPressed: controller.restart,
child: const Text('QR Expired — Retry'),
),
ErrorState(:final error) => Text('Error: ${error.userMessage}'),
};
},
)
Clean up when done:
controller.dispose();
sdk.destroy();
Headless Example
See the
examples/headless/
directory for a complete working example with dark-themed custom UI, event
log, and mock controls.
4. Low-Level SDK (Advanced)
For maximum control, use the core SDK methods directly:
final sdk = createVerifierSDK(VerifierConfig(
stage: DeploymentStage.sandbox,
bearerToken: 'your-vecu-api-token',
));
final result = await sdk.createPresentationRequest('1HGBH41JXMN109186');
if (result is ApiSuccess<CreatePresentationResponse>) {
// Render result.data.qrContent as a QR code
sdk.startPolling();
}
sdk.on<StatusChangedEvent>((event) {
print(event.currentStatus.status); // pending, approved, denied, expired
});
// Clean up when done
sdk.destroy();
Requirements
| Requirement | Version |
|---|---|
| Flutter | >= 3.16.0 |
| Dart | >= 3.2.0, < 4.0.0 |
Next Steps
- API Reference — Configuration, widgets, methods, events, types