Android从6.0(api = 23)系统开始就支持指纹认证功能,但在Android P (api = 28) 系统官方标记为(@Deprecated)过期,不再推荐使用,并新增BiometricPrompt接口,来做指纹识别。所以在项目开发中我们为了兼容手机版本,就必须要做好版本适配

一、Android 6.0处理

1、创建 FingerprintManager对象

FingerprintManager manager = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE);

然后调用authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler)去验证指纹,看官方文档如下:

    /**     * @param crypto object associated with the call or null if none required.     * @param cancel an object that can be used to cancel authentication     * @param flags optional flags; should be 0     * @param callback an object to receive authentication events     * @param handler an optional handler to handle callback events         * @deprecated See {@link BiometricPrompt#authenticate(CancellationSignal, Executor,     * BiometricPrompt.AuthenticationCallback)} and {@link BiometricPrompt#authenticate(     * BiometricPrompt.CryptoObject, CancellationSignal, Executor,     * BiometricPrompt.AuthenticationCallback)}     */    @Deprecated    @RequiresPermission(anyOf = {USE_BIOMETRIC, USE_FINGERPRINT})    public void authenticate(@Nullable CryptoObject crypto, @Nullable CancellationSignal cancel,int flags, @NonNull AuthenticationCallback callback, @Nullable Handler handler) {        authenticate(crypto, cancel, flags, callback, handler, mContext.getUserId());    }
  • CryptoObject crypto:与调用关联的加密对象,如果不需要,则为空,但是这样的话,就意味这app无条件信任认证的结果,这是app被篡改的风险。
  • CancellationSignal cancel:可用于取消指纹验证的对象,当在指纹验证的时候取消指纹扫描,如果不取消,就会一致扫描指纹,直到超时
  • flags:图文标志,标志当前图文,默认是0
  • AuthenticationCallback  callback:指纹验证结果的回掉对象,通过改对象,我们处理指纹是否验证成功
  • Handler  handler:处理回调事件的可选处理程序,

a、CryptoObject对象创建

参考CryptoObjectHelper类,获取对象如下:

FingerprintManager.CryptoObject crypto = new CryptoObjectHelper().createCryptoObject();
@RequiresApi(Build.VERSION_CODES.M)public class CryptoObjectHelper {    // This can be key name you want. Should be unique for the app.    static final String KEY_NAME = "us.mifeng.fingerprint.biometric.CryptoObjectHelper";    // We always use this keystore on Android.    static final String KEYSTORE_NAME = "AndroidKeyStore";    // Should be no need to change these values.    static final String KEY_ALGORITHM = KeyProperties.KEY_ALGORITHM_AES;    static final String BLOCK_MODE = KeyProperties.BLOCK_MODE_CBC;    static final String ENCRYPTION_PADDING = KeyProperties.ENCRYPTION_PADDING_PKCS7;    static final String TRANSFORMATION = KEY_ALGORITHM + File.separator + BLOCK_MODE + File.separator  + ENCRYPTION_PADDING;    final KeyStore _keystore;    public CryptoObjectHelper() throws Exception {        _keystore = KeyStore.getInstance(KEYSTORE_NAME);        _keystore.load(null);    }    public FingerprintManager.CryptoObject createCryptoObject() throws Exception {        Cipher cipher = createCipher(true);        return new FingerprintManager.CryptoObject(cipher);    }    private Cipher createCipher(boolean retry) throws Exception {        Key key = getKey();        Cipher cipher = Cipher.getInstance(TRANSFORMATION);        try {            cipher.init(Cipher.ENCRYPT_MODE | Cipher.DECRYPT_MODE, key);        } catch (KeyPermanentlyInvalidatedException e) {            _keystore.deleteEntry(KEY_NAME);            if (retry) {                createCipher(false);            } else {                throw new Exception("Could not create the cipher for fingerprint authentication.", e);            }        }        return cipher;    }    private Key getKey() throws Exception {        Key secretKey;        if (!_keystore.isKeyEntry(KEY_NAME)) {            createKey();        }        secretKey = _keystore.getKey(KEY_NAME, null);        return secretKey;    }   private void createKey() throws Exception {        KeyGenerator keyGen = KeyGenerator.getInstance(KEY_ALGORITHM, KEYSTORE_NAME);        KeyGenParameterSpec keyGenSpec =                new KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)                        .setBlockModes(BLOCK_MODE)                        .setEncryptionPaddings(ENCRYPTION_PADDING)                        .setUserAuthenticationRequired(true)                        .build();        keyGen.init(keyGenSpec);        keyGen.generateKey();    }}

b、CancellationSignal 对象创建

CancellationSignal cancel = new CancellationSignal();

设置取消验证监听回掉

cancel.setOnCancelListener(new CancellationSignal.OnCancelListener() {            @Override            public void onCancel() {            }        });

调用cancel()方法取消验证

cancel.cancel();

c、AuthenticationCallback对象创建回掉

    FingerprintManager.AuthenticationCallback callback= new FingerprintManager.AuthenticationCallback(){            @Override            public void onAuthenticationError(int errorCode, CharSequence errString) {                super.onAuthenticationError(errorCode, errString);            }            @Override            public void onAuthenticationFailed() {                super.onAuthenticationFailed();            }            @Override            public void onAuthenticationHelp(int helpCode, CharSequence helpString) {                super.onAuthenticationHelp(helpCode, helpString);            }            @Override            public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {                super.onAuthenticationSucceeded(result);            }        };    }

   对AuthenticationCallback中的方法处理:

  • onAuthenticationError:当遇到不可恢复的错误并且操作完成时调用。不会再对此对象进行回调,一般是输入次数过多或者是手机硬件出现问题
  • onAuthenticationFailed:当指纹有效但无法识别时调用。
  • onAuthenticationHelp:在身份验证过程中遇到可恢复的错误时调用。提供的帮助字符串用于为用户提供出错的指导,例如“传感器脏了,请清理它”。
  • onAuthenticationSucceeded:指纹识别成功回掉

