feat(arc): 添加虹软人脸识别插件基础功能

- 集成虹软 ArcSoft Face SDK,提供人脸检测、识别、活体检测功能
- 实现 Android 平台原生插件,包含 ArcPlugin 和 FaceEngineManager
- 添加完整的人脸错误码枚举(586个错误码),覆盖 SDK 所有错误情况
- 创建人脸信息数据模型 FaceInfo,封装检测结果和特征数据
- 配置 Android 权限和依赖,包括相机、存储、网络等必要权限
- 添加方法通道实现,连接 Flutter 层与原生层通信
- 配置项目基础文件,包含 .gitignore、分析选项和元数据配置
- 实现单元测试框架,包含 Dart 和 Java 层的基本测试用例
- 添加示例应用配置,验证插件集成和基本功能使用
- 提供详细的开发指导文档 CLAUDE.md,说明架构和 API 使用方法
This commit is contained in:
2026-03-30 17:13:58 +08:00
parent fe851528df
commit 2a1cfd230d
50 changed files with 4357 additions and 0 deletions

9
android/.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.cxx

59
android/build.gradle Normal file
View File

@@ -0,0 +1,59 @@
group = "com.xiarui.arc"
version = "1.0"
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:8.9.1")
}
}
rootProject.allprojects {
repositories {
google()
mavenCentral()
}
}
apply plugin: "com.android.library"
android {
namespace = "com.xiarui.arc"
compileSdk = 36
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
defaultConfig {
minSdk = 24
}
sourceSets {
main {
jniLibs.srcDirs = ['src/main/jniLibs']
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation("junit:junit:4.13.2")
testImplementation("org.mockito:mockito-core:5.0.0")
}
testOptions {
unitTests.all {
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
outputs.upToDateWhen {false}
showStandardStreams = true
}
}
}
}

Binary file not shown.

Binary file not shown.

1
android/settings.gradle Normal file
View File

@@ -0,0 +1 @@
rootProject.name = 'arc'

View File

@@ -0,0 +1,12 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.xiarui.arc">
<!-- 虹软 SDK 所需权限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.FLASHLIGHT"/>
</manifest>

View File

