Flutter面部识别插件facetec_flutter_plugin_demo的使用

发布于 1周前 作者 ionicwang 来自 Flutter

Flutter面部识别插件facetec_flutter_plugin_demo的使用

更新版本以支持最新SDK版本

此插件通过Android或iOS平台为Flutter应用提供对FaceTec SDK的便捷访问。该插件由SnapCommute Labs Pvt. Ltd. 创建。该插件功能有限。如需完整的插件功能,请发送邮件至plugins@snapcommute.com。完整版插件包含注册、认证、ID扫描等功能,并且具有通过FaceTec SDK提供的完整自定义选项。

注意事项

此插件仅是一个演示插件,具有最低限度的功能。目前,该插件与iOS和Android SDK版本9.6.16兼容,Flutter版本为3.3。

安装

在项目的pubspec.yaml文件中添加以下内容:

facetec_flutter_plugin_demo:
  path: ../

根据示例应用,更新FaceTec开发者网站上提供的设备密钥标识符。

文件复制和修改

由于FaceTec SDK文件较大,不包含在Flutter Pub文件夹中。请访问FaceTec开发者网站(dev.facetec.com)下载SDK文件,并将相应的文件复制到此插件的根目录下。

对于Android,下载的zip文件中会有一个.aar文件(例如facetec-sdk-version#.aar),需要将其复制到android根目录下的libs文件夹中。对于iOS,下载的zip文件中会有一个名为FaceTecSDK.xcframework的文件夹,需要将其复制到iOS根目录下。

还需要复制图像文件以确保最新的SDK正常工作。对于Android,将所有动画和可绘制文件夹复制到res文件夹中。这些文件夹可以在从FaceTec网站下载的SDK zip文件中的Android示例应用中找到。对于iOS,将所有图像文件复制到类似结构的assets/images文件夹中,并在pubspec.yaml文件中添加相应的资产代码。

对于iOS,还需要在info.plist文件中添加NSCameraUsageDescription,以便相机权限屏幕出现。

插件中可用的函数

FacetecFlutterPluginDemo.initialize("ADD YOUR KEY HERE", isProductionMode, "PRODUCTION KEY TEXT");
FacetecFlutterPluginDemo.verify();
FacetecFlutterPluginDemo.enroll("user_id");
FacetecFlutterPluginDemo.authenticate("user_id");
FacetecFlutterPluginDemo.idCheck("user_id", isNewUser);
FacetecFlutterPluginDemo.getEnrollmentStatus("user_id", "CUSTOM ENROLLMENT STATUS END POINT");
FacetecFlutterPluginDemo.deleteEnrollment("user_id", "CUSTOM DELETE ENROLLMENT END POINT");
FacetecFlutterPluginDemo.auditTrail();
FacetecFlutterPluginDemo.idScanImages();
FacetecFlutterPluginDemo.setServerUrl("sever_url");
FacetecFlutterPluginDemo.setPublicKey("public_key");
FacetecFlutterPluginDemo.setTheme("theme");
FacetecFlutterPluginDemo.getSdkStatus();
FacetecFlutterPluginDemo.getVersion();

使用示例

以下是完整的示例代码,展示了如何使用facetec_flutter_plugin_demo插件进行初始化、注册、认证等操作。

import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:io';
import 'dart:convert';

import 'package:flutter/services.dart';
import 'package:facetec_flutter_plugin_demo/facetec_flutter_plugin_demo.dart';

void main() {
  runApp(MaterialApp(
    home: MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _platformVersion = 'Unknown';
  String message = "";
  int messageCounter = 0;
  TextEditingController textFieldController = TextEditingController();
  bool initialized = false;
  File? idImageFile;
  String base64image = "";
  GlobalKey scaffoldKey = GlobalKey();

  [@override](/user/override)
  void initState() {
    super.initState();
    initPlatformState();
  }

  void addMessage(String msg, BuildContext context) {
    setState(() {
      messageCounter++;
      showToast(context, msg);
      message = messageCounter.toString() + ": " + msg + "\n" + message;
    });
  }

  void showToast(BuildContext context, String msg) {
    final scaffold = ScaffoldMessenger.of(scaffoldKey.currentContext!);
    scaffold.showSnackBar(
      SnackBar(
        content: Text(msg),
        action: SnackBarAction(
            label: 'OK', onPressed: scaffold.hideCurrentSnackBar),
      ),
    );
  }

  // 平台消息异步,因此我们在异步方法中初始化。
  Future<void> initPlatformState() async {
    String platformVersion;
    // 平台消息可能失败,所以我们使用try/catch来处理PlatformException。
    // 我们还处理消息可能返回null的情况。
    try {
      platformVersion = await FacetecFlutterPluginDemo.platformVersion;
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }

    // 如果在异步平台消息飞行期间小部件从树中删除,我们想要丢弃回复而不是调用
    // setState来更新我们的不存在的外观。
    if (!mounted) return;

    setState(() {
      _platformVersion = platformVersion;
    });
  }

  Future<void> displayTextInputDialog(
      BuildContext context, String title, Function onOk) async {
    return showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            title: Text(title),
            content: TextField(
              controller: textFieldController,
              decoration: InputDecoration(hintText: "Enter details"),
            ),
            actions: <Widget>[
              TextButton(
                style: TextButton.styleFrom(backgroundColor: Colors.red, primary: Colors.white),
                child: Text('CANCEL'),
                onPressed: () {
                  setState(() {
                    Navigator.pop(context);
                  });
                },
              ),
              TextButton(
                style: TextButton.styleFrom(backgroundColor: Colors.red, primary: Colors.white),
                child: Text('OK'),
                onPressed: () {
                  setState(() {
                    onOk();
                    Navigator.pop(context);
                  });
                },
              ),
            ],
          );
        });
  }

  final ButtonStyle flatButtonStyle = TextButton.styleFrom(
    primary: Colors.white,
    shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
    backgroundColor: Colors.lightBlue,
  );

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      key: scaffoldKey,
      appBar: AppBar(
        title: const Text('FaceTec Plugin Demo'),
      ),
      body: Center(
          child: SingleChildScrollView(
        scrollDirection: Axis.vertical,
        child: ConstrainedBox(
          constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                mainAxisSize: MainAxisSize.max,
                children: [
                  Container(
                    margin: EdgeInsets.all(2),
                    child: TextButton(
                      child: Text(
                        'Initialize',
                        style: TextStyle(fontSize: 20.0),
                      ),
                      onPressed: () async {
                        String publicKey = "-----BEGIN PUBLIC KEY-----\n" +
                            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5PxZ3DLj+zP6T6HFgzzk\n" +
                            "M77LdzP3fojBoLasw7EfzvLMnJNUlyRb5m8e5QyyJxI+wRjsALHvFgLzGwxM8ehz\n" +
                            "DqqBZed+f4w33GgQXFZOS4AOvyPbALgCYoLehigLAbbCNTkeY5RDcmmSI/sbp+s6\n" +
                            "mAiAKKvCdIqe17bltZ/rfEoL3gPKEfLXeN549LTj3XBp0hvG4loQ6eC1E1tRzSkf\n" +
                            "GJD4GIVvR+j12gXAaftj3ahfYxioBH7F7HQxzmWkwDyn3bqU54eaiB7f0ftsPpWM\n" +
                            "ceUaqkL2DZUvgN0efEJjnWy5y1/Gkq5GGWCROI9XG/SwXJ30BbVUehTbVcD70+ZF\n" +
                            "8QIDAQAB\n" +
                            "-----END PUBLIC KEY-----";
                        String serverUrl =
                            "https://api.facetec.com/api/v3.1/biometrics";
                        String appToken = "Enter your FaceTec license key here";
                        String publicKeyMsg =
                            await FacetecFlutterPluginDemo.setPublicKey(
                                publicKey);
                        if (publicKeyMsg.startsWith("success")) {
                          addMessage(publicKeyMsg.substring(7), context);
                        } else {
                          addMessage(publicKeyMsg.substring(5), context);
                        }
                        String serverUrlMsg =
                            await FacetecFlutterPluginDemo.setServerUrl(
                                serverUrl);
                        if (serverUrlMsg.startsWith("success")) {
                          addMessage(serverUrlMsg.substring(7), context);
                        } else {
                          addMessage(serverUrlMsg.substring(5), context);
                        }
                        String initializeMsg =
                            await FacetecFlutterPluginDemo.initialize(
                                appToken, false, "");
                        if (initializeMsg.startsWith("success")) {
                          initialized = true;
                          addMessage(initializeMsg.substring(7), context);
                        } else {
                          addMessage(initializeMsg.substring(5), context);
                        }
                      },
                      style: flatButtonStyle,
                    ),
                  ),
                  Container(
                    margin: EdgeInsets.all(2),
                    child: TextButton(
                      child: Text(
                        'Enroll',
                        style: TextStyle(fontSize: 20.0),
                      ),
                      onPressed: () {
                        if (initialized) {
                          displayTextInputDialog(context, "Enter user Id", () async {
                            String enrollMsg =
                                await FacetecFlutterPluginDemo.enroll(
                                    textFieldController.text);
                            if (enrollMsg.startsWith("success")) {
                              addMessage(enrollMsg.substring(7), context);
                            } else {
                              addMessage(enrollMsg.substring(5), context);
                            }
                          });
                        } else {
                          showToast(context, "SDK not initialized");
                        }
                      },
                      style: flatButtonStyle,
                    ),
                  ),
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                mainAxisSize: MainAxisSize.max,
                children: [
                  Container(
                    margin: EdgeInsets.all(2),
                    child: TextButton(
                      child: Text(
                        'Authenticate',
                        style: TextStyle(fontSize: 20.0),
                      ),
                      onPressed: () {
                        if (initialized) {
                          displayTextInputDialog(context, "Enter user Id", () async {
                            String enrollMsg =
                                await FacetecFlutterPluginDemo.authenticate(
                                    textFieldController.text);
                            if (enrollMsg.startsWith("success")) {
                              addMessage(enrollMsg.substring(7), context);
                            } else {
                              addMessage(enrollMsg.substring(5), context);
                            }
                          });
                        } else {
                          showToast(context, "SDK not initialized");
                        }
                      },
                      style: flatButtonStyle,
                    ),
                  ),
                  Container(
                    margin: EdgeInsets.all(2),
                    child: TextButton(
                      child: Text(
                        'Verify',
                        style: TextStyle(fontSize: 20.0),
                      ),
                      onPressed: () async {
                        if (initialized) {
                          String enrollMsg =
                              await FacetecFlutterPluginDemo.verify();
                          if (enrollMsg.startsWith("success")) {
                            addMessage(enrollMsg.substring(7), context);
                          } else {
                            addMessage(enrollMsg.substring(5), context);
                          }
                        } else {
                          showToast(context, "SDK not initialized");
                        }
                      },
                      style: flatButtonStyle,
                    ),
                  ),
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                mainAxisSize: MainAxisSize.max,
                children: [
                  Container(
                    margin: EdgeInsets.all(2),
                    child: TextButton(
                      child: Text(
                        'IDCheck',
                        style: TextStyle(fontSize: 20.0),
                      ),
                      onPressed: () {
                        if (initialized) {
                          showSimpleDialogIDCheck(context, false);
                        } else {
                          showToast(context, "SDK not initialized");
                        }
                      },
                      style: flatButtonStyle,
                    ),
                  ),
                  Container(
                    margin: EdgeInsets.all(2),
                    child: TextButton(
                      child: Text(
                        'Audit Trail',
                        style: TextStyle(fontSize: 20.0),
                      ),
                      onPressed: () async {
                        if (initialized) {
                          String enrollMsg =
                              await FacetecFlutterPluginDemo.auditTrail();
                          if (enrollMsg.startsWith("success")) {
                            await showDialog(
                                context: context,
                                builder: (_) => imageDialog('IDscanImage', enrollMsg.substring(7), context));
                          } else {
                            addMessage(enrollMsg.substring(5), context);
                          }
                        } else {
                          showToast(context, "SDK not initialized");
                        }
                      },
                      style: flatButtonStyle,
                    ),
                  ),
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                mainAxisSize: MainAxisSize.max,
                children: [
                  Container(
                    margin: EdgeInsets.all(2),
                    child: TextButton(
                      child: Text(
                        'ID Scan Images',
                        style: TextStyle(fontSize: 20.0),
                      ),
                      onPressed: () async {
                        if (initialized) {
                          String enrollMsg =
                              await FacetecFlutterPluginDemo.idScanImages();
                          if (enrollMsg.startsWith("success")) {
                            await showDialog(
                                context: context,
                                builder: (_) => imageDialog('IDscanImage', enrollMsg.substring(7), context));
                          } else {
                            addMessage(enrollMsg.substring(5), context);
                          }
                        } else {
                          showToast(context, "SDK not initialized");
                        }
                      },
                      style: flatButtonStyle,
                    ),
                  ),
                  Container(
                    margin: EdgeInsets.all(2),
                    child: TextButton(
                      child: Text(
                        'Set Theme',
                        style: TextStyle(fontSize: 20.0),
                      ),
                      onPressed: () {
                        showSimpleDialog(context);
                      },
                      style: flatButtonStyle,
                    ),
                  ),
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                mainAxisSize: MainAxisSize.max,
                children: [
                  Container(
                    margin: EdgeInsets.all(2),
                    child: TextButton(
                      child: Text(
                        'Get Version',
                        style: TextStyle(fontSize: 20.0),
                      ),
                      onPressed: () async {
                        String versionMsg =
                            await FacetecFlutterPluginDemo.getVersion();
                        if (versionMsg.startsWith("success")) {
                          addMessage(versionMsg.substring(7), context);
                        } else {
                          addMessage(versionMsg.substring(5), context);
                        }
                      },
                      style: flatButtonStyle,
                    ),
                  ),
                  Container(
                    margin: EdgeInsets.all(2),
                    child: TextButton(
                      child: Text(
                        'Get SDK Status',
                        style: TextStyle(fontSize: 20.0),
                      ),
                      onPressed: () async {
                        String statusMsg =
                            await FacetecFlutterPluginDemo.getSdkStatus();
                        if (statusMsg.startsWith("success")) {
                          addMessage(statusMsg.substring(7), context);
                        } else {
                          addMessage(statusMsg.substring(5), context);
                        }
                      },
                      style: flatButtonStyle,
                    ),
                  ),
                ],
              ),
              Container(
                margin: EdgeInsets.all(2),
                child: TextButton(
                  child: Text(
                    'Get User Enrollment Status',
                    style: TextStyle(fontSize: 20.0),
                  ),
                  onPressed: () {
                    if (initialized) {
                      displayTextInputDialog(context, "Enter user Id", () async {
                        String enrollMsg = await FacetecFlutterPluginDemo.getUserEnrollmentStatus(
                            textFieldController.text, "");
                        if (enrollMsg.startsWith("success")) {
                          addMessage(enrollMsg.substring(7), context);
                        } else {
                          addMessage(enrollMsg.substring(5), context);
                        }
                      });
                    } else {
                      showToast(context, "SDK not initialized");
                    }
                  },
                  style: flatButtonStyle,
                ),
              ),
              Container(
                margin: EdgeInsets.all(2),
                child: TextButton(
                  child: Text(
                    'Delete Enrollment',
                    style: TextStyle(fontSize: 20.0),
                  ),
                  onPressed: () async {
                    if (initialized) {
                      displayTextInputDialog(context, "Enter user Id", () async {
                        String enrollMsg =
                            await FacetecFlutterPluginDemo.deleteEnrollment(
                                textFieldController.text, "");
                        if (enrollMsg.startsWith("success")) {
                          addMessage(enrollMsg.substring(7), context);
                        } else {
                          addMessage(enrollMsg.substring(5), context);
                        }
                      });
                    } else {
                      showToast(context, "SDK not initialized");
                    }
                  },
                  style: flatButtonStyle,
                ),
              ),
              Expanded(
                flex: 1,
                child: SingleChildScrollView(
                  scrollDirection: Axis.vertical,
                  child: Text(
                    message,
                  ),
                ),
              ),
            ],
          ),
        ),
      )),
    );
  }

  // 显示对话框
  showSimpleDialog(BuildContext context) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return SimpleDialog(
          title: const Text('Choose an theme'),
          children: [
            SimpleDialogOption(
              child: const Text("FaceTec Theme"),
              onPressed: () {
                Navigator.of(context).pop();
                setTheme("FaceTec Theme");
              },
            ),
            SimpleDialogOption(
              child: const Text("Pseudo-Fullscreen"),
              onPressed: () {
                Navigator.of(context).pop();
                setTheme("Pseudo-Fullscreen");
              },
            ),
            SimpleDialogOption(
              child: const Text("Well-Rounded"),
              onPressed: () {
                Navigator.of(context).pop();
                setTheme("Well-Rounded");
              },
            ),
            SimpleDialogOption(
              child: const Text("Bitcoin Exchange"),
              onPressed: () {
                Navigator.of(context).pop();
                setTheme("Bitcoin Exchange");
              },
            ),
            SimpleDialogOption(
              child: const Text("eKYC"),
              onPressed: () {
                Navigator.of(context).pop();
                setTheme("eKYC");
              },
            ),
            SimpleDialogOption(
              child: const Text("Sample Bank"),
              onPressed: () {
                Navigator.of(context).pop();
                setTheme("Sample Bank");
              },
            )
          ],
        );
      },
    );
  }

  setTheme(String theme) {
    FacetecFlutterPluginDemo.setTheme(theme);
  }

  Image imageFromBase64String(String base64String) {
    return Image.memory(base64Decode(base64String));
  }

  Widget imageDialog(text, base64, context) {
    return Dialog(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Padding(
            padding: const EdgeInsets.only(left: 8.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text(
                  '$text',
                  style: TextStyle(fontWeight: FontWeight.bold),
                ),
                IconButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  icon: Icon(Icons.close_rounded),
                  color: Colors.redAccent,
                ),
              ],
            ),
          ),
          Container(
            width: 220,
            height: 200,
            child: imageFromBase64String(base64),
          ),
        ],
      ),
    );
  }

  showSimpleDialogIDCheck(BuildContext context, bool custom) {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return SimpleDialog(
          title: const Text('Choose whether existing or new user'),
          children: [
            SimpleDialogOption(
              child: const Text("Existing User"),
              onPressed: () {
                Navigator.of(context).pop();
                if (custom) {
                } else {
                  displayTextInputDialog(context, "Enter user Id", () async {
                    String enrollMsg = await FacetecFlutterPluginDemo.idCheck(
                        textFieldController.text, false);
                    if (enrollMsg.startsWith("success")) {
                      addMessage(enrollMsg.substring(7), context);
                    } else {
                      addMessage(enrollMsg.substring(5), context);
                    }
                  });
                }
              },
            ),
            SimpleDialogOption(
              child: const Text("New User"),
              onPressed: () {
                Navigator.of(context).pop();
                if (custom) {
                } else {
                  displayTextInputDialog(context, "Enter user Id", () async {
                    String enrollMsg = await FacetecFlutterPluginDemo.idCheck(
                        textFieldController.text, true);
                    if (enrollMsg.startsWith("success")) {
                      addMessage(enrollMsg.substring(7), context);
                    } else {
                      addMessage(enrollMsg.substring(5), context);
                    }
                  });
                }
              },
            ),
          ],
        );
      },
    );
  }
}

