Giới thiệu
Bài viết hướng dẫn cách kiểm tra thiết bị có phần cứng cảm biến vân tay (fingerprint sensor) và đã đăng ký vân tay hay không, sử dụng FingerprintManager (API 23-28) và BiometricManager (API 29+ - khuyến nghị).
Các bước thực hiện
Bước 1: Tạo project mới
Android Studio → File → New Project → Empty Activity.
Bước 2: Thêm dependency Biometric (Khuyến nghị)
dependencies {
// Biometric API thống nhất (API 23+)
implementation "androidx.biometric:biometric:1.1.0"
// Hoặc mới nhất
implementation "androidx.biometric:biometric-ktx:1.2.0-alpha04"
}
Bước 3: Khai báo quyền (AndroidManifest.xml)
<uses-permission android:name="android.permission.USE_BIOMETRIC" /> <!-- Cũ: USE_FINGERPRINT (deprecated API 28) -->
Bước 4: Giao diện (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp">
<TextView
android:id="@+id/tvFingerprintStatus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Checking fingerprint..."
android:textSize="18sp"
android:lineSpacingExtra="8dp" />
<Button
android:id="@+id/btnAuthenticate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="Xác thực vân tay / Mặt" />
</LinearLayout>
Bước 5: Code hiện đại - BiometricManager (API 29+ / AndroidX Biometric)
package com.example.fingerprintcheck
import android.content.Context
import android.hardware.biometrics.BiometricManager
import android.os.Build
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
private lateinit var biometricPrompt: BiometricPrompt
private lateinit var promptInfo: BiometricPrompt.PromptInfo
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
checkFingerprintHardware()
setupBiometricPrompt()
btnAuthenticate.setOnClickListener {
biometricPrompt.authenticate(promptInfo)
}
}
private fun checkFingerprintHardware() {
val biometricManager = BiometricManager.from(this)
val authResult = biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)
val message = when (authResult) {
BiometricManager.BIOMETRIC_SUCCESS -> {
"✅ Thiết bị CÓ cảm biến vân tay/mặt VÀ đã đăng ký ít nhất 1 lần"
}
BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> {
"❌ Thiết bị KHÔNG CÓ cảm biến sinh trắc học"
}
BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> {
"⚠️ Có cảm biến nhưng KHÔNG KHẢ DỤNG tạm thời (đang dùng by other process)"
}
BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> {
"⚠️ Có cảm biến nhưng CHƯA ĐĂNG KÝ vân tay/mặt nào"
}
BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> {
"🔒 Cần cập nhật bảo mật để dùng sinh trắc học"
}
BiometricManager.BIOMETRIC_ERROR_UNABLE_TO_PROCESS -> {
"❌ Không thể xử lý yêu cầu sinh trắc học"
}
BiometricManager.BIOMETRIC_ERROR_TIMEOUT -> {
"⏰ Timeout khi kiểm tra"
}
else -> "Trạng thái không xác định: $authResult"
}
tvFingerprintStatus.text = message
}
private fun setupBiometricPrompt() {
val executor = ContextCompat.getMainExecutor(this)
biometricPrompt = BiometricPrompt(this, executor, object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
super.onAuthenticationSucceeded(result)
runOnUiThread {
Toast.makeText(this@MainActivity, "✅ Xác thực thành công!", Toast.LENGTH_SHORT).show()
tvFingerprintStatus.text = "Xác thực thành công!"
}
}
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
runOnUiThread {
Toast.makeText(this@MainActivity, "❌ Lỗi: $errString", Toast.LENGTH_SHORT).show()
}
}
override fun onAuthenticationFailed() {
super.onAuthenticationFailed()
runOnUiThread {
Toast.makeText(this@MainActivity, "❌ Xác thực thất bại", Toast.LENGTH_SHORT).show()
}
}
})
promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Xác thực sinh trắc học")
.setSubtitle("Đặt ngón tay hoặc nhìn vào màn hình")
.setNegativeButtonText("Hủy")
.setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG)
.build()
}
}
Cách cũ: FingerprintManager (API 23-28, Deprecated)
// Chỉ dùng cho maintenance legacy code
val fingerprintManager = getSystemService(FingerprintManager::class.java)
val hasHardware = fingerprintManager.isHardwareDetected
val hasEnrolled = fingerprintManager.hasEnrolledFingerprints
if (hasHardware && hasEnrolled) {
// Có thể dùng FingerprintManager.CryptoObject + Cipher để encrypt/decrypt
}
So sánh: FingerprintManager vs BiometricManager
| Đặc điểm | FingerprintManager (Cũ) | BiometricManager / BiometricPrompt (Mới) |
|---|---|---|
| API Level | 23 (Marshmallow) | 29 (Q) / AndroidX backport to 23 |
| Loại sinh trắc học | Chỉ vân tay | Vân tay, Mặt (Face), Mống mắt (Iris) |
| UI Dialog | Tự build | Hệ thống cung cấp (consistent) |
| Crypto integration | Manual (Cipher) | Built-in (CryptoObject) |
| Trạng thái | Deprecated API 28 | ✅ Khuyến nghị |
Lưu ý quan trọng
- USE_BIOMETRIC permission cần thiết từ Android 10 (API 29).
- BIOMETRIC_STRONG: Class 3 (fingerprint, face 3D). BIOMETRIC_WEAK: Class 2 (face 2D).
- Emulator: Extended Controls → Fingerprint → Enroll fingerprint để test.
- Không lưu trữ dữ liệu vân tay gốc - chỉ lưu template mã hóa trong TEE/Keystore.
- Test trên thiết bị thật để kết quả chính xác.