请联系我们开通账号
最低 Android 版本要求:
4.4 (API Level:19)
编译 Android SDK 版本:
API Level:35
额外依赖的第三方库:
无
支持的 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 交互方式改为近程远程检测模式,移除了动作检测,因此与动作检测相关的属性和方法将不会产生任何效果。
我们在 3.6.0 版本支持 Android 15 16 KB 的页面大小
我们建议您阅读变更日志以了解新版本 SDK 中的更新内容。
安装 CV-Demo.apk 到您的手机,使用测试账号登录
如果您想快速集成 SDK 并且对 UI 部分没有定制化的需求, 请按照如下方式添加依赖到您的 /shared/build.gradle.kts
中:
xxxxxxxxxx
...
android {
...
dependencies {
api("ai.advance.mobile-sdk.android:liveness-detection:3.6.1")
api("androidx.appcompat:appcompat:1.6.1")
api("androidx.constraintlayout:constraintlayout:2.1.4")
// The default UI library
api(":ai.advance.mobile-sdk.android:liveness-detection-ui:3.6.1@aar")
}
}
如果您需要自定义 UI,请按照以下步骤操作:
点击此链接下载 UI 源码 然后解压
将 liveness-kotlin/liveness/src/main/kotlin/ai
文件夹复制到 shared/src/androidMain/kotlin
将liveness-kotlin/liveness/src/main/res
文件夹复制到 shared/src/androidMain/
,如果 androidMain
文件夹中已经存在 res
文件夹,您需要手动合并两个 res
文件夹的内容。
将liveness-kotlin/liveness/src/main/AndroidManifest.xml
文件夹复制到shared/src/androidMain/
,如果 androidMain
文件夹中已经存在该文件,请打开现有文件并在 <application>
节点中注册 LivenessActivity
。
打开根目录中的 settings.gradle.kts
文件并添加以下 Maven 仓库配置:
xxxxxxxxxx
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url 'https://public-n3.advai.net/repository/maven-releases/' }
}
}
打开 /shared/build.gradle.kts
并添加以下依赖:
xxxxxxxxxx
...
android {
...
dependencies {
api("ai.advance.mobile-sdk.android:liveness-detection:3.6.1")
api("androidx.appcompat:appcompat:1.6.1")
api("androidx.constraintlayout:constraintlayout:2.1.4")
}
}
初始化 SDK.
建议您在 application 类中调用初始化方法
xxxxxxxxxx
// 最后一个布尔值表示是否启用全局服务,设置为 true 表示启用,false 表示不启用。
GuardianLivenessDetectionSDK.init(this,your market,false)
检查 license
license 由您的服务器调用我们的 OpenAPI 获得,在开始活体检测页面之前需要检查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 是否拼了引号,回车符等等
设置 SignatureId(可选功能,若不设置此 id 或设置为空,则维持 livenessId 方式不变)
在已知的下述情况下,AAI 生成的 livenessId 未能传达到您的服务端,这些 livenessId 的结果就会丢失。为了解决此问题,您的后端可以调用 AAI 接口生成 SignatureId 并传给 SDK。SignatureId 可用于获取活体分数,与 livenessId 具备等效的功能。
xxxxxxxxxx
1. 活体图片上传过程中,用户点击返回键离开页面
2. 活体成功后,App 发生意外(如网络异常,App 异常等)未能将 livenessId 传给服务端
请注意:SignatureId 可为空,但不可重复使用
xxxxxxxxxx
GuardianLivenessDetectionSDK.setSignatureId(signatureId);
设置人脸活体检测控件的背景颜色(请不要在 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{
/**
* requestCode
*/
public static final int REQUEST_CODE_LIVENESS = xxxx;
/**
* start Liveness Activity
*/
private void startLivenessActivity() {
Intent intent = new Intent(this, LivenessActivity.class)
// Set camera type, default is front camera
GuardianLivenessDetectionSDK.setCameraType(CameraType.FRONT)// The back camera is CameraType.BACK
startActivityForResult(intent, REQUEST_CODE_LIVENESS)
}
/**
* get Liveness result
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_LIVENESS) {
// Please make sure to save eventId for contacting us for troubleshooting purposes
String eventId = LivenessResult.getEventId();
File videoFile = LivenessResult.getVideoFile(this);// The video file
if (LivenessResult.isSuccess()) {// Success
String livenessId = LivenessResult.getLivenessId();// livenessId
boolean pay = LivenessResult.isPay();// pay status
Bitmap livenessBitmap = LivenessResult.getLivenessBitmap();// picture(Far)
Bitmap nearBitmap = LivenessResult.getNearBitmap();// picture(Near)
List<LivenessImageData> auditImageList = LivenessResult.getAuditImageList();// Audit images
} else {// Failure
String errorCode = LivenessResult.getErrorCode();// error code
String errorMsg = LivenessResult.getErrorMsg();// error message
...
}
}
}
}
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 有效期比较, 发生此类问题通常是用户的手机时间不准确所导致。 建议:
xxxxxxxxxx
1. 判断用户手机时间准确性,如果用户篡改了手机时间,提示用户不要修改手机时间
2. 请求 license 时,将 license 有效期设置更长些
SDK运行时会占用多少内存?
取决于相机的性能,没有具体的值,建议使用相关工具进行检测
支持。通过这个方法可以设置为后置摄像头。请注意,我们对于后置摄像头的兼容性未做充分的调优, 不建议使用后置摄像头
xxxxxxxxxx
GuardianLivenessDetectionSDK.setCameraType(CameraType.BACK);
AAI 会存储录制的视频吗?
AAI 不负责存储视频文件,仅支持通过 SDK 获取活体视频。 请妥善传输视频并根据业务需要自行删除手机上的视频文件
升级 3D 活体后,LivenessResult.getImageSequenceList() 方法找不到了
该方法是动作活体特有的,3D活体没有此方法。
扫描出 SDK 调用了 androidId 等设备信息的方法,如何去除?
依赖对应版本的 core 的 nd 版本即可(以 5.6 版本为例)
implementation 'ai.advance.mobile-sdk.android:core:5.6.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());