更多关于Flutter面部识别插件facetec_flutter_plugin_demo的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter面部识别插件facetec_flutter_plugin_demo的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何使用 facetec_flutter_plugin_demo 插件的示例代码。这个插件通常用于面部识别功能,假设你已经安装并配置好了 Flutter 环境,并且已经添加了 facetec_flutter_plugin 到你的 pubspec.yaml 文件中。

1. 添加依赖

首先,确保你的 pubspec.yaml 文件中已经包含了 facetec_flutter_plugin 的依赖:

dependencies:
  flutter:
    sdk: flutter
  facetec_flutter_plugin: ^latest_version  # 请替换为实际最新版本号

然后运行 flutter pub get 来安装依赖。

2. 配置 Android 和 iOS

由于面部识别功能涉及到原生代码,你需要在 Android 和 iOS 项目中进行一些配置。这通常包括添加必要的权限和配置文件。详细步骤请参考插件的官方文档。

3. 使用插件进行面部识别

以下是一个简单的 Flutter 应用示例,展示如何使用 facetec_flutter_plugin 进行面部识别:

import 'package:flutter/material.dart';
import 'package:facetec_flutter_plugin/facetec_flutter_plugin.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String result = "";

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Facetec Flutter Plugin Demo'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'Face Recognition Result:',
                style: TextStyle(fontSize: 20),
              ),
              SizedBox(height: 20),
              Text(
                result,
                style: TextStyle(fontSize: 18),
              ),
              SizedBox(height: 40),
              ElevatedButton(
                onPressed: () async {
                  try {
                    // 这里假设你已经有了一个 FaceTec 账户并获取了必要的 API 密钥等信息
                    String apiKey = "YOUR_API_KEY";
                    String apiSecret = "YOUR_API_SECRET";
                    String sessionId = "YOUR_SESSION_ID"; // 这个通常是在开始会话时由服务器生成的

                    // 初始化插件
                    FacetecFlutterPlugin facetec = FacetecFlutterPlugin();

                    // 开始面部识别
                    String recognitionResult = await facetec.startFaceRecognition(
                      apiKey: apiKey,
                      apiSecret: apiSecret,
                      sessionId: sessionId,
                    );

                    // 更新 UI
                    setState(() {
                      result = recognitionResult;
                    });
                  } catch (e) {
                    setState(() {
                      result = "Error: ${e.message}";
                    });
                  }
                },
                child: Text('Start Face Recognition'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

注意事项

  1. API 密钥和会话管理:在实际应用中,你需要管理 API 密钥和会话 ID。通常,你会有一个后端服务来处理这些敏感信息,并生成会话 ID。

  2. 错误处理:上面的示例中简单地捕获了异常并更新了 UI,但在生产环境中,你可能需要更详细的错误处理和用户反馈。

  3. 权限请求:确保在 Android 和 iOS 上请求了必要的权限,如相机权限。

  4. UI/UX:上面的示例是一个简单的按钮点击事件,实际应用中你可能需要更复杂的 UI/UX 设计,比如引导用户进行面部扫描的界面。

  5. 插件版本:确保你使用的是最新版本的插件,并查看官方文档以获取最新的使用指南和 API 更改。

这个示例代码应该能帮助你开始使用 facetec_flutter_plugin 进行面部识别。如果你有更具体的需求或遇到问题,请查阅插件的官方文档或寻求官方支持。

回到顶部