Hướng dẫn tích hợp Flash Liveness SDK cho Android
Phiên bản SDK hiện tại: 1.7.23.
Tài liệu này dành cho ứng dụng Android native Kotlin/Java tích hợp trực tiếp io.liveness.flash:sdk-android.
1. Yêu cầu
| Hạng mục | Yêu cầu |
|---|---|
| Android SDK | minSdk 24, compileSdk 34 khuyến nghị |
| Java/Kotlin target | Java 17/Kotlin JVM target 17 khuyến nghị |
| Package access | Có quyền đọc GitHub Packages của eidasvn/flash-liveness-android |
| Thiết bị test | Thiết bị thật có camera |
2. Cấu hình repository
Thêm GitHub Packages repository vào settings.gradle hoặc root build.gradle:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
maven {
url = uri("https://maven.pkg.github.com/eidasvn/flash-liveness-android")
credentials {
username = "GITHUB_USERNAME"
password = "GITHUB_PERSONAL_ACCESS_TOKEN"
}
}
}
}
Token cần có quyền read:packages và quyền truy cập repository private.
3. Thêm dependency
Trong build.gradle của module app:
dependencies {
implementation("io.liveness.flash:sdk-android:1.7.23")
implementation("com.google.mlkit:face-detection:16.1.7")
}
SDK đã khai báo transitive dependencies cho CameraX và TensorFlow Lite. App host chỉ cần khai báo thêm dependency ngoài khi dự án có conflict version cụ thể.
4. Khai báo quyền
Trong AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
Trước khi gọi SDK, app nên request runtime permission CAMERA. Nếu người dùng từ chối quyền, không start SDK; hãy hiển thị hướng dẫn mở quyền trong Settings.
5. ProGuard/R8
Nếu bật minify, thêm rule:
-keep class com.liveness.sdk.corev4.model.** { *; }
-keep interface com.liveness.sdk.corev4.utils.CallbackLivenessListener { *; }
6. Khởi tạo cấu hình
SDK dùng LivenessRequest để nhận thông tin tích hợp và cấu hình UI:
val livenessRequest = LivenessRequest(
baseURL = "https://your-api-domain.com",
appId = "YOUR_APP_ID",
secret = "YOUR_SECRET",
privateKey = "YOUR_RSA_PRIVATE_KEY",
publicKey = "YOUR_RSA_PUBLIC_KEY",
verifyLevel = VerifyLevel.MEDIUM,
isDebug = BuildConfig.DEBUG,
faceMatchNoteDisplayMode = FaceMatchNoteDisplayMode.SHOW_ONCE,
imageResizeConfig = ImageResizeConfig(
maxDimension = 1024,
compression = 95
)
)
LiveNessSDK.setConfigSDK(this, livenessRequest)
faceMatchNoteDisplayMode hỗ trợ:
| Giá trị | Ý nghĩa |
|---|---|
HIDDEN | Không hiển thị note trước khi scan |
SHOW_ONCE | Chỉ hiển thị lần đầu trên thiết bị |
ALWAYS | Luôn hiển thị trước mỗi lần scan |
7. Tùy biến ảnh và giao diện
ImageResizeConfig áp dụng cho ảnh gửi lên API verify liveness và ảnh trả về callback/result.
| Thuộc tính | Kiểu | Giá trị khuyến nghị |
|---|---|---|
maxDimension | Int | 1024; SDK giới hạn hợp lệ trong khoảng 1..4096 |
compression | Int | 90..95; SDK giới hạn hợp lệ trong khoảng 0..100 |
Ví dụ tùy biến overlay và note:
val maskConfig = FaceMatchMaskConfig(
maskBackgroundColor = "#66000000",
ovalStrokeColor = "#00A7FF",
textBackgroundColor = "#00A7FF",
textColor = "#FFFFFFFF",
instructionMessageMap = mapOf(
0 to "Khuôn mặt hợp lệ",
7 to "Không tìm thấy khuôn mặt",
10 to "Giữ yên khuôn mặt",
14 to "Phát hiện nhiều khuôn mặt"
)
)
val noteConfig = FaceMatchNoteConfig(
textColor = "#1F2937",
buttonTextColor = "#FFFFFF",
buttonBackgroundColor = "#00A7FF",
titleText = "Lưu ý",
messageText = "Vui lòng giữ điện thoại ngang tầm mắt để khuôn mặt nằm trọn trong khung hình.",
environmentTitleText = "Môi trường",
environmentDescriptionText = "Đủ ánh sáng",
sunglassesTitleText = "Không",
sunglassesDescriptionText = "Đeo kính râm",
maskTitleText = "Không",
maskDescriptionText = "Đeo khẩu trang",
buttonTitleText = "Đã hiểu"
)
Truyền các config này vào LivenessRequest qua faceMatchMaskConfig, faceMatchNoteConfig và faceMatchInstructionTopInset nếu cần chỉnh vị trí text hướng dẫn.
8. Thực hiện live check
8.1 Mở bằng Activity
Phù hợp khi muốn SDK tự mở màn hình FaceMatchActivity.
LiveNessSDK.startLiveNess(
context = this@MainActivity,
mLivenessRequest = livenessRequest,
livenessListener = object : CallbackLivenessListener {
override fun onStart() {
// SDK bắt đầu camera/session liveness.
}
override fun onResultsLiveness(action: String?) {
// Action/hướng dẫn trung gian trong quá trình liveness.
}
override fun onCallbackLiveness(data: LivenessModel?) {
handleLivenessResult(data)
}
}
)
Không dùng applicationContext cho flow này vì SDK cần Activity để mở UI và xử lý back stack.
8.2 Nhúng bằng Fragment
LiveNessSDK.startLiveNess(
context = this,
mLivenessRequest = livenessRequest,
supportFragmentManager = supportFragmentManager,
container = R.id.fragment_container,
livenessListener = listener
)
8.3 Nhúng bằng LivenessFrameLayout
Phù hợp khi app muốn chủ động quản lý pause(), resume(), stop() và release().
private var livenessView: LivenessFrameLayout? = null
private fun openLiveness() {
livenessView = LivenessFrameLayout(this).apply {
attachAndStart(
activity = this@MainActivity,
container = findViewById(R.id.frame_view_main),
mLivenessRequest = livenessRequest,
livenessListener = listener
)
}
}
override fun onPause() {
livenessView?.pause()
super.onPause()
}
override fun onResume() {
super.onResume()
livenessView?.resume()
}
override fun onDestroy() {
livenessView?.release()
livenessView = null
super.onDestroy()
}
Nếu tự xử lý nút back trong Activity nhúng view, forward back event vào SDK:
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (livenessView?.handleBackPressed() == true) return
finish()
}
})
Khi back được xử lý bởi SDK, callback trả về status = LivenessFrameLayout.STATUS_BACK_PRESSED.
9. Xử lý callback
Nên ưu tiên đọc callback theo thứ tự:
| Field | Ý nghĩa |
|---|---|
sdkErrorCode | Mã lỗi nội bộ ổn định để app xử lý logic |
status | HTTP status hoặc trạng thái flow |
message | Thông điệp hiển thị/log |
Ví dụ:
private fun handleLivenessResult(data: LivenessModel?) {
when (data?.sdkErrorCode) {
null -> {
// Không có lỗi SDK nội bộ, kiểm tra status/success theo payload backend.
}
"BACK_PRESSED" -> {
// Người dùng bấm back.
}
"PERMISSION_DENIED" -> {
// Thiếu quyền camera.
}
else -> {
// Log và hiển thị thông báo phù hợp.
}
}
}
Một số sdkErrorCode thường gặp:
COMPROMISED_ENVIRONMENTSDK_NOT_INITIALIZEDINVALID_INPUTEMPTY_RESPONSETOTP_ERRORPERMISSION_DENIEDDATA_CONFIG_FAILVERIFY_FAILEDBACK_PRESSED
10. Register face
Nếu flow cần đăng ký khuôn mặt:
LiveNessSDK.registerFace(
context = this,
mLivenessRequest = livenessRequest,
livenessListener = listener
)
11. Tiện ích
| Hàm | Mục đích |
|---|---|
LiveNessSDK.checkVersion() | Trả về version SDK hiện tại |
LiveNessSDK.isRegisterFace(context) | Kiểm tra thiết bị/người dùng đã đăng ký mặt chưa |
LiveNessSDK.getDeviceId(context) | Lấy device ID SDK đang dùng |
LiveNessSDK.clearAllData(context) | Xóa cache/config SDK |
12. Checklist trước production
- Tắt
isDebughoặc giảm log level. - Kiểm tra credential GitHub Packages không nằm trong source public.
- Kiểm thử permission denied, back pressed, network timeout, verify failed.
- Kiểm thử trên nhiều thiết bị thật, đặc biệt thiết bị camera yếu hoặc ánh sáng thấp.