readid_flutter 0.1.2-beta
readid_flutter: ^0.1.2-beta copied to clipboard
Flutter plugin for ReadID.
example/lib/main.dart
/*
* ReadID Flutter SDK Sample Code
*
* Copyright © 2024 Inverid B.V. All rights reserved.
*/
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:readid_example/document_selection.dart';
import 'package:readid_example/strings.dart';
import 'package:readid_example/ui/dropdown_widget.dart';
import 'package:readid_example/ui/generic_dialog.dart';
import 'package:readid_flutter/readid.dart';
import 'handle_response.dart';
void main() async {
runApp(
MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple, brightness: Brightness.light),
fontFamily: Strings.roboto,
useMaterial3: true),
darkTheme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple, brightness: Brightness.dark),
fontFamily: Strings.roboto,
useMaterial3: true),
themeMode: ThemeMode.system,
home: const ReadIDApp(),
),
);
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
}
class ReadIDApp extends StatefulWidget {
const ReadIDApp({super.key});
@override
State<ReadIDApp> createState() => _ReadIDAppState();
}
class _ReadIDAppState extends State<ReadIDApp> {
/// The possible flows the user can choose in this example app.
final List<ReadIDFlow> _flows = [NFCWithAccessControlFlow(), VIZOnlyOnePageFlow()];
/// The text that is displayed when the flow is finished.
String? _statusText;
/// The document selection the user selected from the dropdown menu depending on the flow
DocumentSelection _documentSelection = DocumentTypeSelection(DocumentType.passport);
/// The ReadID plugin, you use this to start a ReadID flow and verify identity documents.
final _readidPlugin = ReadID();
/// The Visual Inspection Zone result. This will be available after a ReadID Session is complete.
VIZResult? _vizResult;
/// When an only VIZ Flow is chosen, it's possible to chain the result to scan the NFC chip.
bool _shouldShowFlowChainingButton = false;
/// Will be populated with the face image on the identity document, if available.
Uint8List? _image;
// Put your API credentials in a json file and pass them using --dart-define-from-file
final String _baseUrl = const String.fromEnvironment('BASE_URL');
// Note: You should have different access keys for each server environment
final String _accessKey = const String.fromEnvironment('ACCESS_KEY');
@override
void initState() {
super.initState();
resumeReadID();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
body: ListView(
children: [
DropdownWidget(
flows: _flows,
documentSelection: _documentSelection,
onSubmit: (ReadIDFlow selectedFlow, DocumentSelection documentSelection) {
_documentSelection = documentSelection;
_startReadID(selectedFlow);
},
onFlowChain: () {
_continueFlowChain();
},
statusText: _statusText,
shouldShowFlowChain: _shouldShowFlowChainingButton,
image: _image,
)
],
),
);
}
// Method to start the ReadID process
// It takes two parameters: flow and session
// flow is the ReadIDFlow object that will be used in the ReadID process
// session is the ReadIDSession object that will be used in the ReadID process in case of flow chaining
void _startReadID(ReadIDFlow flow, [ReadIDSession? session]) async {
ReadIDResult? readIDResult;
try {
// If flow is an instance of NFCWithAccessControlFlow,
// configure it with _configureNFCWithAccessControlFlow method
if (flow is NFCWithAccessControlFlow) {
_configureNFCWithAccessControlFlow(flow);
}
// If flow is an instance of VIZOnlyOnePageFlow,
// configure it with _configureVIZOnlyOnePageFlow method
if (flow is VIZOnlyOnePageFlow) {
_configureVIZOnlyOnePageFlow(flow);
}
// Start the ReadID process with the specified flow
// The result of the ReadID process will be stored in readIDResult
readIDResult = await _readidPlugin.startReadID(flow: flow);
} on Failure catch (e) {
handleFailure(e);
} on PlatformException catch (e) {
handleErrorResponse(e);
} finally {
updateUI(readIDResult: readIDResult);
}
}
// Method to configure NFCWithAccessControlFlow
// It takes one parameter: flow, which is an instance of NFCWithAccessControlFlow
void _configureNFCWithAccessControlFlow(NFCWithAccessControlFlow flow) {
flow
..baseUrl = _baseUrl
..accessKey = _accessKey
// Indicates whether an NFC result screen will be shown.
..shouldShowNFCResult = true
// If enabled, tries to read images(face or signature)
// If no images are needed, set to false to speed up reading process
..shouldReadImages = true
// Shows a skip reading button after the specified number of attempts.
// To hide or never show the skip button, set it to -1.
// To show skip button immediately, set it to 0.
// Set to a value > 0, to show skip button after specified number of attempts.
..allowSkipReadingAfterAttempts = 2
// Add the type of documents to be processed here.
..allowedDocumentTypes = List.from({_documentSelection.value});
}
/// Method to configure VIZOnlyOnePageFlow.
/// We assume that after this one page flow, we either go to the NFC flow if possible, or fall back to the optical flow.
void _configureVIZOnlyOnePageFlow(VIZOnlyOnePageFlow flow) {
flow
..baseUrl = _baseUrl
..accessKey = _accessKey
// Add the type of documents to be processed here.
// For a faster VIZ capture, it is recommended to keep a single document type, as it avoids the VIZ capture algorithm having to check for multiple document types.
..allowedPageTypes = List.from({_documentSelection.value})
// We intend to followup with an NFCOnlyFlow, so do not commit the session yet. Note that ReadIDSessions can only be committed once.
..preventSessionCommit = true
// Configures the preferred MRZ validation, the default is 'accessControl'.
..mrzValidation = MRZValidation.accessControl
// Configure this property to specify if the qr code detection is required. This can be configured to .required if the QR code detection is mandatory
..qrCodeFeatureRequirement = FeatureRequirement.notRequired
// If this is true, a document selection screen will be displayed.
// This significantly improve processing time as only the selected document type has to be processed.
..shouldShowDocumentSelection = false
// Set time interval here if it is required to show manual capture button after the specified time interval. Set it to 0 to show the button instantly.
// Setting this to -1 will never show the manual capture button.
..allowManualCaptureAfterTimeout = -1
// Indicates whether an screen with the VIZ result will be shown. Usually this is only used during development.
..shouldShowVIZResult = false
// Use the following properties to control the quality of the resulting capture.
// You might want to disable these during development of your app for faster testing.
..shouldRequireNoGlareOnDocument = true
..shouldRequireSharpImage = true
..shouldRequireNoFingerOnDocument = true;
}
/// Continues the VIZ flow to the NFC flow.
void _continueFlowChain() async {
ReadIDSession? session = _vizResult?.readIDSession;
/// Retrieve the NFC access key used to access the identity document.
NFCAccessKey? key = _vizResult?.nfcAccessKey;
if (session == null || key == null) {
return;
}
NFCOnlyFlow nfcFlow = NFCOnlyFlow(key, _vizResult?.documentInfo);
nfcFlow
..baseUrl = _baseUrl
..accessKey = _accessKey
..readIDSession = session;
_startReadID(nfcFlow, session);
}
/// Updates the UI to show information from the session, if there is any.
void updateUI({required ReadIDResult? readIDResult}) {
if (readIDResult == null) {
_statusText = null;
_image = null;
setState(() {});
}
final vizResult = readIDResult?.vizResult;
final nfcResult = readIDResult?.nfcResult;
if (nfcResult != null) {
// this is how to retrieve the data from the result, please check the documentation
// for more details on where to find the data you are interested in
_statusText = "${nfcResult.readIDSession?.documentContent?.secondaryIdentifier} "
"${nfcResult.readIDSession?.documentContent?.primaryIdentifier}"
"\n${Strings.verificationResult} ${nfcResult.readIDSession?.consolidatedIdentityData?.chipCloneDetection.value}";
_image = nfcResult.faceImage;
if (nfcResult.readIDSession != null) {
releaseSession(nfcResult.readIDSession!);
}
_vizResult = null;
_shouldShowFlowChainingButton = false;
} else if (vizResult != null) {
// keep a reference for potential flow chain
_vizResult = vizResult;
_shouldShowFlowChainingButton = true;
_statusText = "${vizResult.readIDSession?.documentContent?.secondaryIdentifier} "
"${vizResult.readIDSession?.documentContent?.primaryIdentifier}";
} else {
_statusText = Strings.statusNoResult;
}
setState(() {});
}
/// Always call [release] on the ReadIDSession when the session is complete to prevent memory leaks.
void releaseSession(ReadIDSession session) {
session.release();
}
void handleFailure(Failure failure) {
handleResponse(failure, context);
}
void handleErrorResponse(PlatformException e) {
showGenericDialog(
context: context, title: Strings.genericErrorTitle, message: e.message ?? Strings.genericErrorMessage);
}
/// Call resumeReadID to make sure that the user can continue the session should your Flutter activity be killed on Android.
void resumeReadID() async {
await Future.delayed(const Duration(seconds: 1));
ReadIDResult result = await _readidPlugin.resumeReadID();
if (result.vizResult == null) {
Fluttertoast.showToast(msg: "No previous VIZ result");
debugPrint("No previous VIZ result");
} else {
debugPrint("Previous VIZ result: ${result.vizResult?.readIDSession?.documentContent?.secondaryIdentifier}");
Fluttertoast.showToast(
msg: "Welcome back ${result.vizResult?.readIDSession?.documentContent?.secondaryIdentifier}");
}
if (result.nfcResult == null) {
debugPrint("No previous NFC result");
} else {
debugPrint("Previous NFC result");
_image = result.nfcResult?.faceImage;
updateUI(readIDResult: result);
}
}
}