转载请注明出处:http://blog.csdn.net/wl9739/article/details/52444671

最近项目需要使用到指纹识别的功能,查阅了相关资料后,整理成此文。

指纹识别是在Android 6.0之后新增的功能,因此在使用的时候需要先判断用户手机的系统版本是否支持指纹识别。另外,实际开发场景中,使用指纹的主要场景有两种:

  • 纯本地使用。即用户在本地完成指纹识别后,不需要将指纹的相关信息给后台。
  • 与后台交互。用户在本地完成指纹识别后,需要将指纹相关的信息传给后台。

由于使用指纹识别功能需要一个加密对象(CryptoObject)该对象一般是由对称加密或者非对称加密获得。上述两种开发场景的实现大同小异,主要区别在于加密过程中密钥的创建和使用,一般来说,纯本地的使用指纹识别功能,只需要对称加密即可;而与后台交互则需要使用非对称加密:将私钥用于本地指纹识别,识别成功后将加密信息传给后台,后台开发人员用公钥解密,以获得用户信息。

下面先简单介绍一下对称加密和非对称加密的相关概念,然后对两种开发方式的实现分别进行讲解。

对称加密、非对称加密和签名

在正式使用指纹识别功能之前,有必要先了解一下对称加密和非对称加密的相关内容。

  • 对称加密:所谓对称,就是采用这种加密方法的双方使用方式用同样的密钥进行加密和解密。密钥是控制加密及解密过程的指令。算法是一组规则,规定如何进行加密和解密。因此加密的安全性不仅取决于加密算法本身,密钥管理的安全性更是重要。因为加密和解密都使用同一个密钥,如何把密钥安全地传递到解密者手上就成了必须要解决的问题。

  • 非对称加密:非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。 非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将其中的一把作为公用密钥向其它方公开;得到该公用密钥的乙方使用该密钥对机密信息进行加密后再发送给甲方;甲方再用自己保存的另一把专用密钥对加密后的信息进行解密。

  • 签名:在信息的后面再加上一段内容,可以证明信息没有被修改过。一般是对信息做一个hash计算得到一个hash值,注意,这个过程是不可逆的,也就是说无法通过hash值得出原来的信息内容。在把信息发送出去时,把这个hash值加密后做为一个签名和信息一起发出去。

由以上内容可以了解到,对称加密和非对称加密的特点如下:

  • 对称加密的优点是速度快,适合于本地数据和本地数据库的加密,安全性不如非对称加密。常见的对称加密算法有DES、3DES、AES、Blowfish、IDEA、RC5、RC6。
  • 非对称加密的安全性比较高,适合对需要网络传输的数据进行加密,速度不如对称加密。非对称加密应用于SSH, HTTPS, TLS,电子证书,电子签名,电子身份证等等

指纹识别的对称加密实现

使用指纹识别的对称加密功能的主要流程如下:

  1. 使用 KeyGenerator 创建一个对称密钥,存放在 KeyStore 里。
  2. 设置 KeyGenParameterSpec.Builder.setUserAuthenticationRequired() 为true,
  3. 使用创建好的对称密钥初始化一个Cipher对象,并用该对象调用 FingerprintManager.authenticate() 方法启动指纹传感器并开始监听。
  4. 重写 FingerprintManager.AuthenticationCallback 的几个回调方法,以处理指纹识别成功(onAuthenticationSucceeded())、失败(onAuthenticationFailed() 和 onAuthenticationError())等情况。

创建密钥

创建密钥要涉及到两个类:KeyStore 和 KeyGenerator。

KeyStore 是用于存储、获取密钥(Key)的容器,获取 KeyStore的方法如下:

try {mKeyStore = KeyStore.getInstance("AndroidKeyStore");
} catch (KeyStoreException e) {throw new RuntimeException("Failed to get an instance of KeyStore", e);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

而生成 Key,如果是对称加密,就需要 KeyGenerator 类。获取一个 KeyGenerator 对象比较简单,方法如下:

// 对称加密, 创建 KeyGenerator 对象
try {mKeyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

获得 KeyGenerator 对象后,就可以生成一个 Key 了:

 try {keyStore.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);}keyGenerator.init(builder.build());keyGenerator.generateKey();
} catch (CertificateException | NoSuchAlgorithmException | IOException | InvalidAlgorithmParameterException e) {e.printStackTrace();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

关于 KeyStrore 和 KeyGenerator 的相关介绍,推荐阅读:Android KeyStore + FingerprintManager 存储密码

创建并初始化 Cipher 对象

Cipher 对象是一个按照一定的加密规则,将数据进行加密后的一个对象。调用指纹识别功能需要使用到这个对象。创建 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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

然后使用刚才创建好的密钥,初始化 Cipher 对象:

 try {keyStore.load(null);SecretKey key = (SecretKey) keyStore.getKey(keyName, null);cipher.init(Cipher.ENCRYPT_MODE, key);return true;
} catch (IOException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException | KeyStoreException | InvalidKeyException e) {throw new RuntimeException("初始化 cipher 失败", e);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

使用指纹识别功能

真正到了使用指纹识别功能的时候,你会发现其实很简单,只是调用 FingerprintManager 类的的方法authenticate()而已,然后系统会有相应的回调反馈给我们,该方法如下:

public void authenticate(CryptoObject crypto, CancellationSignal cancel, int flags, AuthenticationCallback callback, Handler handler) 
  • 1
  • 1

该方法的几个参数解释如下:

  • 第一个参数是一个加密对象。还记得之前我们大费周章地创建和初始化的Cipher对象吗?这里的 CryptoObject 对象就是使用 Cipher 对象创建创建出来的:new FingerprintManager.CryptoObject(cipher)
  • 第二个参数是一个 CancellationSignal 对象,该对象提供了取消操作的能力。创建该对象也很简单,使用 new CancellationSignal() 就可以了。
  • 第三个参数是一个标志,默认为0。
  • 第四个参数是 AuthenticationCallback 对象,它本身是 FingerprintManager 类里面的一个抽象类。该类提供了指纹识别的几个回调方法,包括指纹识别成功、失败等。需要我们重写。
  • 最后一个 Handler,可以用于处理回调事件,可以传null。

完成指纹识别后,还要记得将 AuthenticationCallback 关闭掉:

public void stopListening() {if (cancellationSignal != null) {selfCancelled = true;cancellationSignal.cancel();cancellationSignal = null;}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

重写回调方法

调用了 authenticate() 方法后,系统就会启动指纹传感器,并开始扫描。这时候根据扫描结果,会通过FingerprintManager.AuthenticationCallback类返回几个回调方法:

// 成功
onAuthenticationSucceeded()
// 失败
onAuthenticationFaile()
// 错误
onAuthenticationError()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

一般我们需要重写这几个方法,以实现我们的功能。关于onAuthenticationFaile()onAuthenticationError()的区别,后面会讲到。

指纹识别的非对称加密实现

其实流程和上面的流程差不多:

  1. 使用 KeyPairGenerator 创建一个非对称密钥。
  2. 使用创建好的私钥进行签名,使用该签名创建一个加密对象,并将该对象作为 FingerprintManager.authenticate() 方法的一个参数,启动指纹传感器并开始监听。
  3. 重写 FingerprintManager.AuthenticationCallback 类的几个回调方法,以处理指纹识别成功(onAuthenticationSucceeded())、失败(onAuthenticationFailed() 和 onAuthenticationError())等情况。

可以看见,指纹识别的非对称加密方式和对称加密方式的实现流程是差不多的,它们之间最明显的差别是在于密钥的生成与使用。

创建密钥

这里要使用 KeyPairGenerator 来创建一组非对称密钥,首先是获取 KeyPairGenerator 对象:

// 非对称加密,创建 KeyPairGenerator 对象
try {mKeyPairGenerator =  KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {throw new RuntimeException("Failed to get an instance of KeyPairGenerator", e);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

得到了 KeyPairGenerator 对象后,就可以创建 KeyPair(密钥对)了:

try {// Set the alias of the entry in Android KeyStore where the key will appear// and the constrains (purposes) in the constructor of the BuildermKeyPairGenerator.initialize(new KeyGenParameterSpec.Builder(KEY_NAME,KeyProperties.PURPOSE_SIGN).setDigests(KeyProperties.DIGEST_SHA256).setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))// Require the user to authenticate with a fingerprint to authorize// every use of the private key.setUserAuthenticationRequired(true).build());mKeyPairGenerator.generateKeyPair();
} catch (InvalidAlgorithmParameterException e) {throw new RuntimeException(e);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

签名

指纹识别的对称加密实现中使用了Cipher对象来创建CryptoObject对象,而在这里,我们将会使用私钥进行签名,用签名对象来创建CryptoObject对象:

// 使用私钥签名
try {mKeyStore.load(null);PrivateKey key = (PrivateKey) mKeyStore.getKey(KEY_NAME, null);mSignature.initSign(key);return true;
} catch (KeyPermanentlyInvalidatedException e) {return false;
} catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException| NoSuchAlgorithmException | InvalidKeyException e) {throw new RuntimeException("Failed to init Cipher", e);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

同样的,调用new FingerprintManager.CryptoObject(mSignature)方法创建一个CryptoObject对象。

调用指纹识别方法

这里的使用方法和前面“指纹识别的对称加密实现”中的调用方法是一样的,都是调用FingerprintManager.authenticate()方法。这里就不再叙述。

监听回调

监听回调也和之前的类似,唯一不同的是,我们在识别成功后需要和后台进行交互,也就是onAuthenticationSucceeded()中处理的逻辑不一样。

实际应用中的注意事项

判断用户是否可以使用指纹识别功能

一般来说,为了增加安全性,要求用户在手机的“设置”中开启了密码锁屏功能。当然,使用指纹解锁的前提是至少录入了一个指纹。

// 如果没有设置密码锁屏,则不能使用指纹识别
if (!keyguardManager.isKeyguardSecure()) {Toast.makeText(this, "请在设置界面开启密码锁屏功能",Toast.LENGTH_LONG).show();
}
// 如果没有录入指纹,则不能使用指纹识别
if (!fingerprintManager.hasEnrolledFingerprints()) {Toast.makeText(this, "您还没有录入指纹, 请在设置界面录入至少一个指纹",Toast.LENGTH_LONG).show();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这里用到了两个类:KeyguardManager 和 FingerprintManager,前者是屏幕保护的相关类。后者是指纹识别的核心类。

关于指纹识别回调方法

前面说到AuthenticationCallback类里面的几个回调方法,其中有三个是我们开发中需要用到的:

onAuthenticationError()
onAuthenticationSucceeded()
onAuthenticationFailed()
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

关于这三个回调方法,有几点需要注意的:

  1. 当指纹识别失败后,会调用onAuthenticationFailed()方法,这时候指纹传感器并没有关闭,系统给我们提供了5次重试机会,也就是说,连续调用了5次onAuthenticationFailed()方法后,会调用onAuthenticationError()方法。

  2. 当系统调用了onAuthenticationError()onAuthenticationSucceeded()后,传感器会关闭,只有我们重新授权,再次调用authenticate()方法后才能继续使用指纹识别功能。

  3. 当系统回调了onAuthenticationError()方法关闭传感器后,这种情况下再次调用authenticate()会有一段时间的禁用期,也就是说这段时间里是无法再次使用指纹识别的。当然,具体的禁用时间由手机厂商的系统不同而有略微差别,有的是1分钟,有的是30秒等等。而且,由于手机厂商的系统区别,有些系统上调用了onAuthenticationError()后,在禁用时间内,其他APP里面的指纹识别功能也无法使用,甚至系统的指纹解锁功能也无法使用。而有的系统上,在禁用时间内调用其他APP的指纹解锁功能,或者系统的指纹解锁功能,就能立即重置指纹识别功能。

示例代码

最后, android Sample 里面关于指纹的示例代码地址如下:

对称加密方式:android-FingerprintDialog。

非对称加密方式:android-AsymmetricFingerprintDialog


以下内容更新于 2017.6.5

获取指纹信息

越来越多的朋友开始关心指纹识别这一功能模块,并且通过各种渠道向我咨询一些关于指纹识别的需求解决方案。这里就统一说明一下,就不一一回复了。

前面已经说到了,监听指纹识别成功之后会有一个 onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) 回调方法。该方法会给我们一个 AuthenticationResult 类的对象 result,该类的源码如下:

public static class AuthenticationResult {private Fingerprint mFingerprint;private CryptoObject mCryptoObject;/*** Authentication result** @param crypto the crypto object* @param fingerprint the recognized fingerprint data, if allowed.* @hide*/public AuthenticationResult(CryptoObject crypto, Fingerprint fingerprint) {mCryptoObject = crypto;mFingerprint = fingerprint;}/*** Obtain the crypto object associated with this transaction* @return crypto object provided to {@link FingerprintManager#authenticate(CryptoObject,*     CancellationSignal, int, AuthenticationCallback, Handler)}.*/public CryptoObject getCryptoObject() { return mCryptoObject; }/*** Obtain the Fingerprint associated with this operation. Applications are strongly* discouraged from associating specific fingers with specific applications or operations.** @hide*/public Fingerprint getFingerprint() { return mFingerprint; }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

这个类里面包含了一个 Fingerprint 对象,如果我们查看 Fingerprint 类的源码,可以得知该类提供了指纹的一些属性,包括指纹的名称、GroupId、FingerId 和 DeviceId 等属性。也就是说,通过 onAuthenticationSucceeded() 回调方法,我们可以得到识别的指纹的一些信息。

那为什么我们之前不使用该返回给我们的 AuthenticationResult 类对象 result 呢?因为我们没办法通过正常途径获取到这些信息。因为mFingerprint 属性是私有的,getFingerprint() 方法是被 @hide 修饰的,甚至连存储指纹信息的 Fingerprint 类也是被 @hide 修饰的。

在 Android SDK 中,有两种 API 是我们无法直接获取的,一种是位于包 com.android.internal 下面的 API,另一种是被 @hide 修饰的类和方法。

然而,针对第二种被隐藏的 API,我们可以通过反射的方式来调用相关的类和方法。以 onAuthenticationSucceeded() 回调方法为例,看看如何获取识别成功的指纹信息:

@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {try {Field field = result.getClass().getDeclaredField("mFingerprint");field.setAccessible(true);Object fingerPrint = 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 (NoSuchFieldException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) {e.printStackTrace();}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

显示的结果如下:

name:
fingerId: 1765296462
groupId: 0
deviceId: 547946660160
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4

其中,返回的 name 为空字符串。

这里要提醒一点,由于每个手机厂商都会对 Android 系统进行或多或少的定制,因此在不同的手机上调用上面的方法得到的结果可能会不一样。比如在我的手机上,fingerId 是一个十位数的整数,在其他手机上面可能就是个一位数的整数。

得到了指纹信息之后,我们就可以做一些额外的功能了,比如监听用户是否使用同一个指纹来解锁,就可以用上面的方法来判断。

除了在 onAuthenticationSucceeded() 回调方法中获取被识别的指纹信息外,还可以利用 FingerprintManager 类的 getEnrolledFingerprints() 方法来获取手机中存储的指纹列表:

public void getFingerprintInfo() {try {FingerprintManager fingerprintManager = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE);Method method = FingerprintManager.class.getDeclaredMethod("getEnrolledFingerprints");Object obj = method.invoke(fingerprintManager);if (obj != null) {Class<?> clazz = Class.forName("android.hardware.fingerprint.Fingerprint");Method getFingerId = clazz.getDeclaredMethod("getFingerId");for (int i = 0; i < ((List) obj).size(); i++) {Object item = ((List) obj).get(i);if (null == item) {continue;}Log.d(TAG, "fingerId: " + getFingerId.invoke(item));}}} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | ClassNotFoundException e) {e.printStackTrace();}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

在一些场景中,需要对用户手机里面录入的指纹进行监听,当用户手机里面的指纹列表发生了变化(比如用户删除了指纹或者新增了指纹),就需要用户重新输入密码,这时就可以用上面的方法,记录用户手机里面的指纹 ID,并进行前后对比。(当然,这种做法的安全系数并不高,也难以兼容众多设备,这里只是举例说明用途)

Android中的指纹识别相关推荐

  1. Android 6.0指纹识别App开发demo

    在Android 6.0中google终于给android系统加上了指纹识别的支持,这个功能在iPhone上早就已经实现了,并且在很多厂商的定制的ROM中也都自己内部实现这个功能了,这个功能来的有点晚 ...

  2. Android 6.0 指纹识别功能学习(一)----阿冬专栏!!!

    转载自:http://www.cnblogs.com/changyuet/p/5535082.html 由于毕设需要设计增强的身份认证(生物特征认证方式),所以需要学习指纹识别相关的android6. ...

  3. Android开发学习—指纹识别系统的原理与使用

    指纹识别是什么? 提到指纹识别我们就要先弄清楚什么事指纹,指纹为何能够做到区别性. 指纹,由于其具有终身不变性.唯一性和方便性,已几乎成为生物特征识别的代名词.指纹是指人的手指末端正面皮肤上凸凹不平产 ...

  4. [向前一小步]Android简单实现指纹识别登录

    指纹识别在Android的开发中可以说是不怎么常见,但是Google对于生物识别缺失很重视,显示废弃了以往的Android6.0推出的FingerprintManager ,后针对Android9.0 ...

  5. Android FingerPrint之指纹识别

    目前, 市面上的手机基本都支持了指纹解锁功能,甚至已经支持面部识别解锁,及虹膜识别了,但是在我们的App中却是很少有指纹登录的,包括一些金融类软件,这是因为,指纹识别是在Android 6.0 以上才 ...

  6. Android 的简易指纹识别

    一.第一步 ​ 1.第一步首先在build.gradle中导入咱们的指纹识别依赖. dependencies {implementation 'androidx.appcompat:appcompat ...

  7. “关于Android系统的指纹识别安全性”文章引来的讨论

    本文的目的:真实客观分析来自迈瑞微的这篇文章中提及的各个观点 文章标题:指纹识别离安全支付还有多远? 转发地址:http://news.cecb2b.com/info/20160105/3296661 ...

  8. Android下的指纹识别及登陆

    一.概述 Android下的指纹识别是在Android6.0后添加的功能,因此,在实现的时候要判断用户机是否支持,然后对于开发来说,使用场景有两种,分别是本地识别和跟服务器交互: 1.本地识别:在本地 ...

  9. 网络渗透中的指纹识别

    主要内容:指纹是网站CMS指纹识别,计算机操作系统及web容器的指纹识别. 1.CMS:(content management system)整站系统或文章系统 作用:开发者只要给客服一个软件包,客服 ...

最新文章

  1. SpringIOC的依耐注入DI---set注入---constructor有参构造注入---了解P命名空间---了解SpEL
  2. Flex移动皮肤开发(一)
  3. Bash:把粘贴板上的内容拷贝的文件中。
  4. python约瑟夫环单向循环链表_用单向循环链表解决约瑟夫环(Joseph)问题
  5. RocketMQ Remoting模块源码功能分析
  6. 自制力差?!教你强迫自己学习
  7. 卡内基梅隆大学计算机博士申请,2020年卡内基梅隆大学博士申请时间
  8. 如何将livp文件转换为jpeg图片格式
  9. @Valid对页面传参的校验问题
  10. 无线耳机除了苹果哪个牌子好?类似苹果耳机的蓝牙耳机推荐
  11. 【Linux学习笔记】27:环境变量中的语系变量
  12. 2020最新阿里、腾讯、华为、字节跳动等大厂的薪资和职级对比
  13. STM32单片机开发实例 基于STM32单片机的智能血压计
  14. 华为G610(Android 4.2)永久关闭键盘灯的方法
  15. thinkphp使用phpoffice读取Excel并写入数据库
  16. SpringBoot+Vue实现供销链管理系统,值得学习!
  17. 微信小程序实现svga格式动画播放
  18. [内容有误,请看参考和评论区]Spring 注解配置(annotation-config 和 component-scan的不同)
  19. 跨行业数据挖掘标准流程(CRISP-DM)
  20. cannot exec into a container in a completed pod;

热门文章

  1. Overload resolution ambiguity. All these functions match. kotlin 开发问题日常记录
  2. C# 日期插入access数据库
  3. Python 自动化办公
  4. 解决数据库日期返回格式不是yyyy-MM-dd HH:mm:ss 的问题
  5. 有效数字修约,按四舍六入五成双原则
  6. csp刷题总结(如此编码python版本)
  7. 分享一波前端开发也需要知道的关于 Centos、Docker、Nginx、Node、Jenkins的相关知识...
  8. 风变python基础语法_风变编程python (基础语法爬虫精进)
  9. ​华为麒麟1020首曝光;全球首款 5G 扩展现实平台发布;英特尔将开拓“全硅”市场;京东周伯文掌舵,申元庆出局……...
  10. cad引出线段lisp_利用lisp给CAD直线取整?