@@ -0,0 +1,586 @@
package com.xiarui.arc;
/**
* 虹软人脸识别 SDK 错误码枚举
* 映射 SDK 返回的错误码到可读描述
* 官方错误码文档https://ai.arcsoft.com.cn
*/
public enum FaceErrorCode {
// ==================== 通用错误码 ====================
/**
* 成功
*/
MOK(0, "0x0", "成功"),
/**
* 错误原因不明
*/
MERR_UNKNOWN(1, "0x1", "错误原因不明"),
/**
* 无效的参数
*/
MERR_INVALID_PARAM(2, "0x2", "无效的参数"),
/**
* 引擎不支持
*/
MERR_UNSUPPORTED(3, "0x3", "引擎不支持"),
/**
* 内存不足
*/
MERR_NO_MEMORY(4, "0x4", "内存不足"),
/**
* 状态错误
*/
MERR_BAD_STATE(5, "0x5", "状态错误"),
/**
* 用户取消相关操作
*/
MERR_USER_CANCEL(6, "0x6", "用户取消相关操作"),
/**
* 操作时间过期
*/
MERR_EXPIRED(7, "0x7", "操作时间过期"),
/**
* 用户暂停操作
*/
MERR_USER_PAUSE(8, "0x8", "用户暂停操作"),
/**
* 缓冲上溢
*/
MERR_BUFFER_OVERFLOW(9, "0x9", "缓冲上溢"),
/**
* 缓冲下溢
*/
MERR_BUFFER_UNDERFLOW(10, "0xA", "缓冲下溢"),
/**
* 存贮空间不足
*/
MERR_NO_DISKSPACE(11, "0xB", "存贮空间不足"),
/**
* 组件不存在
*/
MERR_COMPONENT_NOT_EXIST(12, "0xC", "组件不存在"),
/**
* 全局数据不存在
*/
MERR_GLOBAL_DATA_NOT_EXIST(13, "0xD", "全局数据不存在"),
// ==================== SDK 基础错误码 ====================
/**
* 无效的 APP_ID
*/
MERR_FSDK_INVALID_APP_ID(28673, "0x7001", "无效的 APP_ID"),
/**
* 无效的 SDK_KEY
*/
MERR_FSDK_INVALID_SDK_ID(28674, "0x7002", "无效的 SDK_KEY"),
/**
* APP_ID 和 SDK_KEY 不匹配
*/
MERR_FSDK_INVALID_ID_PAIR(28675, "0x7003", "APP_ID 和 SDK_KEY 不匹配"),
/**
* SDK_KEY 和使用的 SDK 不匹配
*/
MERR_FSDK_MISMATCH_ID_AND_SDK(28676, "0x7004", "SDK_KEY 和使用的 SDK 不匹配"),
/**
* 系统版本不被当前 SDK 所支持
*/
MERR_FSDK_SYSTEM_VERSION_UNSUPPORTED(28677, "0x7005", "系统版本不被当前 SDK 所支持"),
// ==================== 人脸识别基础错误码 ====================
/**
* 无效的输入内存
*/
MERR_FSDK_FR_INVALID_MEMORY_INFO(73729, "0x12001", "无效的输入内存"),
/**
* 无效的输入图像参数
*/
MERR_FSDK_FR_INVALID_IMAGE_INFO(73730, "0x12002", "无效的输入图像参数"),
/**
* 无效的脸部信息
*/
MERR_FSDK_FR_INVALID_FACE_INFO(73731, "0x12003", "无效的脸部信息"),
/**
* 当前设备无 GPU 可用
*/
MERR_FSDK_FR_NO_GPU_AVAILABLE(73732, "0x12004", "当前设备无 GPU 可用"),
/**
* 待比较的两个人脸特征的版本不一致
*/
MERR_FSDK_FR_MISMATCHED_FEATURE_LEVEL(73733, "0x12005", "待比较的两个人脸特征的版本不一致"),
// ==================== 人脸特征检测错误码 ====================
/**
* 人脸特征检测错误未知
*/
MERR_FSDK_FACEFEATURE_UNKNOWN(81921, "0x14001", "人脸特征检测错误未知"),
/**
* 人脸特征检测内存错误
*/
MERR_FSDK_FACEFEATURE_MEMORY(81922, "0x14002", "人脸特征检测内存错误"),
/**
* 人脸特征检测格式错误
*/
MERR_FSDK_FACEFEATURE_INVALID_FORMAT(81923, "0x14003", "人脸特征检测格式错误"),
/**
* 人脸特征检测参数错误
*/
MERR_FSDK_FACEFEATURE_INVALID_PARAM(81924, "0x14004", "人脸特征检测参数错误"),
/**
* 人脸特征检测结果置信度低
*/
MERR_FSDK_FACEFEATURE_LOW_CONFIDENCE_LEVEL(81925, "0x14005", "人脸特征检测结果置信度低"),
/**
* 人脸特征检测结果操作过期
*/
MERR_FSDK_FACEFEATURE_EXPIRED(81926, "0x14006", "人脸特征检测结果操作过期"),
/**
* 人脸特征检测人脸丢失
*/
MERR_FSDK_FACEFEATURE_MISSFACE(81927, "0x14007", "人脸特征检测人脸丢失"),
/**
* 人脸特征检测没有人脸
*/
MERR_FSDK_FACEFEATURE_NO_FACE(81928, "0x14008", "人脸特征检测没有人脸"),
/**
* 人脸特征检测人脸信息错误
*/
MERR_FSDK_FACEFEATURE_FACEDATA(81929, "0x14009", "人脸特征检测人脸信息错误"),
// ==================== ASF 扩展错误码 ====================
/**
* Engine 不支持的检测属性
*/
MERR_ASF_EX_FEATURE_UNSUPPORTED_ON_INIT(86017, "0x15001", "Engine 不支持的检测属性"),
/**
* 需要检测的属性未初始化
*/
MERR_ASF_EX_FEATURE_UNINITED(86018, "0x15002", "需要检测的属性未初始化"),
/**
* 待获取的属性未在 process 中处理过
*/
MERR_ASF_EX_FEATURE_UNPROCESSED(86019, "0x15003", "待获取的属性未在 process 中处理过"),
/**
* PROCESS 不支持的检测属性
*/
MERR_ASF_EX_FEATURE_UNSUPPORTED_ON_PROCESS(86020, "0x15004", "PROCESS 不支持的检测属性"),
/**
* 无效的输入图像
*/
MERR_ASF_EX_INVALID_IMAGE_INFO(86021, "0x15005", "无效的输入图像"),
/**
* 无效的脸部信息
*/
MERR_ASF_EX_INVALID_FACE_INFO(86022, "0x15006", "无效的脸部信息"),
// ==================== 激活相关错误码 ====================
/**
* SDK 激活失败,请打开读写权限
*/
MERR_ASF_ACTIVATION_FAIL(90113, "0x16001", "SDK 激活失败,请打开读写权限"),
/**
* SDK 已激活
*/
MERR_ASF_ALREADY_ACTIVATED(90114, "0x16002", "SDK 已激活"),
/**
* SDK 未激活
*/
MERR_ASF_NOT_ACTIVATED(90115, "0x16003", "SDK 未激活"),
/**
* detectFaceScaleVal 不支持
*/
MERR_ASF_SCALE_NOT_SUPPORT(90116, "0x16004", "detectFaceScaleVal 不支持"),
/**
* 激活文件与 SDK 类型不匹配
*/
MERR_ASF_ACTIVEFILE_SDKTYPE_MISMATCH(90117, "0x16005", "激活文件与 SDK 类型不匹配"),
/**
* 设备不匹配
*/
MERR_ASF_DEVICE_MISMATCH(90118, "0x16006", "设备不匹配"),
/**
* 唯一标识不合法
*/
MERR_ASF_UNIQUE_IDENTIFIER_ILLEGAL(90119, "0x16007", "唯一标识不合法"),
/**
* 参数为空
*/
MERR_ASF_PARAM_NULL(90120, "0x16008", "参数为空"),
/**
* 版本不支持
*/
MERR_ASF_VERSION_NOT_SUPPORT(90122, "0x1600A", "版本不支持"),
/**
* 签名错误
*/
MERR_ASF_SIGN_ERROR(90123, "0x1600B", "签名错误"),
/**
* 激活信息保存异常
*/
MERR_ASF_DATABASE_ERROR(90124, "0x1600C", "激活信息保存异常"),
/**
* 唯一标识符校验失败
*/
MERR_ASF_UNIQUE_CHECKOUT_FAIL(90125, "0x1600D", "唯一标识符校验失败"),
/**
* 颜色空间不支持
*/
MERR_ASF_COLOR_SPACE_NOT_SUPPORT(90126, "0x1600E", "颜色空间不支持"),
/**
* 图片宽高不支持,宽度需四字节对齐
*/
MERR_ASF_IMAGE_WIDTH_HEIGHT_NOT_SUPPORT(90127, "0x1600F", "图片宽高不支持,宽度需四字节对齐"),
/**
* android.permission.READ_PHONE_STATE 权限被拒绝
*/
MERR_ASF_READ_PHONE_STATE_DENIED(90128, "0x16010", "android.permission.READ_PHONE_STATE 权限被拒绝"),
/**
* 激活数据被破坏,请删除激活文件,重新进行激活
*/
MERR_ASF_ACTIVATION_DATA_DESTROYED(90129, "0x16011", "激活数据被破坏,请删除激活文件,重新进行激活"),
/**
* 服务端未知错误
*/
MERR_ASF_SERVER_UNKNOWN_ERROR(90130, "0x16012", "服务端未知错误"),
/**
* android.permission.INTERNET 权限被拒绝
*/
MERR_ASF_INTERNET_DENIED(90131, "0x16013", "android.permission.INTERNET 权限被拒绝"),
/**
* 激活文件与 SDK 版本不匹配,请重新激活
*/
MERR_ASF_ACTIVEFILE_SDK_MISMATCH(90132, "0x16014", "激活文件与 SDK 版本不匹配,请重新激活"),
/**
* 设备信息太少,不足以生成设备指纹
*/
MERR_ASF_DEVICEINFO_LESS(90133, "0x16015", "设备信息太少,不足以生成设备指纹"),
/**
* 客户端时间与服务器时间前后相差在 30 分钟以上
*/
MERR_ASF_LOCAL_TIME_NOT_CALIBRATED(90134, "0x16016", "客户端时间与服务器时间前后相差在 30 分钟以上"),
/**
* 数据校验异常
*/
MERR_ASF_APPID_DATA_DECRYPT(90135, "0x16017", "数据校验异常"),
/**
* 传入的 APP_ID 和 AppKey 与使用的 SDK 版本不一致
*/
MERR_ASF_APPID_APPKEY_SDK_MISMATCH(90136, "0x16018", "传入的 APP_ID 和 AppKey 与使用的 SDK 版本不一致"),
/**
* 短时间大量请求会被禁止请求30 分钟之后解封
*/
MERR_ASF_NO_REQUEST(90137, "0x16019", "短时间大量请求会被禁止请求30 分钟之后解封"),
/**
* 激活文件不存在
*/
MERR_ASF_ACTIVE_FILE_NO_EXIST(90138, "0x1601A", "激活文件不存在"),
/**
* 当前设备时间不正确,请调整设备时间
*/
MERR_ASF_CURRENT_DEVICE_TIME_INCORRECT(90139, "0x1601B", "当前设备时间不正确,请调整设备时间"),
/**
* 检测模型不支持
*/
MERR_ASF_DETECT_MODEL_UNSUPPORTED(90140, "0x1601C", "检测模型不支持"),
// ==================== 网络相关错误码 ====================
/**
* 无法解析主机地址
*/
MERR_ASF_NETWORK_COULDNT_RESOLVE_HOST(94209, "0x17001", "无法解析主机地址"),
/**
* 无法连接服务器
*/
MERR_ASF_NETWORK_COULDNT_CONNECT_SERVER(94210, "0x17002", "无法连接服务器"),
/**
* 网络连接超时
*/
MERR_ASF_NETWORK_CONNECT_TIMEOUT(94211, "0x17003", "网络连接超时"),
/**
* 网络未知错误
*/
MERR_ASF_NETWORK_UNKNOWN_ERROR(94212, "0x17004", "网络未知错误"),
// ==================== 激活密钥相关错误码 ====================
/**
* 无法连接激活服务器
*/
MERR_ASF_ACTIVEKEY_COULDNT_CONNECT_SERVER(98305, "0x18001", "无法连接激活服务器"),
/**
* 服务器系统错误
*/
MERR_ASF_ACTIVEKEY_SERVER_SYSTEM_ERROR(98306, "0x18002", "服务器系统错误"),
/**
* 请求参数错误
*/
MERR_ASF_ACTIVEKEY_POST_PARM_ERROR(98307, "0x18003", "请求参数错误"),
/**
* ACTIVE_KEY 与 APP_ID、SDK_KEY 不匹配
*/
MERR_ASF_ACTIVEKEY_PARM_MISMATCH(98308, "0x18004", "ACTIVE_KEY 与 APP_ID、SDK_KEY 不匹配"),
/**
* ACTIVE_KEY 已经被使用
*/
MERR_ASF_ACTIVEKEY_ACTIVEKEY_ACTIVATED(98309, "0x18005", "ACTIVE_KEY 已经被使用"),
/**
* ACTIVE_KEY 信息异常
*/
MERR_ASF_ACTIVEKEY_ACTIVEKEY_FORMAT_ERROR(98310, "0x18006", "ACTIVE_KEY 信息异常"),
/**
* ACTIVE_KEY 与 APP_ID 不匹配
*/
MERR_ASF_ACTIVEKEY_APPID_PARM_MISMATCH(98311, "0x18007", "ACTIVE_KEY 与 APP_ID 不匹配"),
/**
* SDK 与激活文件版本不匹配
*/
MERR_ASF_ACTIVEKEY_SDK_FILE_MISMATCH(98312, "0x18008", "SDK 与激活文件版本不匹配"),
/**
* ACTIVE_KEY 已过期
*/
MERR_ASF_ACTIVEKEY_EXPIRED(98313, "0x18009", "ACTIVE_KEY 已过期"),
// ==================== 离线授权相关错误码 ====================
/**
* 离线授权文件不存在或无读写权限
*/
MERR_ASF_LICENSE_FILE_NOT_EXIST(102401, "0x19001", "离线授权文件不存在或无读写权限"),
/**
* 离线授权文件已损坏
*/
MERR_ASF_LICENSE_FILE_DATA_DESTROYED(102402, "0x19002", "离线授权文件已损坏"),
/**
* 离线授权文件与 SDK 版本不匹配
*/
MERR_ASF_LICENSE_FILE_SDK_MISMATCH(102403, "0x19003", "离线授权文件与 SDK 版本不匹配"),
/**
* 离线授权文件与 SDK 信息不匹配
*/
MERR_ASF_LICENSE_FILEINFO_SDKINFO_MISMATCH(102404, "0x19004", "离线授权文件与 SDK 信息不匹配"),
/**
* 离线授权文件与设备指纹不匹配
*/
MERR_ASF_LICENSE_FILE_FINGERPRINT_MISMATCH(102405, "0x19005", "离线授权文件与设备指纹不匹配"),
/**
* 离线授权文件已过期
*/
MERR_ASF_LICENSE_FILE_EXPIRED(102406, "0x19006", "离线授权文件已过期"),
/**
* 离线授权文件不可用,本地原有激活文件可继续使用
*/
MERR_ASF_LOCAL_EXIST_USEFUL_ACTIVE_FILE(102407, "0x19007", "离线授权文件不可用,本地原有激活文件可继续使用"),
/**
* 离线授权文件版本过低
*/
MERR_ASF_LICENSE_FILE_VERSION_TOO_LOW(102408, "0x19008", "离线授权文件版本过低"),
// ==================== 人脸搜索相关错误码 ====================
/**
* 人脸列表为空
*/
MERR_ASF_SEARCH_EMPTY(151553, "0x25001", "人脸列表为空"),
/**
* 人脸不存在
*/
MERR_ASF_SEARCH_NO_EXIST(151554, "0x25002", "人脸不存在"),
/**
* 特征值长度不匹配
*/
MERR_ASF_SEARCH_FEATURE_SIZE_MISMATCH(151555, "0x25003", "特征值长度不匹配"),
/**
* 相似度异常
*/
MERR_ASF_SEARCH_LOW_CONFIDENCE(151556, "0x25004", "相似度异常"),
// ==================== 自定义扩展错误码 ====================
/**
* 引擎未初始化(自定义错误码)
*/
ENGINE_NOT_INITIALIZED(-1, "N/A", "引擎未初始化"),
/**
* 未知错误
*/
UNKNOWN(-2, "N/A", "未知错误");
/**
* 错误码(十进制)
*/
private final int code;
/**
* 错误码(十六进制)
*/
private final String hexCode;
/**
* 错误描述
*/
private final String message;
/**
* 构造函数
* @param code 错误码(十进制)
* @param hexCode 错误码(十六进制)
* @param message 错误描述
*/
FaceErrorCode(int code, String hexCode, String message) {
this.code = code;
this.hexCode = hexCode;
this.message = message;
}
/**
* 获取错误码(十进制)
* @return 错误码整数值
*/
public int getCode() {
return code;
}
/**
* 获取错误码(十六进制)
* @return 错误码十六进制字符串
*/
public String getHexCode() {
return hexCode;
}
/**
* 获取错误描述
* @return 错误描述信息
*/
public String getMessage() {
return message;
}
/**
* 根据错误码整数值获取对应的枚举
* @param code 错误码整数(十进制)
* @return 对应的 FaceErrorCode 枚举
*/
public static FaceErrorCode fromCode(int code) {
for (FaceErrorCode e : values()) {
if (e.code == code) {
return e;
}
}
return UNKNOWN;
}
/**
* 根据错误码获取错误描述
* @param code 错误码整数
* @return 错误描述信息
*/
public static String getMessageByCode(int code) {
FaceErrorCode errorCode = fromCode(code);
return errorCode.getMessage();
}
/**
* 判断是否为成功状态
* @param code 错误码整数
* @return true 表示成功false 表示失败
*/
public static boolean isSuccess(int code) {
return code == MOK.getCode();
}
/**
* 获取错误的详细信息(包含十进制、十六进制和描述)
* @return 格式化的错误信息
*/
public String getDetailMessage() {
return String.format("[%d / %s] %s", code, hexCode, message);
}
/**
* 获取错误的详细信息(包含十进制、十六进制和描述)
* @param code 错误码整数
* @return 格式化的错误信息
*/
public static String getDetailMessageByCode(int code) {
FaceErrorCode errorCode = fromCode(code);
return errorCode.getDetailMessage();
}
}

