Android指纹识别
指纹识别大致应用在几种场景
1,系统解锁
2,应用锁
3,支付认证
4,普通的登录认证
指纹识别需要手机硬件支持才能使用。核心的API 是FingerprintManager。主类依赖三个内部类,
1,FingerprintManager.AuthenticationResult 指纹识别结果封装,从回调接口里面会传回来
2, FingerprintManager.CryptoObject 指纹识别数据传输加密对象
3, FingerprintManager.AuthenticationCallback 指纹识别成功、失败、错误的回调接口。
FingerprintManager 提供3个方法
启动指纹识别
2.png
这里cancel参数是用来主动取消指纹识别的。handle是默认会在主线程运行。
判断是否至少录入一个指纹
3.png
判断是否有硬件支持
4.png
有这些方法就可以尝试下代码编写了。
1,首先 AndroidManifest权限声明权限
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
2,获取FingerManager服务对象
public static FingerprintManager getFingerprintManager(Context context) {
FingerprintManager fingerprintManager = null;
try {
fingerprintManager = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
} catch (Throwable e) {
L.v("have not class FingerprintManager");
}
return fingerprintManager;
}
- 启动指纹识别
mFingerprintManager.authenticate(cryptoObject, mCancellationSignal, 0, mAuthCallback, null);
参数意思参考文档说明,这里比较复杂的是创建CryptoObject对象,如果只是简单测试可以为null。
官方v4兼容包
上面介绍是官方实现指纹识别的方式,当然适配肯定没这么简单,因为有很多设备兼容性要考虑,Google后续再v4包中提供了一套完整的实现,实现类与上面的一一对应的,就是改了个名字(FingerprintManager改为了FingerprintManagerCompat,所以Google在v4包中做了一些兼容性处理),做了很多兼容处理,官方推荐使用后者。
下面是一些相关的注意点或者说是一些会遇到的坑。
1,Google官方支持指纹识别的标准接口是在Android6.0开始的,如果各个厂商都升级到6.0并且硬件上都给予支持,那么我们按照标准的指纹识别接口使用就可以了。
2,如果在android6.0发布以后,手机厂商来不及升级,但是工程师们参考了官方指纹识别的代码,把代码移植到他们的6.0版本以下的系统,或者参照Google提供的接口自己实现了一套指纹识别机制,只是对开发者暴露的接口一样,这样就可以像使用标准接口一样使用,但是这种情况就难说了,实现不好的可能本身就有很多bug,适配起也比较麻烦,不过起码还是能用的。
3,如果厂商在Google之前就已经做了指纹识别,那这种情况肯定不能使用官方标准接口,如果要适配这种设备,只能使用厂商提供的第三方指纹识别SDK。
所以建议 6.0及以上系统选择性屏蔽一些机型(有些厂商支持不好)
这里CryptoObject的初始化工作。
private void initCryptoObject() {
try {
mCryptoObjectCreator = new CryptoObjectCreator(new CryptoObjectCreator.ICryptoObjectCreateListener() {
@Override
public void onDataPrepared(FingerprintManager.CryptoObject cryptoObject) {
// startAuthenticate(cryptoObject);
// 如果需要一开始就进行指纹识别,可以在秘钥数据创建之后就启动指纹认证
}
});
} catch (Throwable throwable) {
FPLog.log("create cryptoObject failed!");
}
}
CryptoObjectCreator类
@TargetApi(Build.VERSION_CODES.M)
public class CryptoObjectCreator {
private static final String KEY_NAME = "crypto_object_fingerprint_key";
private FingerprintManager.CryptoObject mCryptoObject;
private KeyStore mKeyStore;
private KeyGenerator mKeyGenerator;
private Cipher mCipher;
public interface ICryptoObjectCreateListener {
void onDataPrepared(FingerprintManager.CryptoObject cryptoObject);
}
public CryptoObjectCreator(ICryptoObjectCreateListener createListener) {
mKeyStore = providesKeystore();
mKeyGenerator = providesKeyGenerator();
mCipher = providesCipher(mKeyStore);
if (mKeyStore != null && mKeyGenerator != null && mCipher != null) {
mCryptoObject = new FingerprintManager.CryptoObject(mCipher);
}
prepareData(createListener);
}
private void prepareData(final ICryptoObjectCreateListener createListener) {
new Thread("FingerprintLogic:InitThread") {
@Override
public void run() {
try {
if (mCryptoObject != null) {
createKey();
// Set up the crypto object for later. The object will be authenticated by use
// of the fingerprint.
if (!initCipher()) {
FPLog.log("Failed to init Cipher.");
}
}
} catch (Exception e) {
FPLog.log(" Failed to init Cipher, e:" + Log.getStackTraceString(e));
}
if (createListener != null) {
createListener.onDataPrepared(mCryptoObject);
}
}
}.start();
}
/**
* Creates a symmetric key in the Android Key Store which can only be used after the user has
* authenticated with fingerprint.
*/
private void createKey() {
// The enrolling flow for fingerprint. This is where you ask the user to set up fingerprint
// for your flow. Use of keys is necessary if you need to know if the set of
// enrolled fingerprints has changed.
try {
mKeyStore.load(null);
// Set the alias of the entry in Android KeyStore where the key will appear
// and the constrains (purposes) in the constructor of the Builder
mKeyGenerator.init(new KeyGenParameterSpec.Builder(KEY_NAME,
KeyProperties.PURPOSE_ENCRYPT |
KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
// Require the user to authenticate with a fingerprint to authorize every use
// of the key
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build());
mKeyGenerator.generateKey();
} catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException
| CertificateException | IOException e) {
FPLog.log(" Failed to createKey, e:" + Log.getStackTraceString(e));
throw new RuntimeException(e);
}
}
/**
* Initialize the {@link Cipher} instance with the created key in the {@link #createKey()}
* method.
*
* @return {@code true} if initialization is successful, {@code false} if the lock screen has
* been disabled or reset after the key was generated, or if a fingerprint got enrolled after
* the key was generated.
*/
private boolean initCipher() {
try {
mKeyStore.load(null);
SecretKey key = (SecretKey) mKeyStore.getKey(KEY_NAME, null);
mCipher.init(Cipher.ENCRYPT_MODE, key);
return true;
} catch (KeyPermanentlyInvalidatedException e) {
FPLog.log(" Failed to initCipher, e:" + Log.getStackTraceString(e));
return false;
} catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException
| NoSuchAlgorithmException | InvalidKeyException e) {
FPLog.log(" Failed to initCipher, e :" + Log.getStackTraceString(e));
throw new RuntimeException("Failed to init Cipher", e);
}
}
public static KeyStore providesKeystore() {
try {
return KeyStore.getInstance("AndroidKeyStore");
} catch (Throwable e) {
return null;
}
}
public static KeyGenerator providesKeyGenerator() {
try {
return KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
} catch (Throwable e) {
return null;
}
}
public static Cipher providesCipher(KeyStore keyStore) {
try {
return Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
} catch (Throwable e) {
return null;
}
}
public FingerprintManager.CryptoObject getCryptoObject() {
return mCryptoObject;
}
public void onDestroy() {
mCipher = null;
mCryptoObject = null;
mCipher = null;
mKeyStore = null;
}
}
下面是效果图
5.png
点击按钮启动指纹识别之后识别指纹。成功。
6.png
当然,这只是简单指纹识别功能。具体可以根据业务开发。结合登录或者一些需要安全验证的操作。就可以提高用户体验。