开始使用Flutter MRZ扫描器
随着技术的进步,各种流程不断地被数字化。例如,我们可以在机场从国民身份证或护照上获得旅客的信息,而无需键入每一个信息。
通过扫描护照或国民身份证的MRZ部分,我们可以获得旅客的姓名、国籍、年龄、证件号码,甚至是图像等信息。
简介
本教程将利用BlinkId SDK建立一个简单的Flutter应用程序,从国民身份证或护照上获取用户数据。通过快速扫描,我们将能够从身份证、护照、驾驶执照和几乎所有其他政府颁发的身份证中提取信息。
先决条件
为了继续学习,读者将需要以下条件。
应用程序设置
- 在命令行中,通过执行下面的命令,创建一个新的目录来存储我们的项目文件。
mkdir mrz
- 将工作目录改为上面创建的目录,并执行下面的命令来创建一个新的Flutter项目。
cd mrz
flutter create --org com.mrzapp mrzapp
- 一旦项目创建完毕,在您最喜欢的IDE中打开该项目。在项目根目录下,找到
pubspec.yaml文件,并在依赖关系部分添加以下依赖关系。
blinkid_flutter: ^5.13.0
change_app_package_name: any
- blinkid_flutter是我们将用来扫描护照和国民身份证的MRZ部分以获得用户数据的软件包。
- change_app_package_name是一个包,我们将用它来改变应用程序的包名。
- 在
lib目录中,在main.dart文件中添加以下代码片段。
class MRZApp extends StatelessWidget {
const MRZApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter MRZ Scanner',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const ScanID(),
);
}
}
MRZ扫描
-
在
lib目录中,创建一个名为scan_screen.dart的新文件,并添加以下代码片断。 -
在上面创建的类中,创建一个名为
ScanID的有状态的Flutter widget,并添加以下代码段。
class ScanID extends StatefulWidget {
const ScanID({Key? key}) : super(key: key);
@override
_ScanIDState createState() => _ScanIDState();
}
class _ScanIDState extends State<ScanID> {
String? _resultString = "";
}
- 在上面的代码片断中,我们创建了一个有状态的部件,在它的状态类中,我们有一个字符串
_resultString,它将存储扫描的数据。
- 在
_ScanIDState类中,创建一个scan()方法,将扫描护照和国民身份证的MRZ部分。用下面的代码片断更新scan()方法。
Future<void> scan() async {
String license;
// Set the license key depending on the target platform you are building for.
if (Theme.of(context).platform == TargetPlatform.iOS) {
license =
"";
} else if (Theme.of(context).platform == TargetPlatform.android) {
license =
"";
} else {
license =
"";
}
var idRecognizer = BlinkIdCombinedRecognizer();
idRecognizer.returnFullDocumentImage = true;
idRecognizer.returnFaceImage = true;
BlinkIdOverlaySettings settings = BlinkIdOverlaySettings();
var results = await MicroblinkScanner.scanWithCamera(
RecognizerCollection([idRecognizer]), settings, license);
if (!mounted) return;
// When the scan is cancelled, the result is null therefore we return to the the main screen.
if (results.isEmpty) return;
//When the result is not null, we check if it is a passport then obtain the details using the `getPassportDetails` method and display them in the UI. If the document type is a national id, we get the details using the `getIdDetails` method and display them in the UI.
for (var result in results) {
if (result is BlinkIdCombinedRecognizerResult) {
if (result.mrzResult?.documentType == MrtdDocumentType.Passport) {
_resultString = getPassportResultString(result);
} else {
_resultString = getIdResultString(result);
}
setState(() {
_resultString = _resultString;
_fullDocumentFrontImageBase64 = result.fullDocumentFrontImage ?? "";
_faceImageBase64 = result.faceImage ?? "";
});
return;
}
}
}
- 在上面的代码片段中,我们检查平台并提供正确的许可证密钥。
- 然后我们检查摄像机是否安装,如果没有,我们返回主屏幕。如果相机已安装,我们扫描文件并获得结果。
用您从BlinkId获得的许可证密钥替换空字符串。
- 在这之前,我们可以用我们的应用程序扫描护照和国民身份证,但不能获得扫描结果。为了获得扫描结果,我们需要创建名为
buildDriverLicenceResult,getIdResultString和getPassportResultString的方法,以字符串格式返回扫描结果。然后,在_ScanIDState类中添加以下函数来获得扫描结果。
//This method is used to obtain the specific user details from the national id from the scan result object.
String getIdResultString(BlinkIdCombinedRecognizerResult result) {
// The information below will be otained from the natioal id if they are available.
// In the case a field is not found, then it is skipped. For example, some national ids do not have the profession field.
return buildResult(result.firstName, "First name") +
buildResult(result.lastName, "Last name") +
buildResult(result.fullName, "Full name") +
buildResult(result.localizedName, "Localized name") +
buildResult(result.additionalNameInformation, "Additional name info") +
buildResult(result.address, "Address") +
buildResult(
result.additionalAddressInformation, "Additional address info") +
buildResult(result.documentNumber, "Document number") +
buildResult(
result.documentAdditionalNumber, "Additional document number") +
buildResult(result.sex, "Sex") +
buildResult(result.issuingAuthority, "Issuing authority") +
buildResult(result.nationality, "Nationality") +
buildDateResult(result.dateOfBirth, "Date of birth") +
buildIntResult(result.age, "Age") +
buildDateResult(result.dateOfIssue, "Date of issue") +
buildDateResult(result.dateOfExpiry, "Date of expiry") +
buildResult(result.dateOfExpiryPermanent.toString(),
"Date of expiry permanent") +
buildResult(result.maritalStatus, "Martial status") +
buildResult(result.personalIdNumber, "Personal Id Number") +
buildResult(result.profession, "Profession") +
buildResult(result.race, "Race") +
buildResult(result.religion, "Religion") +
buildResult(result.residentialStatus, "Residential Status") +
buildDriverLicenceResult(result.driverLicenseDetailedInfo);
}
String buildResult(String? result, String propertyName) {
if (result == null || result.isEmpty) {
return "";
}
return propertyName + ": " + result + "\n";
}
//This function creates a complete date based on the date obtained from the scanned document. For example, date of the document issue.
String buildDateResult(Date? result, String propertyName) {
if (result == null || result.year == 0) {
return "";
}
return buildResult(
"${result.day}.${result.month}.${result.year}", propertyName);
}
String buildIntResult(int? result, String propertyName) {
if (result == null || result < 0) {
return "";
}
return buildResult(result.toString(), propertyName);
}
//This method obtained the
String buildDriverLicenceResult(DriverLicenseDetailedInfo? result) {
if (result == null) {
return "";
}
return buildResult(result.restrictions, "Restrictions") +
buildResult(result.endorsements, "Endorsements") +
buildResult(result.vehicleClass, "Vehicle class") +
buildResult(result.conditions, "Conditions");
}
String getPassportResultString(BlinkIdCombinedRecognizerResult? result) {
if (result == null) {
return "";
}
var dateOfBirth = "";
if (result.mrzResult?.dateOfBirth != null) {
dateOfBirth = "Date of birth: ${result.mrzResult!.dateOfBirth?.day}."
"${result.mrzResult!.dateOfBirth?.month}."
"${result.mrzResult!.dateOfBirth?.year}\n";
}
var dateOfExpiry = "";
if (result.mrzResult?.dateOfExpiry != null) {
dateOfExpiry = "Date of expiry: ${result.mrzResult?.dateOfExpiry?.day}."
"${result.mrzResult?.dateOfExpiry?.month}."
"${result.mrzResult?.dateOfExpiry?.year}\n";
}
return "First name: ${result.mrzResult?.secondaryId}\n"
"Last name: ${result.mrzResult?.primaryId}\n"
"Document number: ${result.mrzResult?.documentNumber}\n"
"Sex: ${result.mrzResult?.gender}\n"
"$dateOfBirth"
"$dateOfExpiry";
}
// This widget will display a complete image of the scanned passport or national id.
buildDriverLicenceResult方法用于在扫描驾照时从扫描结果对象中获得驾照细节。getIdResultString方法用于从扫描的国民身份证中获得用户的详细信息。buildResult方法用于从扫描的文件中获得具体日期,即出生日期、签发日期、到期日期等。
扫描数据的用户界面
然后,我们需要在用户界面上显示从扫描获得的数据。因此,我们需要在_ScanIDState 类中添加以下小部件。
// This widget will display a complete image of the passport or national id that is scanned.
@override
Widget build(BuildContext context) {
Widget fullDocumentFrontImage = Container();
if (_fullDocumentFrontImageBase64 != null &&
_fullDocumentFrontImageBase64 != "") {
fullDocumentFrontImage = Column(
children: <Widget>[
const Text("Document Front Image:"),
Image.memory(
const Base64Decoder().convert(_fullDocumentFrontImageBase64!),
height: 180,
width: 350,
)
],
);
}
//This widget will show the user image obtained from the passport or national id
Widget faceImage = Container();
if (_faceImageBase64 != null && _faceImageBase64 != "") {
faceImage = Column(
children: <Widget>[
const Text("Face Image:"),
Image.memory(
const Base64Decoder().convert(_faceImageBase64!),
height: 150,
width: 100,
)
],
);
}
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
automaticallyImplyLeading: true,
centerTitle: true,
title: const Text(
"Scan ID for Visitor",
style: TextStyle(color: Colors.white),
),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
Padding(
child: ElevatedButton(
child: const Text("Scan ID"),
onPressed: () => scan(),
),
padding: const EdgeInsets.only(bottom: 16.0)),
Text(_resultString!),
fullDocumentFrontImage,
// fullDocumentBackImage,
faceImage,
],
),
),
),
);
}
- 在扫描护照或国民身份证时,
scan()方法启动相机应用程序。当扫描完成后,getIdResultString()方法被调用,对来自scan()方法的结果进行解码并显示在屏幕上。 - 当扫描完成后,调用
getPassportResultString()方法对来自scan()方法的结果进行解码,并将其显示在屏幕上。
BlinkId账户设置
- 导航到microblink.com并创建一个新的账户。
- 从BlinkID账户的设置页面复制许可证密钥,并在
scan()方法中用许可证密钥替换licenseKey变量。
应用程序测试
我们已经完成了开发我们的应用程序。我们需要对其进行测试,以确保一切按预期运行。因此,我们需要在项目根目录下执行以下命令,在安卓手机上运行该应用程序。
flutter run android --target-platform android-arm
结论
现在您已经学会了如何在Flutter应用程序中设置和使用BlinkId SDK,您可以开始在您的应用程序中使用该SDK。