开始学习使用Flutter MRZ扫描器

583 阅读6分钟

开始使用Flutter MRZ扫描器

随着技术的进步,各种流程不断地被数字化。例如,我们可以在机场从国民身份证或护照上获得旅客的信息,而无需键入每一个信息。

通过扫描护照或国民身份证的MRZ部分,我们可以获得旅客的姓名、国籍、年龄、证件号码,甚至是图像等信息。

简介

本教程将利用BlinkId SDK建立一个简单的Flutter应用程序,从国民身份证或护照上获取用户数据。通过快速扫描,我们将能够从身份证、护照、驾驶执照和几乎所有其他政府颁发的身份证中提取信息。

先决条件

为了继续学习,读者将需要以下条件。

  1. 在您的计算机上安装FlutterSDK。
  2. 具有Flutter的背景知识。
  3. 一个BlinkId账户。

应用程序设置

  1. 在命令行中,通过执行下面的命令,创建一个新的目录来存储我们的项目文件。
mkdir mrz
  1. 将工作目录改为上面创建的目录,并执行下面的命令来创建一个新的Flutter项目。
cd mrz
flutter create --org com.mrzapp mrzapp
  1. 一旦项目创建完毕,在您最喜欢的IDE中打开该项目。在项目根目录下,找到pubspec.yaml 文件,并在依赖关系部分添加以下依赖关系。
  blinkid_flutter: ^5.13.0
  change_app_package_name: any
  • blinkid_flutter是我们将用来扫描护照和国民身份证的MRZ部分以获得用户数据的软件包。
  • change_app_package_name是一个包,我们将用它来改变应用程序的包名。
  1. 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扫描

  1. lib 目录中,创建一个名为scan_screen.dart 的新文件,并添加以下代码片断。

  2. 在上面创建的类中,创建一个名为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 ,它将存储扫描的数据。
  1. _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获得的许可证密钥替换空字符串。

  1. 在这之前,我们可以用我们的应用程序扫描护照和国民身份证,但不能获得扫描结果。为了获得扫描结果,我们需要创建名为buildDriverLicenceResult,getIdResultStringgetPassportResultString 的方法,以字符串格式返回扫描结果。然后,在_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账户设置

  1. 导航到microblink.com并创建一个新的账户。
  2. 从BlinkID账户的设置页面复制许可证密钥,并在scan() 方法中用许可证密钥替换licenseKey 变量。

应用程序测试

我们已经完成了开发我们的应用程序。我们需要对其进行测试,以确保一切按预期运行。因此,我们需要在项目根目录下执行以下命令,在安卓手机上运行该应用程序。

flutter run android --target-platform android-arm

结论

现在您已经学会了如何在Flutter应用程序中设置和使用BlinkId SDK,您可以开始在您的应用程序中使用该SDK。