Android指纹识别

2018-04-10  本文已影响0人  ReleaseYH

指纹识别大致应用在几种场景
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;
  }
  1. 启动指纹识别
  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

当然,这只是简单指纹识别功能。具体可以根据业务开发。结合登录或者一些需要安全验证的操作。就可以提高用户体验。

上一篇下一篇

猜你喜欢

热点阅读