Android SDK<23上的指纹识别技术

4
我在一个Android项目中,minSDK=17,targetSDK=23。我们使用FingerprintManager类实现了指纹认证(该类已添加到SDK23中)。我们添加了SDK版本检查,因此如果SDK<23,我们不会使用与指纹相关的任何内容。但是,在旧版SDK中,应用程序的行为是不可预测的:在某些版本上,应用程序会崩溃,在其他版本上,指纹无法工作(因此,这是可以接受的)。
我的问题:
1)是否有好用且易于实现的库可以识别minSDK=17的指纹?
2)如何避免在SDK<23的设备中发生应用程序崩溃?
崩溃错误信息:
E/dalvikvm: Could not find class 'android.hardware.fingerprint.FingerprintManager', referenced from method nl.intratuin.LoginActivity.loginByFingerprint
E/AndroidRuntime: FATAL EXCEPTION: main   java.lang.VerifyError:
LoginActivity at java.lang.Class.newInstanceImpl(Native Method)

一些新信息:使用这个教程创建了 HelloWorld 指纹项目: http://www.techotopia.com/index.php/An_Android_Fingerprint_Authentication_Tutorial 找到了问题的根源: FingerprintDemoActivity->cipherInit:
try {
    keyStore.load(null);
    SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME,
             null);
    cipher.init(Cipher.ENCRYPT_MODE, key);
    return true;
} catch (KeyPermanentlyInvalidatedException e) {
    return false;
} catch (KeyStoreException | CertificateException 
      | UnrecoverableKeyException | IOException
      | NoSuchAlgorithmException | InvalidKeyException e) {
   throw new RuntimeException("Failed to init Cipher", e);
}

第一个catch块会因为上面提到的错误而导致整个应用程序崩溃。当然,我可以删除这个catch块(这个异常扩展了InvalidKeyException,所以它将被处理),并在任何异常情况下返回false。有没有更好的方法?


3
"有没有适用于最低SDK版本为17的好用且易于实现的指纹识别库?在SDK<23之前的指纹支持都是针对特定制造商的。" "如何避免在SDK<23的设备上应用程序崩溃?请提供一个MCVE。" - CommonsWare
8个回答

14

我认为我找到了一个可接受的解决方案:不是捕获 KeyPermanentlyInvalidatedException 异常,而是捕获 InvalidKeyException。这样做一切都能正常工作。但仍然不知道这个异常是如何导致整个应用程序崩溃的...


你是最棒的...谢谢 - Mulflar
谢谢,伙计...你真的救了我的一天。 - Jeyaseelan

5

我也遇到了这个问题,即使我使用:if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)…我的应用程序在Android 4.4-KitKat上崩溃。所以最终问题出现在initCipher方法的catch部分中-请参见以下代码(尽管我不应该进入该部分,因为它是针对M及以上版本的...非常奇怪的行为...):

@TargetApi(Build.VERSION_CODES.M)
private boolean initCipher() {
    try {
        mKeyStore.load(null);
        SecretKey key = (SecretKey) mKeyStore.getKey(KEY_NAME, null);
        mCipher.init(Cipher.ENCRYPT_MODE, key);

        return true;
    } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException
            | NoSuchAlgorithmException e) {
        throw new RuntimeException("Failed to init Cipher", e);
    } catch (InvalidKeyException e) {
        e.printStackTrace();
        return false;

    }
}

显然,捕获的顺序很重要。所以请确保按照我提到的方式编写。

感谢使用 @TargetApi(Build.VERSION_CODES.M) - Ahmed Nabil

4

崩溃原因:

FingerprintManager类适用于Android版本23及以上

如果您的应用程序正在使用FingerprintManager类并且在旧版Android上运行,则会遇到此异常。

支持旧版Android:

如果您计划支持Android <23,请使用FingerprintManagerCompat代替FingerprintManagerFingerprintManagerCompat类在内部检查Android版本并轻松处理身份验证部分。

如何使用:

  • android.hardware.fingerprint.FingerprintManager替换为android.support.v4.hardware.fingerprint.FingerprintManagerCompat

  • android.os.CancellationSignal替换为android.support.v4.os.CancellationSignal

查看示例代码

https://github.com/hiteshsahu/FingerPrint-Authentication-With-React-Native-Android/blob/master/android/app/src/main/java/com/aproject/view/Fragments/FingerprintAuthenticationDialogFragment.java


1
看看由afollestad创建的一个叫做digitus的库。 如果指纹不可用,该库可以回退到密码。
在SDK 23之前的任何设备都需要使用自己独立的基于设备制造商的SDK。

链接不可用。 - Morteza Rastgoo

1

只需按照 Android Studio 提示操作,一切都会没问题的。

 try {
        mKeyStore.load(null);
        SecretKey key = (SecretKey) mKeyStore.getKey(keyName, null);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return true;
    } catch (IOException | NoSuchAlgorithmException | CertificateException
            | UnrecoverableKeyException | KeyStoreException | InvalidKeyException e) {
        e.printStackTrace();
        throw new RuntimeException("Failed to init Cipher", e);
    }

0
我通过将所有指纹代码移动到一个辅助类中来解决了这个问题,这样与指纹代码相关的类就不会在活动中被导入,并且只有当SDK_INT大于23时才实例化辅助类(在我的情况下,我只支持Android 6+)。

0

回答问题的第二部分:

如何避免在SDK<23的设备上应用程序崩溃?

这个简单的逻辑检查就足够了:

if (Build.VERSION.SDK_INT < 23) { 
   // Handle the mechanism where the SDK is older.
}else{
   // Handle the mechanism where the SDK is 23 or later.
}

1
尝试过了,但不管怎样,我的sdk 17崩溃了。 - Ivan Budnikov

0

我也遇到了这个问题。即使我使用了:if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)…我的应用程序在较低的API上仍然会崩溃。我解决了这个问题,方法如下:

替换以下代码:

      try {

            keyStore.load(null);
            SecretKey key = (SecretKey) keyStore.getKey(KEY_NAME,
                    null);
            cipher.init(Cipher.ENCRYPT_MODE, key);
            return true;
        } catch (KeyPermanentlyInvalidatedException e) {
            return false;
        } catch (KeyStoreException | CertificateException
                | UnrecoverableKeyException | IOException
                | NoSuchAlgorithmException | InvalidKeyException e) {
            throw new RuntimeException("Failed to init Cipher", e);
        }

使用:

     try {

            keyStore.load(null);
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecretKey key = null;
        try {
            key = (SecretKey) keyStore.getKey(KEY_NAME,
                    null);
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        }
        try {
            cipher.init(Cipher.ENCRYPT_MODE, key);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return true;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接