在开始之前,我们需要知道使用指纹识别硬件的基本步骤:
1.在AndroidManifest.xml中申明如下权限:
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
2.获得FingerprintManager的对象引用
3.在运行是检查设备指纹识别的兼容性,比如是否有指纹识别设备等。下面我们详细说一下上面的步骤:
申明权限
这一步比较简单,只要在AndroidManifest.xml中添加上面说到的权限就可以了。
获得FingerprintManager对象引用
这是app开发中获得系统服务对象的常用方式,如下:
// Using the Android Support Library v4
fingerprintManager = FingerprintManagerCompat.from(this);
// Using API level 23:
fingerprintManager = (FingerprintManager)getSystemService(Context.FINGERPRINT_SERVICE);
上面给出两种方式,第一种是通过V4支持包获得兼容的对象引用,这是google推行的做法;还有就是直接使用api 23 framework中的接口获得对象引用。
之后就可以直接使用,或者是考虑加密后再使用。因为这里主要是讲解如何使用,方便上手操作,详细的就不多说了,注释里见!
下面直接给出使用时的demo。
因为我们使用的时候主要是用到开启指纹的识别,识别后成功、失败回调的方法。
多于的东西自行了解,多多益善。
我这里才用的是对称加密,其实不加密也可以运行。
package com.zq.sensoradapter;
import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
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;
public class FingerActivity extends AppCompatActivity {
public static final String TAG = "Finger";
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fingerprint);
Button button = findViewById(R.id.sure_btn);
//点击开始识别
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
createKey();
checkFinger();
}
});
}
/**
* 检查是否支持指纹识别
* 若支持则开启指纹识别
*/
@RequiresApi(api = Build.VERSION_CODES.M)
private void checkFinger(){
FingerprintManager fingerprintManager = getFingerprintManager(this);//获取指纹识别管理器
if (fingerprintManager == null){
Toast.makeText(this,"此设备无法指纹识别",Toast.LENGTH_LONG);
}else {
sureFinger(fingerprintManager);
}
}
/**
* 获取指纹识别管理器
* @param context
* @return
*/
public static FingerprintManager getFingerprintManager(Context context) {
FingerprintManager fingerprintManager = null;
try {
fingerprintManager = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
} catch (Throwable e) {
Log.e(TAG,"have not class FingerprintManager");
}
return fingerprintManager;
}
/**
* 开始指纹识别
*/
@RequiresApi(api = Build.VERSION_CODES.M)
private void sureFinger(FingerprintManager fingerprintManager){
//第一个参数是一个加密对象。这里的 CryptoObject 对象就是使用 Cipher 对象创建创建出来的:new FingerprintManager.CryptoObject(cipher)。
//第二个参数是一个 CancellationSignal 对象,该对象提供了取消操作的能力。创建该对象也很简单,使用 new CancellationSignal() 就可以了。
//第三个参数是一个标志,默认为0。
//第四个参数是 AuthenticationCallback 对象,它本身是 FingerprintManager 类里面的一个抽象类。该类提供了指纹识别的几个回调方法,包括指纹识别成功、失败等。需要我们重写。
//最后一个 Handler,可以用于处理回调事件,可以传null。
fingerprintManager.authenticate(new FingerprintManager.CryptoObject(defaultCipher),
new CancellationSignal(), 0, new FingerprintManager.AuthenticationCallback() {
//连续识别错误后,识别时调用的方法,一般持续30s-60s。
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
super.onAuthenticationError(errorCode, errString);
Log.e(TAG,errorCode +"onAuthenticationError 识别错误:" + errString);
}
//告诉你除开识别失败后的错误信息
@Override
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
super.onAuthenticationHelp(helpCode, helpString);
Log.e(TAG,helpCode + ":onAuthenticationHelp 识别帮助 " + helpString);
}
//识别成功后给予的回调
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
Log.e(TAG,"onAuthenticationSucceeded 识别成功"+ result.getClass().getDeclaredFields());
for (Field params:result.getClass().getDeclaredFields()) {
Log.e(TAG,"onAuthenticationSucceeded params = "+ params.getName() );
}
try {
//因为mfrangerprint 和与之有关的都是属于hide所以要通过反射去获取
//然而就算这么写了 却并不能获取到Fingerprint这个的值(个人认为是本地拦截了,
// 为了保密,不然随便写个软件都能获取,指纹信息随便泄漏)
Field field = result.getClass().getDeclaredField("mFingerprint");
field.setAccessible(true);
Log.e(TAG,"getDeclaredField params = "+ field.getName());
Object fingerPrint = field.get(result);
Log.e(TAG,"field.get(result) params = "+ field.get(result));
/* Class<?> clzz = Class.forName("android.hardware.fingerprint.Fingerprint");
Method getName = clzz.getDeclaredMethod("getName");
Method getFingerId = clzz.getDeclaredMethod("getFingerId");
Method getGroupId = clzz.getDeclaredMethod("getGroupId");
Method getDeviceId = clzz.getDeclaredMethod("getDeviceId");
CharSequence name = (CharSequence) getName.invoke(fingerPrint);
int fingerId = (int) getFingerId.invoke(fingerPrint);
int groupId = (int) getGroupId.invoke(fingerPrint);
long deviceId = (long) getDeviceId.invoke(fingerPrint);
Log.d(TAG, "name: " + name);
Log.d(TAG, "fingerId: " + fingerId);
Log.d(TAG, "groupId: " + groupId);
Log.d(TAG, "deviceId: " + deviceId);*/
} catch (Exception e) {
e.printStackTrace();
}
}
//手指指纹识别错误,可以继续识别,连续错的次数一般在五次左右,就会关闭一段时间只回调onAuthenticationError
@Override
public void onAuthenticationFailed() {
super.onAuthenticationFailed();
Log.e(TAG,"onAuthenticationFailed 识别失败");
}
}, null);
}
//这里用到的是对称加密
KeyStore mKeyStore;//是用于存储、获取密钥(Key)的容器
KeyGenerator mKeyGenerator;//对称加密,就需要 KeyGenerator 类
Cipher defaultCipher;//Cipher 对象是一个按照一定的加密规则,将数据进行加密后的一个对象。
/**
* 创建并初始化的Cipher对象
*/
@RequiresApi(api = Build.VERSION_CODES.M)
private void createKey(){
//创建keyStore
/* KeyStore mKeyStore;
KeyGenerator mKeyGenerator;
Cipher defaultCipher;*/
try {
mKeyStore = KeyStore.getInstance("AndroidKeyStore");
} catch (KeyStoreException e) {
throw new RuntimeException("Failed to get an instance of KeyStore", e);
}
// 对称加密, 创建 KeyGenerator 对象
// KeyGenerator mKeyGenerator;
try {
mKeyGenerator = KeyGenerator
.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
}
String defaultKeyName = "crypto_object_fingerprint_key";
//获得 KeyGenerator 对象后,就可以生成一个 Key 了
try {
mKeyStore.load(null);
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(defaultKeyName,
KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
builder.setInvalidatedByBiometricEnrollment(true);
}
mKeyGenerator.init(builder.build());
mKeyGenerator.generateKey();
} catch (CertificateException | NoSuchAlgorithmException | IOException | InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
//创建 Cipher 对象
// Cipher defaultCipher;
try {
defaultCipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new RuntimeException("创建Cipher对象失败", e);
}
//初始化 Cipher 对象:
try {
mKeyStore.load(null);
SecretKey key = (SecretKey) mKeyStore.getKey(defaultKeyName, null);
defaultCipher.init(Cipher.ENCRYPT_MODE, key);
// return true;
} catch (IOException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException | KeyStoreException | InvalidKeyException e) {
throw new RuntimeException("初始化 cipher 失败", e);
}
}
}
这里主要是讲解如何去使用,而并未详细的讲解指纹识别的流程。
想要了解更多的可点击:参考文章链接