请联系我们开通账号
最低 Android 版本要求:
4.4 (API Level:19)编译 Android SDK 版本:
API Level:35额外依赖的第三方库:
无支持的 CPU 架构:
armeabi-v7a, arm64-v8aSDK 包大小:
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.4")api("androidx.appcompat:appcompat:1.6.1")api("androidx.constraintlayout:constraintlayout:2.1.4")// The default UI libraryapi(":ai.advance.mobile-sdk.android:liveness-detection-ui:3.6.4@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 仓库配置:
xxxxxxxxxxdependencyResolutionManagement {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.4")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有效性。
xxxxxxxxxxString 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 的licenseERROR_LICENSE(4,5): 解析失败,请检查 license 是否拼了引号,回车符等等设置 SignatureId(可选功能,若不设置此 id 或设置为空,则维持 livenessId 方式不变)
在已知的下述情况下,AAI 生成的 livenessId 未能传达到您的服务端,这些 livenessId 的结果就会丢失。为了解决此问题,您的后端可以调用 AAI 接口生成 SignatureId 并传给 SDK。SignatureId 可用于获取活体分数,与 livenessId 具备等效的功能。
xxxxxxxxxx1. 活体图片上传过程中,用户点击返回键离开页面2. 活体成功后,App 发生意外(如网络异常,App 异常等)未能将 livenessId 传给服务端
请注意:SignatureId 可为空,但不可重复使用
xxxxxxxxxxGuardianLivenessDetectionSDK.setSignatureId(signatureId);
设置人脸活体检测控件的背景颜色(请不要在 LivenessView 上叠加遮罩图像,如果有的话请移除)
xxxxxxxxxxmLivenessView.setMaskColor(getResources().getColor(R.color.xxx)设置人脸活体检测控件的椭圆框颜色
xxxxxxxxxxmLivenessView.setOvalColor(getResources().getColor(R.color.xxx))设置检测超时时长
xxxxxxxxxx// 可设置的输入范围为: [10000,60000] 毫秒,默认值为50000毫秒GuardianLivenessDetectionSDK.set3DLivenessTimeoutMills(50000)捕获审计图
当启用此功能时,我们将根据您的配置在用户移动过程中捕获多张图像
xxxxxxxxxxGuardianLivenessDetectionSDK.setAuditImageConfig(new AuditImageConfig .AuditImageConfigBuilder() .setEnableCollectSwitch(true)// 开启收集开关,默认值为false .setImageCaptureInterval(400)// 捕获图像的最小间隔时间,默认间隔为400毫秒 .setImageMaxNumber(10)// 最大捕获图像数量,默认数量为10 .setImageWidth(400)// 图像宽度,默认为400像素 .setImageQuality(30)// 图像压缩质量,必须在[30,100]范围内,默认值为30 .build())获取审计图
xxxxxxxxxxList<LivenessImageData> auditImageList = LivenessResult.getAuditImageList();
// 数据结构public class LivenessImageData { public final String base64Image;// Base64 格式图像 public final long timestamp;// 图像截取时间戳}视频录制功能
启用此功能后,SDK 将激活视频录制。在人脸活体检测过程完成后,您可以使用SDK方法获取视频文件。视频文件格式为.mp4。请注意,此视频只能通过 SDK 获得,无法从后端获取。使用完视频后,是否删除本地文件由您决定。
xxxxxxxxxxGuardianLivenessDetectionSDK.setRecordVideoSwitch(true)GuardianLivenessDetectionSDK.setMaxRecordVideoSeconds(60)// 最大录制时长,单位为秒,有效范围为[2,60]秒,默认为60秒。获取视频文件
xxxxxxxxxxFile videoFile = LivenessResult.getVideoFile(this)
自定义返回图像的尺寸
xxxxxxxxxx// 可设置的输入范围为: [300,1000] 像素GuardianLivenessDetectionSDK.setResultPictureSize(600)
用户绑定 (强烈建议).
您可以使用此方法将您的用户唯一标识符传递给我们,我们将根据该标识符建立映射关系。当遇到问题时,这有助于我们检查日志。
xxxxxxxxxxGuardianLivenessDetectionSDK.bindUser(String userId)
遮挡检测功能
如果您想要启用遮挡检测,请在初始化 SDK 之后调用以下方法来进行设置。
xxxxxxxxxxGuardianLivenessDetectionSDK.isDetectOcclusion(true)
启动活体检测并获取结果.
每次活体检测成功时,都将返回一个唯一的 livenessId 和一张 600*600 像素的清晰照片。
您需要将livenessId发送给您的服务器,服务器将调用openAPI来获取此次检测的得分。
您可以通过SDK提供的方法直接获取图像,或者从服务器端调用openAPI。
重要提示:每次活体检测完成后,请务必保存eventId。如果用户在使用过程中遇到任何问题,请提供eventId以便我们进行故障排查。如果没有eventId,将很难解决问题。
xxxxxxxxxxpublic 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 cameraGuardianLivenessDetectionSDK.setCameraType(CameraType.FRONT)// The back camera is CameraType.BACKstartActivityForResult(intent, REQUEST_CODE_LIVENESS)}/*** get Liveness result*/@Overrideprotected 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 purposesString eventId = LivenessResult.getEventId();File videoFile = LivenessResult.getVideoFile(this);// The video fileif (LivenessResult.isSuccess()) {// SuccessString livenessId = LivenessResult.getLivenessId();// livenessIdboolean pay = LivenessResult.isPay();// pay statusBitmap livenessBitmap = LivenessResult.getLivenessBitmap();// picture(Far)Bitmap nearBitmap = LivenessResult.getNearBitmap();// picture(Near)List<LivenessImageData> auditImageList = LivenessResult.getAuditImageList();// Audit images} else {// FailureString errorCode = LivenessResult.getErrorCode();// error codeString 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中添加以下配置来过滤掉不需要的语言:
xxxxxxxxxxandroid {defaultConfig {...resConfigs("in-rID") // 示例:仅支持印尼语,剔除其他语言资源}}
代码混淆
SDK 已经内置了 Proguard 规则,因此您不需要进行任何额外的配置。
关于 androidx
考虑到
androidx和android.support.*包之间的互斥关系,SDK 的所有.aar包都是android.support.*包。如果您的项目是androidx包,在编译时遇到android.support.*包冲突错误,请在您项目根目录的gradle.properties文件中添加以下配置,然后重新编译项目,就可以解决这个问题:
xxxxxxxxxxandroid.enableJetifier=true
bindUser方法中的 userId 应该传什么值?
能够定位到本次活体事件的字符串即可。 建议值:用户id 、用户名、设备号、交易号
IMediaPlayer.isPlayEnable()方法缺失
此方法已删除,请使用 mLivenessView.isSoundPlayEnable() 替代
报 DEVICE_NOT_SUPPORT 的原因
报 UNDEFINED 的原因
UNDEFINED 表示发生了 SDK 未预料的错误,请客户提供相关视频内容以及 userId 给我们进行排查
刚获取的 license ,SDK 提示过期怎么办?
为了减少网络请求次数,license 有效期的检验在手机端本地进行,根据手机当前时间和 license 有效期比较, 发生此类问题通常是用户的手机时间不准确所导致。 建议:
xxxxxxxxxx1. 判断用户手机时间准确性,如果用户篡改了手机时间,提示用户不要修改手机时间2. 请求 license 时,将 license 有效期设置更长些
SDK运行时会占用多少内存?
取决于相机的性能,没有具体的值,建议使用相关工具进行检测
支持。通过这个方法可以设置为后置摄像头。请注意,我们对于后置摄像头的兼容性未做充分的调优, 不建议使用后置摄像头
xxxxxxxxxxGuardianLivenessDetectionSDK.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时我们会调用如下代码:
xxxxxxxxxxString result = GuardianLivenessDetectionSDK.setLicenseAndCheck("Your license string"); 如果您的license字符串过长,可能会导致编译失败,您可以将license字符串写入文件,然后读取文件内容传入方法中。在项目的assets目录下新建一个文件,如license,将license字符串写入文件,然后在代码中读取文件内容传入方法中:
xxxxxxxxxxString 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的代码可以这样使用:
xxxxxxxxxxString result = GuardianLivenessDetectionSDK.setLicenseAndCheck(readLicenseFromAssets());