第 1 步:在 build.gradle 文件中添加最新的生物识别依赖项。
implementation 'androidx.biometric:biometric:1.0.1'
第 2 步:在 AndroidManifest.xml 文件中添加生物识别权限。
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
第3步:创建activity_login.xml文件并定义触控 ID 按钮的 UI。
activity_login.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:id="@+id/parent_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="30dp">
<Button
android:id="@+id/touch_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/river_blue"
android:stateListAnimator="@null"
android:text="Biometric Login"
android:textAllCaps="false"
android:textColor="@color/white"
android:textSize="16sp" />
</RelativeLayout>
</layout>
第 4 步:创建 LoginActivity.java文件以实现生物识别登录功能。
登录活动.java:
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.biometric.BiometricPrompt;
import androidx.core.content.ContextCompat;
import android.os.Build;
import android.os.Bundle;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.widget.Button;
import androidx.biometric.BiometricManager;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
/**
* Created by: rajoo.kannaujiya on 02/16/2020
*/
@RequiresApi(api = Build.VERSION_CODES.P)
public class LoginActivity extends AppCompatActivity {
private static final String KEY_NAME = "KeyName";
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";
private static final String FORWARD_SLASH = "/";
private Button touchButton;
@RequiresApi(api = Build.VERSION_CODES.P)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
touchButton = findViewById(R.id.touch_button);
touchButton.setOnClickListener((view) -> onTouchIdClick());
displayBiometricButton();
}
private void onTouchIdClick() {
getBiometricPromptHandler().authenticate(getBiometricPrompt(), new BiometricPrompt.CryptoObject(getCipher()));
// Please see the below mentioned note section.
// getBiometricPromptHandler().authenticate(getBiometricPrompt());
}
private boolean isBiometricCompatibleDevice() {
if (getBiometricManager().canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS) {
return true;
} else {
return false;
}
}
private void displayBiometricButton() {
if (isBiometricCompatibleDevice()) {
touchButton.setEnabled(false);
} else {
touchButton.setEnabled(true);
generateSecretKey();
}
}
private BiometricManager getBiometricManager() {
return BiometricManager.from(this);
}
private void generateSecretKey() {
KeyGenerator keyGenerator = null;
KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(
KEY_NAME, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.setUserAuthenticationRequired(true)
.setInvalidatedByBiometricEnrollment(false)
.build();
try {
keyGenerator = KeyGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE);
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
e.printStackTrace();
}
if (keyGenerator != null) {
try {
keyGenerator.init(keyGenParameterSpec);
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
keyGenerator.generateKey();
}
}
private SecretKey getSecretKey() {
KeyStore keyStore = null;
Key secretKey = null;
try {
keyStore = KeyStore.getInstance(ANDROID_KEY_STORE);
} catch (KeyStoreException e) {
e.printStackTrace();
}
if (keyStore != null) {
try {
keyStore.load(null);
} catch (CertificateException | IOException | NoSuchAlgorithmException e) {
e.printStackTrace();
}
try {
secretKey = keyStore.getKey(KEY_NAME, null);
} catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
e.printStackTrace();
}
}
return (SecretKey) secretKey;
}
private Cipher getCipher() {
Cipher cipher = null;
try {
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + FORWARD_SLASH
+ KeyProperties.BLOCK_MODE_CBC + FORWARD_SLASH
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
try {
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey());
} catch (InvalidKeyException e) {
e.printStackTrace();
}
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
e.printStackTrace();
}
return cipher;
}
private BiometricPrompt.PromptInfo getBiometricPrompt() {
return new BiometricPrompt.PromptInfo.Builder()
.setTitle("Biometric login for my app")
.setSubtitle("Login with your biometric credential")
.setNegativeButtonText("cancel")
.setConfirmationRequired(false)
.build();
}
private void onBiometricSuccess() {
//Call the respective API on biometric success
callLoginApi("userName", "password");
}
private BiometricPrompt getBiometricPromptHandler() {
return new BiometricPrompt(this, ContextCompat.getMainExecutor(this),
new BiometricPrompt.AuthenticationCallback() {
@Override
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
super.onAuthenticationError(errorCode, errString);
}
@Override
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
onBiometricSuccess();
}
@Override
public void onAuthenticationFailed() {
super.onAuthenticationFailed();
}
}
);
}
}
注意:生物识别传感器(指纹、面部、虹膜)的身份验证级别分为强和弱。根据 Android 兼容性定义文档 (Android CDD),要访问 Android 密钥存储,生物识别传感器的身份验证级别必须分类为“强”。由于面部和虹膜传感器在某些设备中被归类为弱类别,因此在这些设备中,面部和虹膜选项将不会显示在使用CryptoObject进行身份验证的生物识别提示中。
getBiometricPromptHandler().authenticate(getBiometricPrompt(), new BiometricPrompt.CryptoObject(getCipher()));
如果您在没有CryptoObject的情况下对生物识别提示进行身份验证,则将显示它。
getBiometricPromptHandler().authenticate(getBiometricPrompt());