Android 中指纹识别
Android从6.0系统开始就支持指纹认证功能了,指纹功能还需要有硬件支持才行
指纹与手机系统设置的指纹进行匹配
如图:
在LoginActivity 中弹出指纹验证Fragment,验证成功进入MainActivity中
代码:
创建FingerprintDialogFragment 继承 DialogFragment
package com.chuanye.zhiwendemo; import android.annotation.SuppressLint; import android.content.Context; import android.hardware.fingerprint.FingerprintManager; import android.os.Bundle; import android.os.CancellationSignal; import android.support.annotation.Nullable; import android.support.v4.app.DialogFragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; import javax.crypto.Cipher; public class FingerprintDialogFragment extends DialogFragment { private FingerprintManager fingerprintManager; private CancellationSignal mCancellationSignal; private Cipher mCipher; private LoginActivity mActivity; private TextView errorMsg; /** * 标识是否是用户主动取消的认证。 */ private boolean isSelfCancelled; public void setCipher(Cipher cipher) { mCipher = cipher; } @Override public void onAttach(Context context) { super.onAttach(context); mActivity = (LoginActivity) getActivity(); } @SuppressLint("NewApi") @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); fingerprintManager = getContext().getSystemService(FingerprintManager.class); setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog); } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fingerprint_dialog, container, false); errorMsg = v.findViewById(R.id.error_msg); TextView cancel = v.findViewById(R.id.cancel); cancel.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dismiss(); stopListening(); } }); return v; } @Override public void onResume() { super.onResume(); // 开始指纹认证监听 startListening(mCipher); } @Override public void onPause() { super.onPause(); // 停止指纹认证监听 stopListening(); } @SuppressLint({"MissingPermission", "NewApi"}) private void startListening(Cipher cipher) { isSelfCancelled = false; mCancellationSignal = new CancellationSignal(); fingerprintManager.authenticate(new FingerprintManager.CryptoObject(cipher), mCancellationSignal, 0, new FingerprintManager.AuthenticationCallback() { @Override public void onAuthenticationError(int errorCode, CharSequence errString) { if (!isSelfCancelled) { errorMsg.setText(errString); if (errorCode == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT) { Toast.makeText(mActivity, errString, Toast.LENGTH_SHORT).show(); dismiss(); } } } @Override public void onAuthenticationHelp(int helpCode, CharSequence helpString) { errorMsg.setText(helpString); } @Override public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) { Toast.makeText(mActivity, "指纹认证成功", Toast.LENGTH_SHORT).show(); mActivity.onAuthenticated(); } @Override public void onAuthenticationFailed() { errorMsg.setText("指纹认证失败,请再试一次"); } }, null); } @SuppressLint("NewApi") private void stopListening() { if (mCancellationSignal != null) { mCancellationSignal.cancel(); mCancellationSignal = null; isSelfCancelled = true; } } }
布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:src="@drawable/ic_fp_40px" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="20dp" android:text="请验证指纹解锁" android:textColor="#000" android:textSize="16sp" /> <TextView android:id="@+id/error_msg" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginTop="5dp" android:maxLines="1" android:textSize="12sp" android:textColor="#f45" /> <View android:layout_width="match_parent" android:layout_height="0.5dp" android:layout_marginTop="10dp" android:background="#ccc" /> <TextView android:id="@+id/cancel" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center" android:text="取消" android:textColor="#5d7883" android:textSize="16sp" /> </LinearLayout>
LoginActivity 中
package com.chuanye.zhiwendemo; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.KeyguardManager; import android.content.Intent; import android.hardware.fingerprint.FingerprintManager; import android.os.Build; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.Toast; import java.security.KeyStore; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; public class LoginActivity extends AppCompatActivity { //https://blog.csdn.net/guolin_blog/article/details/81450114 private static final String DEFAULT_KEY_NAME = "default_key"; KeyStore keyStore; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); if (supportFingerprint()) {//判断是否支持指纹 initKey(); initCipher(); } } /** * 判断是否支持指纹 * @return */ @SuppressLint("MissingPermission") public boolean supportFingerprint() { if (Build.VERSION.SDK_INT < 23) { Toast.makeText(this, "您的系统版本过低,不支持指纹功能", Toast.LENGTH_SHORT).show(); return false; } else { //键盘锁管理者 KeyguardManager keyguardManager = getSystemService(KeyguardManager.class); //指纹管理者 FingerprintManager fingerprintManager = getSystemService(FingerprintManager.class); if (!fingerprintManager.isHardwareDetected()) {//判断硬件支不支持指纹 Toast.makeText(this, "您的手机不支持指纹功能", Toast.LENGTH_SHORT).show(); return false; } else if (!keyguardManager.isKeyguardSecure()) {//还未设置锁屏 Toast.makeText(this, "您还未设置锁屏,请先设置锁屏并添加一个指纹", Toast.LENGTH_SHORT).show(); return false; } else if (!fingerprintManager.hasEnrolledFingerprints()) {//指纹未登记 Toast.makeText(this, "您至少需要在系统设置中添加一个指纹", Toast.LENGTH_SHORT).show(); return false; } } return true; } @TargetApi(23) 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); } } @TargetApi(23) 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) { FingerprintDialogFragment fragment = new FingerprintDialogFragment(); fragment.setCipher(cipher); fragment.show(getSupportFragmentManager(), "fingerprint"); } public void onAuthenticated() { Intent intent = new Intent(this, MainActivity.class); startActivity(intent); finish(); } }
activity_main.xml布局
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="已进入App主界面" android:textSize="18sp" android:layout_gravity="center" /> </FrameLayout>
最后添加权限
<uses-permission android:name="android.permission.USE_FINGERPRINT"></uses-permission>
注意,通常为了让用户清楚的知道现在需要进行指纹认证,Google官方建议最好使用一个通用的指纹图标,而不应该由各APP制作自己的指纹图标。为此,Google也特意提供了一套指纹认证的组图,可以 点击这里 查看和下载。
指纹认证不能单独使用,必须要配合着图案或其他认证方式一起来使用,因为一定要提供一个在设备不支持指纹情况下的其他认证方式
另外FingerprintManager在最新的Android 9.0系统上已经被废弃了因为Android 9.0系统提供了更加强大的生物识别认证功能,包括指纹识别、面部识别、甚至是虹膜识别等等,因此仅仅只能用于指纹识别的FingerprintManager已经不能满足新系统的强大需求了。
参考与郭神的https://blog.csdn.net/guolin_blog/article/details/81450114