最低 Android 版本要求:
4.4 (API Level:19)
编译 Android SDK 版本:
API Level:34
额外依赖的第三方库:
无
支持的 CPU 架构:
armeabi-v7a
, arm64-v8a
SDK 包大小:
4MB+
捕获图像大小:
600px*600px
, 大小约 300KB
, 支持自定义图像大小范围: 300px~1000px
支持的语言:
必须的权限清单:
xxxxxxxxxx
<uses-feature android:name="android.hardware.camera" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
从 2022.8 开始,SDK 支持在线仓库依赖。我们建议使用在线依赖以获得更好的便利性和灵活性。
我们在1.3.9.5 版本中修复了某些 Android 12 设备上的一些潜在崩溃。如果您当前的版本低于此版本,我们建议升级到此版本以解决此问题。
我们已经解决了一些被 VirusTotal 平台检测到的问题。如果您的推广依赖于此平台的检测结果,请升级您的 SDK 版本至
从 2.0.0 版本开始,我们引入了准备阶段的椭圆虚线指引。此外,我们还升级了网络安全策略并更新了 SDK 模型。
从 3.0.0 版本开始,SDK 交互方式改为近程远程检测模式,移除了动作检测,因此与动作检测相关的属性和方法将不会产生任何效果。
我们建议您阅读变更日志以了解新版本 SDK 中的更新内容。
安装 CV-Demo.apk 到您的手机,使用测试账号登录
如果您想快速集成 SDK 并且对 UI 部分没有定制化的需求,您可以通过下面的步骤进行依赖
添加仓库
xxxxxxxxxx
maven { url 'https://public-n3.advai.net/repository/maven-releases/' }
在您项目的 gradle 中添加依赖:
xxxxxxxxxx
implementation 'ai.advance.mobile-sdk.android:liveness-detection-ui:3.4.1'
implementation 'ai.advance.mobile-sdk.android:liveness-detection:3.4.1'
活体 UI 模块我们以源码的形式交付于您,您可以结合自己项目的架构调整这部分代码,请务必再理解 UI 模块代码的前提下再做修改,以免导致程序异常执行
由于androidx
和 support
类库的不兼容,我们提供了两种类库下的源码:
如果您无法在我们的仓库中成功拉取在线的 aar,您可以点击下面的链接下载 aar 文件,手动依赖到liveness
模块中
您可以点击此链接查看 SDK 的版本记录
初始化 SDK.
建议在 application 类中初始化
xxxxxxxxxx
// 如果您开通的是 Global 活体服务,那么您需要将最后一个布尔值设置为 true,否则请设置为 false
GuardianLivenessDetectionSDK.init(application,your market,false);
设置并检查 License
您需要从您的服务端获取 license
xxxxxxxxxx
String license = "xxx";
String checkResult = GuardianLivenessDetectionSDK.setLicenseAndCheck(license);
if ("SUCCESS".equals(checkResult)) {
// license 有效
startLivenessActivity();
} else {
// license 错误, 过期/格式错误/appId 不在授权范围
}
checkResult 的返回值:
APPLICATION_ID_NOT_MATCH: 包名不在授权范围,请检查您的包名
LICENSE_EXPIRE: license过期,我们使用的手机时间比对的有效期,请确认用户校准手机时间
ERROR_LICENSE(1): license解析成功,但是缺少必要的鉴权信息,这个一般不会发生
ERROR_LICENSE(2): license解析成功,但是内部格式错误,这个一般也不会发生
ERROR_LICENSE(3): 极大可能是因为使用的不匹配的 sdk 的license,如在活体上使用 iqa 的license
ERROR_LICENSE(4,5): 解析失败,请检查 license 是否拼了引号,回车符等等
设置人脸活体检测控件的背景颜色(请不要在 LivenessView 上叠加遮罩图像,如果有的话请移除)
xxxxxxxxxx
mLivenessView.setMaskColor(getResources().getColor(R.color.xxx);
设置人脸活体检测控件的椭圆框颜色
xxxxxxxxxx
mLivenessView.setOvalColor(getResources().getColor(R.color.xxx));
设置检测超时时长
xxxxxxxxxx
// 可设置的输入范围为: [10000,60000] 毫秒,默认值为50000毫秒
GuardianLivenessDetectionSDK.set3DLivenessTimeoutMills(50000);
捕获审计图
当启用此功能时,我们将根据您的配置在用户移动过程中捕获多张图像
xxxxxxxxxx
GuardianLivenessDetectionSDK.setAuditImageConfig(new AuditImageConfig
.AuditImageConfigBuilder()
.setEnableCollectSwitch(true)// 开启收集开关,默认值为false
.setImageCaptureInterval(400)// 捕获图像的最小间隔时间,默认间隔为400毫秒
.setImageMaxNumber(10)// 最大捕获图像数量,默认数量为10
.setImageWidth(400)// 图像宽度,默认为400像素
.setImageQuality(30)// 图像压缩质量,必须在[30,100]范围内,默认值为30
.build());
获取审计图
xxxxxxxxxx
List<LivenessImageData> auditImageList = LivenessResult.getAuditImageList();
// 数据结构
public class LivenessImageData {
public final String base64Image;// Base64 格式图像
public final long timestamp;// 图像截取时间戳
}
视频录制功能
启用此功能后,SDK 将激活视频录制。在人脸活体检测过程完成后,您可以使用SDK方法获取视频文件。视频文件格式为.mp4。请注意,此视频只能通过 SDK 获得,无法从后端获取。使用完视频后,是否删除本地文件由您决定。
xxxxxxxxxx
GuardianLivenessDetectionSDK.setRecordVideoSwitch(true);
GuardianLivenessDetectionSDK.setMaxRecordVideoSeconds(60);// 最大录制时长,单位为秒,有效范围为[2,60]秒,默认为60秒。
获取视频文件
xxxxxxxxxx
File videoFile = LivenessResult.getVideoFile(this);
自定义返回图像的尺寸
xxxxxxxxxx
// 可设置的输入范围为: [300,1000] 像素
GuardianLivenessDetectionSDK.setResultPictureSize(600);
用户绑定 (强烈建议).
您可以使用此方法将您的用户唯一标识符传递给我们,我们将根据该标识符建立映射关系。当遇到问题时,这有助于我们检查日志。
xxxxxxxxxx
GuardianLivenessDetectionSDK.bindUser(String userId)
遮挡检测功能
如果您想要启用遮挡检测,请在初始化 SDK 之后调用以下方法来进行设置。
xxxxxxxxxx
GuardianLivenessDetectionSDK.isDetectOcclusion(true)
启动活体检测并获取结果
每次活体检测成功时,都将返回一个唯一的 livenessId 和一张 600*600 像素的清晰照片。
您需要将livenessId发送给您的服务器,服务器将调用openAPI来获取此次检测的得分。
您可以通过SDK提供的方法直接获取图像,或者从服务器端调用openAPI。
重要提示:每次活体检测完成后,请务必保存eventId。如果用户在使用过程中遇到任何问题,请提供eventId以便我们进行故障排查。如果没有eventId,将很难解决问题。
xxxxxxxxxx
public class SomeActivity extends Activity{
/**
* 请求码
*/
public static final int REQUEST_CODE_LIVENESS = xxxx;
/**
* 启动活体检测Activity
*/
private void startLivenessActivity() {
Intent intent = new Intent(this, LivenessActivity.class);
// 设置摄像头类型,默认为前置摄像头
GuardianLivenessDetectionSDK.setCameraType(CameraType.FRONT);// 后置摄像头为 CameraType.BACK
startActivityForResult(intent, REQUEST_CODE_LIVENESS);
}
/**
* 获取活体检测结果
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_LIVENESS) {
// 请务必保存 eventId,以便于我们进行问题排查
String eventId = LivenessResult.getEventId();
File videoFile = LivenessResult.getVideoFile(this);// 视频文件
if (LivenessResult.isSuccess()) {// 成功
String livenessId = LivenessResult.getLivenessId();// livenessId
boolean pay = LivenessResult.isPay();// 是否收费
Bitmap livenessBitmap = LivenessResult.getLivenessBitmap();// 远距离照片
Bitmap nearBitmap = LivenessResult.getNearBitmap();// 近距离照片
List<LivenessImageData> auditImageList = LivenessResult.getAuditImageList();// 审核图片列表
} else {// 失败
String errorCode = LivenessResult.getErrorCode();// 错误码
String errorMsg = LivenessResult.getErrorMsg();// 错误信息
...
}
}
}
}
errorCode | 资源 id | 描述 |
---|---|---|
ACTION_TIMEOUT | liveness_failed_reason_timeout | 检测超时 |
MULTIPLE_FACE | liveness_failed_reason_multipleface | 检测到多张人脸 |
FACE_MISSING | liveness_failed_reason_facemissing_blink_mouth | 检测过程中人脸丢失 |
MUCH_ACTION | fail_reason_much_action | 检测过程中人脸幅度过大 |
USER_GIVE_UP | 用户放弃了检测 | |
NO_RESPONSE | 网络请求失败 | |
DEVICE_NOT_SUPPORT | liveness_device_not_support | 当前设备不支持活体检测 |
UNDEFINED | 其他未定义错误 | |
AUTH_PARAMETER_ERROR | 认证错误:请确保已成功初始化 license | |
AUTH_IAM_FAILED | 认证错误:请确保已成功初始化 license | |
WEAK_LIGHT | liveness_weak_light | 光线太弱 |
STRONG_LIGHT | liveness_too_light | 光线太强 |
AUTH_BAD_NETWORK | 授权网络失败 | |
CHECKING_BAD_NETWORK | 上传图片网络失败 | |
MODEL_ERROR | 模型错误 | |
ALREADY_INIT | 重复加载 | |
NO_UPLOAD_IMAGE | 截取最佳上传图片失败 | |
AUTH_TICKET_DISABLE | Ticket过期 | |
AUTH_ACCOUNT_ACCESS_DENIED | 拒绝访问此帐户 | |
...(Other server side error codes) |
允许您在遵循以下约束的前提下,自定义 UI:
多语言
目前该SDK支持以下语言/语音:英语、印度尼西亚语、中文、越南语、印地语、泰语、墨西哥语。 会根据当前手机的语言自动切换,无需进行代码
默认语言是英语。如果与您应用程序的默认语言不一致,请手动在liveness/res
中找到与您应用程序默认语言对应的资源,并用它替换掉默认资源。
如果 SDK 没有跟随系统语言自动切换,请检查您手机的语言设置,确保[区域]和[语言]均切换到相应的语言。
如果仍然存在多语言问题,而应用程序只支持一种语言,您可以通过在build.gradle
中添加以下配置来过滤掉不需要的语言:
xxxxxxxxxx
android {
defaultConfig {
...
resConfigs("in-rID") // 示例:仅支持印尼语,剔除其他语言资源
}
}
代码混淆
SDK 已经内置了 Proguard 规则,因此您不需要进行任何额外的配置。
关于 androidx
考虑到
androidx
和android.support.*
包之间的互斥关系,SDK 的所有.aar
包都是android.support.*
包。如果您的项目是androidx
包,在编译时遇到android.support.*
包冲突错误,请在您项目根目录的gradle.properties
文件中添加以下配置,然后重新编译项目,就可以解决这个问题:
xxxxxxxxxx
android.enableJetifier=true
bindUser方法中的 userId 应该传什么值?
能够定位到本次活体事件的字符串即可。 建议值:用户id 、用户名、设备号、交易号
IMediaPlayer.isPlayEnable()方法缺失
此方法已删除,请使用 mLivenessView.isSoundPlayEnable() 替代
报 DEVICE_NOT_SUPPORT 的原因
报 UNDEFINED 的原因
UNDEFINED 表示发生了 SDK 未预料的错误,请客户提供相关视频内容以及 userId 给我们进行排查
刚获取的 license ,SDK 提示过期怎么办?
为了减少网络请求次数,license 有效期的检验在手机端本地进行,根据手机当前时间和 license 有效期比较, 发生此类问题通常是用户的手机时间不准确所导致。 建议:
SDK运行时会占用多少内存?
取决于相机的性能,没有具体的值,建议使用相关工具进行检测
支持。通过这个方法可以设置为后置摄像头。请注意,我们对于后置摄像头的兼容性未做充分的调优, 不建议使用后置摄像头
xxxxxxxxxx
GuardianLivenessDetectionSDK.setCameraType(CameraType.BACK);
AAI 会存储录制的视频吗?
AAI 不负责存储视频文件,仅支持通过 SDK 获取活体视频。 请妥善传输视频并根据业务需要自行删除手机上的视频文件
升级 3D 活体后,LivenessResult.getImageSequenceList() 方法找不到了
该方法是动作活体特有的,3D活体没有此方法。
扫描出 SDK 调用了 androidId 等设备信息的方法,如何去除?
依赖对应版本的 core 的 nd 版本即可(以 5.3 版本为例)
implementation 'ai.advance.mobile-sdk.android:core:5.5.nd'
字符串过长
检查license时我们会调用如下代码:
xxxxxxxxxx
String result = GuardianLivenessDetectionSDK.setLicenseAndCheck("Your license string");
如果您的license字符串过长,可能会导致编译失败,您可以将license字符串写入文件,然后读取文件内容传入方法中。在项目的assets
目录下新建一个文件,如license
,将license字符串写入文件,然后在代码中读取文件内容传入方法中:
xxxxxxxxxx
String readLicenseFromAssets() {
String license = null;
try {
InputStream is = getAssets().open("license");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len;
byte[] buffer = new byte[1024];
while ((len = is.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
license = baos.toString();
is.close();
} catch (Exception e) {
e.printStackTrace();
}
return license;
}
之后检查license的代码可以这样使用:
xxxxxxxxxx
String result = GuardianLivenessDetectionSDK.setLicenseAndCheck(readLicenseFromAssets());