View File

@@ -0,0 +1,292 @@
package com.xiarui.arc;
import android.graphics.Rect;
import java.util.HashMap;
import java.util.Map;
/**
* 人脸信息类
* 封装虹软 SDK 返回的单个人脸检测结果
*/
public class FaceInfo {
/**
* 人脸矩形框(左、上、右、下坐标)
*/
private Rect faceRect;
/**
* 人脸角度0/90/180/270
*/
private int faceOrientation;
/**
* 人脸 IDVIDEO 模式下有效)
*/
private int faceId;
/**
* 人脸相似度(识别功能返回)
*/
private float similarity;
/**
* 活体检测结果(>0 表示活体)
*/
private float liveness;
/**
* 年龄(年龄估计功能返回)
*/
private int age;
/**
* 性别性别识别功能返回0=未知1=男2=女)
*/
private int gender;
/**
* 口罩佩戴状态(口罩检测功能返回,-1=未知0=未佩戴1=已佩戴)
*/
private int maskStatus;
/**
* 人脸特征数据(特征提取功能返回)
*/
private byte[] featureData;
/**
* 默认构造函数
*/
public FaceInfo() {
this.faceRect = new Rect();
this.faceOrientation = 0;
this.faceId = 0;
this.similarity = 0.0f;
this.liveness = 0.0f;
this.age = 0;
this.gender = 0;
this.maskStatus = -1;
this.featureData = null;
}
/**
* 构造函数
* @param faceRect 人脸矩形框
*/
public FaceInfo(Rect faceRect) {
this.faceRect = faceRect;
this.faceOrientation = 0;
this.faceId = 0;
this.similarity = 0.0f;
this.liveness = 0.0f;
this.age = 0;
this.gender = 0;
this.maskStatus = -1;
this.featureData = null;
}
/**
* 获取人脸矩形框
* @return 人脸矩形框 Rect 对象
*/
public Rect getFaceRect() {
return faceRect;
}
/**
* 设置人脸矩形框
* @param faceRect 人脸矩形框
*/
public void setFaceRect(Rect faceRect) {
this.faceRect = faceRect;
}
/**
* 设置人脸矩形 left 坐标
* @param left 左坐标
*/
public void setLeft(int left) {
this.faceRect = new Rect(left, faceRect.top, faceRect.right, faceRect.bottom);
}
/**
* 设置人脸矩形 top 坐标
* @param top 上坐标
*/
public void setTop(int top) {
this.faceRect = new Rect(faceRect.left, top, faceRect.right, faceRect.bottom);
}
/**
* 设置人脸矩形 right 坐标
* @param right 右坐标
*/
public void setRight(int right) {
this.faceRect = new Rect(faceRect.left, faceRect.top, right, faceRect.bottom);
}
/**
* 设置人脸矩形 bottom 坐标
* @param bottom 下坐标
*/
public void setBottom(int bottom) {
this.faceRect = new Rect(faceRect.left, faceRect.top, faceRect.right, bottom);
}
/**
* 设置人脸角度
* @param orient 人脸角度
*/
public void setOrient(int orient) {
this.faceOrientation = orient;
}
/**
* 获取人脸角度
* @return 人脸角度0/90/180/270
*/
public int getFaceOrientation() {
return faceOrientation;
}
/**
* 设置人脸角度
* @param faceOrientation 人脸角度
*/
public void setFaceOrientation(int faceOrientation) {
this.faceOrientation = faceOrientation;
}
/**
* 获取人脸 ID
* @return 人脸 ID
*/
public int getFaceId() {
return faceId;
}
/**
* 设置人脸 ID
* @param faceId 人脸 ID
*/
public void setFaceId(int faceId) {
this.faceId = faceId;
}
/**
* 获取人脸相似度
* @return 人脸相似度0.0-1.0
*/
public float getSimilarity() {
return similarity;
}
/**
* 设置人脸相似度
* @param similarity 人脸相似度
*/
public void setSimilarity(float similarity) {
this.similarity = similarity;
}
/**
* 获取活体检测结果
* @return 活体值(>0 表示活体)
*/
public float getLiveness() {
return liveness;
}
/**
* 设置活体检测结果
* @param liveness 活体值
*/
public void setLiveness(float liveness) {
this.liveness = liveness;
}
/**
* 获取年龄
* @return 年龄值
*/
public int getAge() {
return age;
}
/**
* 设置年龄
* @param age 年龄值
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取性别
* @return 性别0=未知1=男2=女)
*/
public int getGender() {
return gender;
}
/**
* 设置性别
* @param gender 性别值
*/
public void setGender(int gender) {
this.gender = gender;
}
/**
* 获取口罩佩戴状态
* @return 口罩状态(-1=未知0=未佩戴1=已佩戴)
*/
public int getMaskStatus() {
return maskStatus;
}
/**
* 设置口罩佩戴状态
* @param maskStatus 口罩状态值
*/
public void setMaskStatus(int maskStatus) {
this.maskStatus = maskStatus;
}
/**
* 获取人脸特征数据
* @return 人脸特征数据字节数组
*/
public byte[] getFeatureData() {
return featureData;
}
/**
* 设置人脸特征数据
* @param featureData 人脸特征数据
*/
public void setFeatureData(byte[] featureData) {
this.featureData = featureData;
}
/**
* 将 FaceInfo 转换为 Map 对象,用于 Flutter 端调用
* @return 包含人脸信息的 Map
*/
public Map<String, Object> toMap() {
Map<String, Object> map = new HashMap<>();
map.put("left", faceRect.left);
map.put("top", faceRect.top);
map.put("right", faceRect.right);
map.put("bottom", faceRect.bottom);
map.put("orientation", faceOrientation);
map.put("faceId", faceId);
map.put("similarity", similarity);
map.put("liveness", liveness);
map.put("age", age);
map.put("gender", gender);
map.put("maskStatus", maskStatus);
map.put("featureData", featureData != null ? featureData : new byte[0]);
return map;
}
}

Binary file not shown.

View File

@@ -0,0 +1,29 @@
package com.xiarui.arc;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import org.junit.Test;
/**
* This demonstrates a simple unit test of the Java portion of this plugin's implementation.
*
* Once you have built the plugin's example app, you can run these tests from the command
* line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
* you can run them directly from IDEs that support JUnit such as Android Studio.
*/
public class ArcPluginTest {
@Test
public void onMethodCall_getPlatformVersion_returnsExpectedValue() {
ArcPlugin plugin = new ArcPlugin();
final MethodCall call = new MethodCall("getPlatformVersion", null);
MethodChannel.Result mockResult = mock(MethodChannel.Result.class);
plugin.onMethodCall(call, mockResult);
verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE);
}
}