Commit 8e82c762 authored by yinjiacheng's avatar yinjiacheng

add 活体检测逻辑

parent bb1105be
package com.yidian.shenghuoquan.newscontent.bean
/**
* author: yinjiacheng
* date: 5/31/21 11:07 PM
* description: 生活号个人认证数据集
*/
class LifeAccountPersonalAuthData {
var realName: String = ""
var idCardNum: String = ""
var idCardPortraitFaceObjectKey: String = ""
var idCardNationalEmblemFaceObjectKey: String = ""
var liveDetectBizToken: String = ""
var liveDetectObjectKey: String = ""
}
...@@ -20,6 +20,7 @@ object Constant { ...@@ -20,6 +20,7 @@ object Constant {
// 调用系统相机、打开系统相册 requestCode // 调用系统相机、打开系统相册 requestCode
const val REQUEST_CODE_OPEN_ALBUM = 101 const val REQUEST_CODE_OPEN_ALBUM = 101
const val REQUEST_CODE_OPEN_CAMERA = 102 const val REQUEST_CODE_OPEN_CAMERA = 102
// 调用旷视FaceID进行身份证采集 requestCode // 调用旷视FaceID进行身份证采集 requestCode
const val REQUEST_CODE_ID_CARD_CAPTURE = 103 const val REQUEST_CODE_ID_CARD_CAPTURE = 103
...@@ -28,8 +29,15 @@ object Constant { ...@@ -28,8 +29,15 @@ object Constant {
const val FILE_PATH_ID_CARD_NATIONAL_EMBLEM_FACE = "/ocr/id_card/national_emblem_face.jpg" const val FILE_PATH_ID_CARD_NATIONAL_EMBLEM_FACE = "/ocr/id_card/national_emblem_face.jpg"
const val FILE_PATH_BUSINESS_LICENSE_CAMERA = "/ocr/business_license_camera.jpg" const val FILE_PATH_BUSINESS_LICENSE_CAMERA = "/ocr/business_license_camera.jpg"
const val FILE_PATH_BUSINESS_LICENSE = "/ocr/business_license.jpg" const val FILE_PATH_BUSINESS_LICENSE = "/ocr/business_license.jpg"
const val FILE_PATH_ALIVE_DETECT_VERIFY_DATA = "/alive_detect/verify"
// 身份证人像面、身份证国徽面标识 // 身份证人像面、身份证国徽面标识
const val ID_CARD_PORTRAIT_FACE = 1 const val ID_CARD_PORTRAIT_FACE = 1
const val ID_CARD_NATIONAL_EMBLEM_FACE = 2 const val ID_CARD_NATIONAL_EMBLEM_FACE = 2
// 活体验证流程
const val TYPE_MEG_LIVE = "meglive" // 动作活体
const val TYPE_STILL = "still" // 静默活体
const val TYPE_FLASH = "flash" // 炫彩活体,通过打光进行活体验证,炫彩活体相较于静默活体安全性更高,但通过率会略有降低
const val TYPE_RAW_IMAGE = "raw_image" // 不进行活体验证,仅使用上传的图片进行后续的比对
} }
\ No newline at end of file
package com.yidian.shenghuoquan.newscontent.http.httpbean package com.yidian.shenghuoquan.newscontent.http.httpbean
class AuthPersonalGetTokenBean(var request: Request,val response: Response) { class AuthPersonalGetTokenBean(val request: Request,val response: Response) {
data class Request(var id_number: String, var id_card_name: String, var liveness_type: String, var biz_no: String) data class Request(val id_number: String, val id_card_name: String, val liveness_type: String)
data class Response(val biz_token: String) data class Response(val biz_token: String)
......
package com.yidian.shenghuoquan.newscontent.http.httpbean package com.yidian.shenghuoquan.newscontent.http.httpbean
class IdentifyIdOcrVerifyBean(var request: Request, val response: Response) { class IdentifyIdOcrVerifyBean(val request: Request, val response: Response) {
data class Request(var biz_token: String, var meglive_objectid: String) data class Request(val biz_token: String, val meglive_objectid: String)
data class Response(val verify_result: Boolean) data class Response(val verify_result: Boolean)
} }
......
...@@ -67,7 +67,7 @@ class AliveTestActivity : BaseActivity<ActivityAliveLayoutBinding>(), PreCallbac ...@@ -67,7 +67,7 @@ class AliveTestActivity : BaseActivity<ActivityAliveLayoutBinding>(), PreCallbac
private fun setOnListener() { private fun setOnListener() {
viewBind.btActionYy.setOnClickListener { viewBind.btActionYy.setOnClickListener {
val requestParams: AuthPersonalGetTokenBean.Request = AuthPersonalGetTokenBean.Request( val requestParams: AuthPersonalGetTokenBean.Request = AuthPersonalGetTokenBean.Request(
idCardNo!!, idCardName!!, "meglive", AppConfig.appid) idCardNo!!, idCardName!!, "meglive")
ApiService.authPersonalGetToken(authPersonalGetTokenCallback, requestParams) ApiService.authPersonalGetToken(authPersonalGetTokenCallback, requestParams)
} }
} }
......
package com.yidian.shenghuoquan.newscontent.ui.auth
import com.yidian.shenghuoquan.newscontent.bean.LifeAccountPersonalAuthData
/**
* author: yinjiacheng
* date: 6/1/21 2:02 AM
* description: 生活号认证数据管理
*/
object LifeAccountAuthDataManager {
val personalAuthData by lazy { LifeAccountPersonalAuthData() }
}
\ No newline at end of file
...@@ -4,6 +4,7 @@ import android.app.Activity ...@@ -4,6 +4,7 @@ import android.app.Activity
import android.content.ContentResolver import android.content.ContentResolver
import android.content.Intent import android.content.Intent
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.Color
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
...@@ -17,7 +18,11 @@ import com.megvii.demo.activity.IDCardDetectActivity ...@@ -17,7 +18,11 @@ import com.megvii.demo.activity.IDCardDetectActivity
import com.megvii.demo.utils.Configuration import com.megvii.demo.utils.Configuration
import com.megvii.idcardquality.IDCardQualityLicenseManager import com.megvii.idcardquality.IDCardQualityLicenseManager
import com.megvii.licensemanager.Manager import com.megvii.licensemanager.Manager
import com.megvii.meglive_sdk.listener.DetectCallback
import com.megvii.meglive_sdk.listener.PreCallback
import com.megvii.meglive_sdk.manager.MegLiveManager
import com.yidian.common.base.BaseFragment import com.yidian.common.base.BaseFragment
import com.yidian.common.http.HttpResult
import com.yidian.common.utils.YdFileUtils import com.yidian.common.utils.YdFileUtils
import com.yidian.shenghuoquan.newscontent.R import com.yidian.shenghuoquan.newscontent.R
import com.yidian.shenghuoquan.newscontent.adapter.BottomSelectAdapter import com.yidian.shenghuoquan.newscontent.adapter.BottomSelectAdapter
...@@ -25,8 +30,7 @@ import com.yidian.shenghuoquan.newscontent.bean.BottomSelectBean ...@@ -25,8 +30,7 @@ import com.yidian.shenghuoquan.newscontent.bean.BottomSelectBean
import com.yidian.shenghuoquan.newscontent.constant.Constant import com.yidian.shenghuoquan.newscontent.constant.Constant
import com.yidian.shenghuoquan.newscontent.databinding.FragmentLifeAccountIdCardAuthBinding import com.yidian.shenghuoquan.newscontent.databinding.FragmentLifeAccountIdCardAuthBinding
import com.yidian.shenghuoquan.newscontent.http.ApiService import com.yidian.shenghuoquan.newscontent.http.ApiService
import com.yidian.shenghuoquan.newscontent.http.httpbean.GetIDCardOCRBean import com.yidian.shenghuoquan.newscontent.http.httpbean.*
import com.yidian.shenghuoquan.newscontent.http.httpbean.IGetIDCardOCRCallback
import com.yidian.shenghuoquan.newscontent.ui.dialog.BottomSelectDialog import com.yidian.shenghuoquan.newscontent.ui.dialog.BottomSelectDialog
import com.yidian.shenghuoquan.newscontent.utils.BitmapUtil import com.yidian.shenghuoquan.newscontent.utils.BitmapUtil
import com.yidian.shenghuoquan.newscontent.utils.FileUtil import com.yidian.shenghuoquan.newscontent.utils.FileUtil
...@@ -42,11 +46,21 @@ import java.io.FileOutputStream ...@@ -42,11 +46,21 @@ import java.io.FileOutputStream
*/ */
class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuthBinding>(), class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuthBinding>(),
View.OnClickListener, BottomSelectAdapter.OnItemClickListener<BottomSelectBean>, View.OnClickListener, BottomSelectAdapter.OnItemClickListener<BottomSelectBean>,
IGetIDCardOCRCallback { IGetIDCardOCRCallback, AuthPersonalGetTokenCallback, IdentifyIdOcrVerifyCallback, PreCallback,
DetectCallback, KS3Core.OnKS3TaskListener {
companion object { companion object {
// 身份证采集页面回传数据 // 身份证采集页面回传数据
private const val EXTRA_NAME_ID_CARD_IMAGE = "idcardimg_bitmap" private const val EXTRA_NAME_ID_CARD_IMAGE = "idcardimg_bitmap"
// 活体检测模型文件名称
private const val FILE_NAME_ALIVE_DETECT_MODEL = "faceidmodel.bin"
//活体检测语种 详见文档
private const val ALIVE_DETECT_LANGUAGE = "zh"
//活体检测请求host 详见文档
private const val ALIVE_DETECT_HOST = "https://api.megvii.com"
} }
/** /**
...@@ -55,15 +69,19 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth ...@@ -55,15 +69,19 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth
private var curFace: Int = -1 private var curFace: Int = -1
/** /**
* 缓存身份证两面上传金山云的objectKey * sdcard/Android/data/package/cache
*/
private val cachePath by lazy { activity?.externalCacheDir?.absolutePath }
/***
* sdcard/Android/data/package/file/face_id
*/ */
private var idCardPortraitFaceObjectKey: String? = null private val fileFaceIDPath by lazy { activity?.getExternalFilesDir("face_id")?.absolutePath }
private var idCardNationalEmblemFaceObjectKey: String? = null
/** /**
* sdcard/Android/data/package/cache * 旷视活体检测
*/ */
private val commonPath by lazy { activity?.externalCacheDir?.absolutePath } private val megLiveManager by lazy { MegLiveManager.getInstance() }
override fun createViewBinding( override fun createViewBinding(
inflater: LayoutInflater, inflater: LayoutInflater,
...@@ -93,9 +111,19 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth ...@@ -93,9 +111,19 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth
* 初始化旷视FaceID * 初始化旷视FaceID
*/ */
private fun initFaceID() { private fun initFaceID() {
// 身份证采集初始化
// 竖屏采集 // 竖屏采集
Configuration.setIsVertical(activity, true) Configuration.setIsVertical(activity, true)
// 检查license是否有效
checkFaceIDLicense() checkFaceIDLicense()
// 若活体检测模型文件不存在则从assets中拷贝
if (!File(fileFaceIDPath + File.separator + FILE_NAME_ALIVE_DETECT_MODEL).exists()) {
FileUtil.copyFileFromAssets(
activity,
FILE_NAME_ALIVE_DETECT_MODEL,
fileFaceIDPath + File.separator + FILE_NAME_ALIVE_DETECT_MODEL
)
}
} }
/** /**
...@@ -156,7 +184,16 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth ...@@ -156,7 +184,16 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth
} }
} }
R.id.iv_face_auth_start -> { R.id.iv_face_auth_start -> {
// TODO: 5/27/21 跳转人脸认证 // 若存在上一次活体检测数据则删除 处理活体检测失败 再次进入
File(cachePath + Constant.FILE_PATH_ALIVE_DETECT_VERIFY_DATA).delete()
// 跳转人脸认证
ApiService.authPersonalGetToken(
this, AuthPersonalGetTokenBean.Request(
LifeAccountAuthDataManager.personalAuthData.idCardNum,
LifeAccountAuthDataManager.personalAuthData.realName,
Constant.TYPE_MEG_LIVE
)
)
} }
} }
} }
...@@ -202,9 +239,12 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth ...@@ -202,9 +239,12 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth
FileUtil.generateFileFromUri( FileUtil.generateFileFromUri(
activity, activity,
data?.data, data?.data,
commonPath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE cachePath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE
)
BitmapUtil.compressImage(
cachePath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE,
10
) )
BitmapUtil.compressImage(commonPath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE, 10)
} else { } else {
val bitmap = BitmapUtil.generateBitmapFromUri( val bitmap = BitmapUtil.generateBitmapFromUri(
activity, activity,
...@@ -215,12 +255,15 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth ...@@ -215,12 +255,15 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth
FileUtil.generateFileFromUri( FileUtil.generateFileFromUri(
activity, activity,
data?.data, data?.data,
commonPath + Constant.FILE_PATH_ID_CARD_NATIONAL_EMBLEM_FACE cachePath + Constant.FILE_PATH_ID_CARD_NATIONAL_EMBLEM_FACE
)
BitmapUtil.compressImage(
cachePath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE,
10
) )
BitmapUtil.compressImage(commonPath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE, 10)
} }
if (File(commonPath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE).exists() && File( if (File(cachePath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE).exists() && File(
commonPath + Constant.FILE_PATH_ID_CARD_NATIONAL_EMBLEM_FACE cachePath + Constant.FILE_PATH_ID_CARD_NATIONAL_EMBLEM_FACE
).exists() ).exists()
) { ) {
// 身份证两面都已选择 执行上传金山云 // 身份证两面都已选择 执行上传金山云
...@@ -240,7 +283,7 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth ...@@ -240,7 +283,7 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth
BitmapUtil.generateFileFromBitmap( BitmapUtil.generateFileFromBitmap(
bitmap, bitmap,
100, 100,
commonPath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE cachePath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE
) )
} else { } else {
val bitmap = bytes?.size?.let { val bitmap = bytes?.size?.let {
...@@ -253,11 +296,11 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth ...@@ -253,11 +296,11 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth
BitmapUtil.generateFileFromBitmap( BitmapUtil.generateFileFromBitmap(
bitmap, bitmap,
100, 100,
commonPath + Constant.FILE_PATH_ID_CARD_NATIONAL_EMBLEM_FACE cachePath + Constant.FILE_PATH_ID_CARD_NATIONAL_EMBLEM_FACE
) )
} }
if (File(commonPath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE).exists() && File( if (File(cachePath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE).exists() && File(
commonPath + Constant.FILE_PATH_ID_CARD_NATIONAL_EMBLEM_FACE cachePath + Constant.FILE_PATH_ID_CARD_NATIONAL_EMBLEM_FACE
).exists() ).exists()
) { ) {
// 身份证两面都已选择 执行上传金山云 // 身份证两面都已选择 执行上传金山云
...@@ -274,7 +317,7 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth ...@@ -274,7 +317,7 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth
*/ */
private fun startUpload() { private fun startUpload() {
KS3Core.INSTANCE.uploadObject( KS3Core.INSTANCE.uploadObject(
File(commonPath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE), File(cachePath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE),
KS3Core.ObjectType.IMAGE, object : KS3Core.OnKS3TaskListener { KS3Core.ObjectType.IMAGE, object : KS3Core.OnKS3TaskListener {
override fun onTaskStart() { override fun onTaskStart() {
...@@ -293,9 +336,12 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth ...@@ -293,9 +336,12 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth
} }
override fun onTaskSuccess(bucket: String?, objectKey: String?) { override fun onTaskSuccess(bucket: String?, objectKey: String?) {
idCardPortraitFaceObjectKey = objectKey objectKey?.let {
LifeAccountAuthDataManager.personalAuthData.idCardPortraitFaceObjectKey =
it
}
KS3Core.INSTANCE.uploadObject( KS3Core.INSTANCE.uploadObject(
File(commonPath + Constant.FILE_PATH_ID_CARD_NATIONAL_EMBLEM_FACE), File(cachePath + Constant.FILE_PATH_ID_CARD_NATIONAL_EMBLEM_FACE),
KS3Core.ObjectType.IMAGE, object : KS3Core.OnKS3TaskListener { KS3Core.ObjectType.IMAGE, object : KS3Core.OnKS3TaskListener {
override fun onTaskStart() { override fun onTaskStart() {
...@@ -314,12 +360,18 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth ...@@ -314,12 +360,18 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth
} }
override fun onTaskSuccess(bucket: String?, objectKey: String?) { override fun onTaskSuccess(bucket: String?, objectKey: String?) {
idCardNationalEmblemFaceObjectKey = objectKey objectKey?.let {
LifeAccountAuthDataManager.personalAuthData.idCardNationalEmblemFaceObjectKey =
it
}
startIDCardOCR() startIDCardOCR()
} }
override fun onTaskFailure(statesCode: Int, message: String?) { override fun onTaskFailure(statesCode: Int, message: String?) {
Log.e(
Constant.LIFE_ACCOUNT_AUTH_TAG,
"upload ID card portrait face failure, message: $message"
)
} }
} }
...@@ -327,7 +379,10 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth ...@@ -327,7 +379,10 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth
} }
override fun onTaskFailure(statesCode: Int, message: String?) { override fun onTaskFailure(statesCode: Int, message: String?) {
Log.e(
Constant.LIFE_ACCOUNT_AUTH_TAG,
"upload ID card national emblem face failure, message: $message"
)
} }
} }
) )
...@@ -339,17 +394,27 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth ...@@ -339,17 +394,27 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth
private fun startIDCardOCR() { private fun startIDCardOCR() {
ApiService.getIDCardOCR( ApiService.getIDCardOCR(
this, this,
GetIDCardOCRBean.Request(idCardPortraitFaceObjectKey, idCardNationalEmblemFaceObjectKey) GetIDCardOCRBean.Request(
LifeAccountAuthDataManager.personalAuthData.idCardPortraitFaceObjectKey,
LifeAccountAuthDataManager.personalAuthData.idCardNationalEmblemFaceObjectKey
)
) )
} }
override fun getIDCardOCRSuccess(result: GetIDCardOCRBean.Response?) { override fun getIDCardOCRSuccess(result: GetIDCardOCRBean.Response?) {
// 存储认证使用的信息
result?.posit?.name?.let {
LifeAccountAuthDataManager.personalAuthData.realName = it
}
result?.posit?.idcard_number?.let {
LifeAccountAuthDataManager.personalAuthData.idCardNum = it
}
// 回显OCR结果 // 回显OCR结果
viewBinding.evRealName.fillEditContent(result?.posit?.name) viewBinding.evRealName.fillEditContent(result?.posit?.name)
viewBinding.evIdCardNumber.fillEditContent(result?.posit?.idcard_number) viewBinding.evIdCardNumber.fillEditContent(result?.posit?.idcard_number)
// 此时身份证两面均已上传并OCR识别完成 删除本地临时存储文件 // 此时身份证两面均已上传并OCR识别完成 删除本地临时存储文件
File(commonPath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE).delete() File(cachePath + Constant.FILE_PATH_ID_CARD_PORTRAIT_FACE).delete()
File(commonPath + Constant.FILE_PATH_ID_CARD_NATIONAL_EMBLEM_FACE).delete() File(cachePath + Constant.FILE_PATH_ID_CARD_NATIONAL_EMBLEM_FACE).delete()
} }
override fun getIDCardOCRFailure(message: String?) { override fun getIDCardOCRFailure(message: String?) {
...@@ -359,6 +424,132 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth ...@@ -359,6 +424,132 @@ class LifeAccountIDCardAuthFragment : BaseFragment<FragmentLifeAccountIdCardAuth
) )
} }
override fun getTokenSuccess(t: HttpResult<AuthPersonalGetTokenBean.Response?>?) {
t?.result?.biz_token?.let {
LifeAccountAuthDataManager.personalAuthData.liveDetectBizToken = it
}
megLiveManager.preDetect(
activity,
t?.result?.biz_token,
ALIVE_DETECT_LANGUAGE,
ALIVE_DETECT_HOST,
fileFaceIDPath + File.separator + FILE_NAME_ALIVE_DETECT_MODEL,
this
)
}
override fun identifyIdOcrVerifySuccess(t: HttpResult<IdentifyIdOcrVerifyBean.Response?>?) {
if (t?.result?.verify_result == true) {
Log.i(Constant.LIFE_ACCOUNT_AUTH_TAG, "live detect success")
// 人脸验证通过UI
changeFaceAuthUI(true)
// 删除活体检测数据
File(cachePath + Constant.FILE_PATH_ALIVE_DETECT_VERIFY_DATA).delete()
}
}
override fun identifyIdOcrVerifyFailure(t: HttpResult<IdentifyIdOcrVerifyBean.Response?>?) {
Log.e(Constant.LIFE_ACCOUNT_AUTH_TAG, "live detect failure, message: ${t?.reason}")
// 人脸验证未通过UI
changeFaceAuthUI(false)
}
override fun onPreStart() {
// TODO: 6/1/21 show progress
}
override fun onPreFinish(token: String?, errorCode: Int, errorMessage: String?) {
// 只有当完成预处理且errorCode==1000的时候才可以调用startDetect开启活体检测
if (errorCode == 1000) {
megLiveManager.setVerticalDetectionType(MegLiveManager.DETECT_VERITICAL_FRONT)
megLiveManager.startDetect(this)
} else {
Log.e(
Constant.LIFE_ACCOUNT_AUTH_TAG,
"alive detect pre detect failure, errorCode: $errorCode, errorMessage: $errorMessage"
)
}
}
override fun onDetectFinish(
token: String?,
errorCode: Int,
errorMessage: String?,
data: String?
) {
if (errorCode == 1000) {
// 保存活体加密数据 上传金山云
FileUtil.generateFileFromString(
data,
cachePath + Constant.FILE_PATH_ALIVE_DETECT_VERIFY_DATA
)
KS3Core.INSTANCE.uploadObject(
cachePath + Constant.FILE_PATH_ALIVE_DETECT_VERIFY_DATA,
this
)
} else {
Log.e(
Constant.LIFE_ACCOUNT_AUTH_TAG,
"alive detect detect failure, errorCode: $errorCode, errorMessage: $errorMessage"
)
changeFaceAuthUI(false)
}
}
override fun onTaskStart() {
}
override fun onTaskProgress(progress: Double) {
}
override fun onTaskFinish() {
}
override fun onTaskCancel() {
}
override fun onTaskSuccess(bucket: String?, objectKey: String?) {
objectKey?.let {
LifeAccountAuthDataManager.personalAuthData.liveDetectObjectKey = it
}
ApiService.identifyIdOcrVerify(
this,
IdentifyIdOcrVerifyBean.Request(
LifeAccountAuthDataManager.personalAuthData.liveDetectBizToken,
LifeAccountAuthDataManager.personalAuthData.liveDetectObjectKey
)
)
}
override fun onTaskFailure(statesCode: Int, message: String?) {
Log.e(
Constant.LIFE_ACCOUNT_AUTH_TAG,
"upload alive detect verify data failure, message: $message"
)
}
/**
* 人脸验证结果UI
* @param result true为验证通过 false为验证未通过
*/
private fun changeFaceAuthUI(result: Boolean) {
if (result) {
viewBinding.tvFaceAuthResult.text = activity?.getText(R.string.face_auth_success)
viewBinding.tvFaceAuthResult.setTextColor(Color.parseColor("#FF6BB81F"))
viewBinding.ivFaceAuthStart.visibility = View.GONE
viewBinding.tvFaceAuthErrorTips.visibility = View.GONE
} else {
viewBinding.tvFaceAuthResult.text = activity?.getText(R.string.face_auth_fail)
viewBinding.tvFaceAuthResult.setTextColor(Color.parseColor("#FFFF3A3A"))
viewBinding.tvFaceAuthErrorTips.visibility = View.VISIBLE
viewBinding.tvFaceAuthErrorTips.text = activity?.getText(R.string.face_auth_error_tips)
}
}
/** /**
* 通过Uri获取文件全路径 * 通过Uri获取文件全路径
* 适配Android Q * 适配Android Q
......
...@@ -2,6 +2,7 @@ package com.yidian.shenghuoquan.newscontent.utils ...@@ -2,6 +2,7 @@ package com.yidian.shenghuoquan.newscontent.utils
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
/** /**
...@@ -21,4 +22,31 @@ object FileUtil { ...@@ -21,4 +22,31 @@ object FileUtil {
context?.contentResolver?.openInputStream(uri)?.copyTo(FileOutputStream(path)) context?.contentResolver?.openInputStream(uri)?.copyTo(FileOutputStream(path))
} }
} }
/**
* 从assets中复制文件到指定路径
* @param assetFileName assets中文件名
* @param destPath 目标路径
*/
fun copyFileFromAssets(context: Context?, assetFileName: String, destPath: String) {
val file = File(destPath)
if (file.exists()) file.delete()
file.parentFile?.mkdirs()
file.createNewFile()
context?.assets?.open(assetFileName)?.copyTo(FileOutputStream(file))
}
/**
* 从String生成File
* @param data 待写入的String
* @param destPath 目标路径
*/
fun generateFileFromString(data: String?, destPath: String) {
if (data.isNullOrEmpty()) return
val file = File(destPath)
if (file.exists()) file.delete()
file.parentFile?.mkdirs()
file.createNewFile()
File(destPath).writeText(data)
}
} }
\ No newline at end of file
...@@ -99,7 +99,9 @@ ...@@ -99,7 +99,9 @@
<string name="check_id_card_number">请核对证件号码</string> <string name="check_id_card_number">请核对证件号码</string>
<string name="face_auth">人脸验证</string> <string name="face_auth">人脸验证</string>
<string name="start_face_auth">去验证</string> <string name="start_face_auth">去验证</string>
<string name="face_auth_fail">人脸识别失败,请重新识别</string> <string name="face_auth_success">验证通过</string>
<string name="face_auth_fail">验证未通过</string>
<string name="face_auth_error_tips">人脸识别失败,请重新识别</string>
<string name="agree">我同意</string> <string name="agree">我同意</string>
<string name="privacy_certification">《隐私认证》</string> <string name="privacy_certification">《隐私认证》</string>
<string name="user_agreement">《用户协议》</string> <string name="user_agreement">《用户协议》</string>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment