目前, 市面上的手机基本都支持了指纹解锁功能,甚至已经支持面部识别解锁,及虹膜识别了,但是在我们的App中却是很少有指纹登录的,包括一些金融类软件,这是因为,指纹识别是在Android 6.0 以上才被支持的,还需要有硬件的支持,这个由于Android 手机层次不齐,所以考虑到兼容性问题,就放弃了指纹识别,更多的是图案解锁功能。
那么,假如我们想做一款指纹解锁的APP,该怎么做呢。
先放张效果图吧。
这里是先用没有录入指纹的手指验证了下,结果提示错误,后面用正确的手指进行验证,提示验证成功。
前面说过了,指纹识别是从Android 6.0 开始的,所以我们在做之前呢,先要验证一些列的问题,看看我们的手机是否支持指纹识别。具体有:
private boolean isSupportFingerPrint() {
if (Build.VERSION.SDK_INT >= 23) {
// 权限判断
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "没有指纹识别权限", Toast.LENGTH_SHORT).show();
return false;
}
// 硬件判断
if (!manager.isHardwareDetected()) {
Toast.makeText(this, "没有指纹识别模块", Toast.LENGTH_SHORT).show();
return false;
}
if (!manager.hasEnrolledFingerprints()) {
Toast.makeText(this, "您至少需要在系统设置中添加一个指纹", Toast.LENGTH_SHORT).show();
return false;
}
} else {
Toast.makeText(this, "您的手机暂不支持指纹识别", Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
完了就可以初始化指纹识别的一些东西了
完整Activity代码:
public class MainActivity extends AppCompatActivity {
private FingerprintManager manager;
private KeyStore keyStore;
private static final String DEFAULT_KEY_NAME = "default_key";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
manager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);
// 判断是否支持指纹
if (isSupportFingerPrint()) {
initKey();
initCipher();
}
}
private boolean isSupportFingerPrint() {
if (Build.VERSION.SDK_INT >= 23) {
// 权限判断
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "没有指纹识别权限", Toast.LENGTH_SHORT).show();
return false;
}
// 硬件判断
if (!manager.isHardwareDetected()) {
Toast.makeText(this, "没有指纹识别模块", Toast.LENGTH_SHORT).show();
return false;
}
if (!manager.hasEnrolledFingerprints()) {
Toast.makeText(this, "您至少需要在系统设置中添加一个指纹", Toast.LENGTH_SHORT).show();
return false;
}
} else {
Toast.makeText(this, "您的手机暂不支持指纹识别", Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
private void initKey() {
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(DEFAULT_KEY_NAME,
KeyProperties.PURPOSE_ENCRYPT |
KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
keyGenerator.init(builder.build());
keyGenerator.generateKey();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void initCipher() {
try {
SecretKey key = (SecretKey) keyStore.getKey(DEFAULT_KEY_NAME, null);
Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
cipher.init(Cipher.ENCRYPT_MODE, key);
showFingerPrintDialog(cipher);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void showFingerPrintDialog(Cipher cipher) {
final FingerPrintDialog fingerPrintDialog = new FingerPrintDialog();
fingerPrintDialog.setCipher(cipher);
fingerPrintDialog.setCancelable(false);
fingerPrintDialog.show(getSupportFragmentManager(), "fingerprint");
}
}
我们在页面中的识别对话框实在DialogFragment中实现的,这样可以利用Fragment的生命周期来处理我们的监听,因为我们总不能一直占着传感器。
DialogFragment代码:里面有详细的注释,这里就不做解释了
public class FingerPrintDialog extends DialogFragment {
private FingerprintManager manager;
private TextView message;
private CancellationSignal cancel;
// 是否主动取消
private boolean isCancel;
private Cipher cipher;
private Handler handler = new Handler();
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
manager = (FingerprintManager) getContext().getSystemService(FINGERPRINT_SERVICE);
cancel = new CancellationSignal();
setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.dialog_fingerprint, container, false);
message = view.findViewById(R.id.error_msg);
return view;
}
@Override
public void onResume() {
super.onResume();
startListening();
}
@Override
public void onPause() {
super.onPause();
stopListening();
}
public void setCipher(Cipher cipher){
this.cipher = cipher;
}
private void startListening() {
isCancel = false;
manager.authenticate(new FingerprintManager.CryptoObject(cipher), cancel, 0, new FingerprintManager.AuthenticationCallback() {
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
if (!isCancel) {
message.setText(errString);
// 超过5次错误,自动锁住
if (errorCode == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT) {
Toast.makeText(getContext(), errString, Toast.LENGTH_SHORT).show();
dismiss();
}
}
}
@Override
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
message.setText(helpString);
}
@Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
Toast.makeText(getContext(), "指纹识别成功!", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(getActivity(), SuccessPageActivity.class);
startActivity(intent);
}
@Override
public void onAuthenticationFailed() {
message.setText("指纹验证失败,请重试!");
// 一秒钟后去掉提示
handler.postDelayed(new Runnable() {
@Override
public void run() {
message.setText(" ");
}
}, 1000);
}
}, null);
}
private void stopListening() {
isCancel = true;
}
}
Demo 地址:https://github.com/Trac-MacGrady/FingerPrintVerification