开发准备
最低 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 部分没有定制化的需求, 请按照如下方式添加依赖到您的 /shared/build.gradle.kts
中:
xxxxxxxxxx
...
android {
...
dependencies {
api("ai.advance.mobile-sdk.android:liveness-detection:3.4.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.4.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.4.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 是否拼了引号,回车符等等
设置人脸活体检测控件的背景颜色(请不要在 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.3 版本为例)
implementation 'ai.advance.mobile-sdk.android:core:5.3.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());