二、Android 8.0处理

1、BiometricPrompt对象创建

google在BiometricPrompt 创建中不需要自定义UI了,Google为了统一指纹识别以及后期的生物识别,已经不允许自定义UI了,创建时必须使用BiometricPrompt.Builder来创建对话框,其中可以自定义title、subtitle、description和一个NegativeButton(也就是cancel键)

        BiometricPrompt prompt =   new BiometricPrompt                .Builder(this)                .setTitle("Verification Title")                .setDescription("Verify fingerprint to continue")                .setSubtitle("")                .setNegativeButton("Use Password", this.getMainExecutor(), new DialogInterface.OnClickListener() {                    @Override                    public void onClick(DialogInterface dialog, int which) {                    }                }).build();

然后通过BiometricPrompt调用

authenticate( @NonNull CryptoObject crypto, @NonNull CancellationSignal cancel, @NonNull @CallbackExecutor Executor executor, @NonNull AuthenticationCallback callback)

authenticate(@NonNull CancellationSignal cancel, @NonNull @CallbackExecutor Executor executor, @NonNull AuthenticationCallback callback)

方法,实现指纹验证

官方文档:

 /** 第一个方法*/    /* @param crypto Object associated with the call     * @param cancel An object that can be used to cancel authentication     * @param executor An executor to handle callback events     * @param callback An object to receive authentication events     */    @RequiresPermission(USE_BIOMETRIC)    public void authenticate(@NonNull CryptoObject crypto,            @NonNull CancellationSignal cancel,            @NonNull @CallbackExecutor Executor executor,            @NonNull AuthenticationCallback callback) {        if (handlePreAuthenticationErrors(callback, executor)) {            return;        }        mFingerprintManager.authenticate(crypto, cancel, mBundle, executor, mDialogReceiver,                callback);    }    /** 第二个方法*/    /* @param cancel An object that can be used to cancel authentication     * @param executor An executor to handle callback events     * @param callback An object to receive authentication events     */    @RequiresPermission(USE_BIOMETRIC)    public void authenticate(@NonNull CancellationSignal cancel,            @NonNull @CallbackExecutor Executor executor,            @NonNull AuthenticationCallback callback) {        if (handlePreAuthenticationErrors(callback, executor)) {            return;        }        mFingerprintManager.authenticate(cancel, mBundle, executor, mDialogReceiver, callback);    }

2、BiometricPrompt.CryptoObject

参考参考CryptoObjectHelper2类,获取对象如下:

BiometricPrompt.CryptoObject cryptoObject = new CryptoObjectHelper2().createCryptoObject();

CryptoObjectHelper2类如下:

@RequiresApi(Build.VERSION_CODES.P)public class CryptoObjectHelper2 {    private static final String KEY_NAME = "BiometricPromptApi28";    public BiometricPrompt.CryptoObject createCryptoObject() throws Exception {        KeyPair keyPair = generateKeyPair(KEY_NAME,true);        String mToBeSignedMessage = new StringBuilder()                .append(Base64.encodeToString(keyPair.getPublic().getEncoded(), Base64.URL_SAFE))                .append(":")                .append(KEY_NAME)                .append(":")                // Generated by the server to protect against replay attack                .append("12345")                .toString();        Signature mSignature = initSignature(KEY_NAME);        return new BiometricPrompt.CryptoObject(mSignature);    }    private Signature initSignature(String keyName) throws Exception {        KeyPair keyPair = getKeyPair(keyName);        if (null != keyPair){            Signature signature = Signature.getInstance("SHA256withECDSA");            signature.initSign(keyPair.getPrivate());            return signature;        }        return null;    }    private KeyPair getKeyPair(String keyName) throws Exception{        KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");        keyStore.load(null);        if (keyStore.containsAlias(keyName)){            PublicKey publicKey = keyStore.getCertificate(keyName).getPublicKey();            PrivateKey privateKey = (PrivateKey) keyStore.getKey(keyName,null);            return new KeyPair(publicKey,privateKey);        }        return null;    }        private KeyPair generateKeyPair(String keyName, boolean invaldateByBiometricEnrollment) throws Exception {        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC,"AndroidKeyStore");        KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keyName,KeyProperties.PURPOSE_SIGN)                .setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))                .setDigests(KeyProperties.DIGEST_SHA256,                        KeyProperties.DIGEST_SHA384,                        KeyProperties.DIGEST_SHA512)                .setUserAuthenticationRequired(true)                .setInvalidatedByBiometricEnrollment(invaldateByBiometricEnrollment);        keyPairGenerator.initialize(builder.build());        return keyPairGenerator.generateKeyPair();    }    }

 

更多相关文章

  1. Android保证首次获取到的location对象不为空的解决方案
  2. android中能不能new Activity()对象引发的思考
  3. android 使用socket与pc传递对象的问题
  4. Android探索之旅 | 面向对象和Java基础
  5. Android对Window对象的管理机制分析
  6. android 5.0之后利用Intent传递Serializable对象存在问题

随机推荐

  1. 简单的三方登录SDK示例,Android Activity
  2. Android知识梳理:消息机制之Looper
  3. Android程序调试时生成main.out.xml文件
  4. Android 通知栏系列....
  5. android WebView 预览office文档
  6. Android 文字链接 文字点击时的背景颜色
  7. 对Activity比较复杂的style设置
  8. Android(安卓)和jsp登录接口
  9. android开机动画启动流程
  10. Gradle(三)构建任务