前天偶尔运行代码,一个段异常映入眼帘,我擦android10上反射机制监听不到指纹id等数据了,原因是android10彻底抛弃了之前指纹的api。所以反射不到了。
怎么解决这个问题?我们换个思路当然反射依然可以,不过你需要在android9之前和之后的版本写不同的反射代码,首先之前的反射代码都是我抄的别人的,android10现在还没大神奉献,我也写不出来!!!!(这是关键)
所以我想到了,
根据当前指纹库创建一个密钥 判断秘钥状态来判断指纹库是否发生了改变。是不是很神奇,不是原创的,我也是看见别人给了这样一个思路。
我们设计一个吧!
1.设计一个初始化秘钥的方法(这个方法要可以重新生成和重复利用之前秘钥的功能,为什么?你问我为啥?因为要监听改变就要能获取上次的秘钥所以要可以重复利用秘钥,因为一旦指纹变化了,用户可能需要重置指纹重新设置指纹密码,那么就要重新生成新的秘钥。)
2,需要一个判断指纹是否改变的方法,使用cipher去验证刚才的key,如果指纹改变了会抛异常,捕获和这个异常就可以了。
不说废话了上代码:
package cn.lkk.lkk.util;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.support.annotation.RequiresApi;
import android.text.TextUtils;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
/**
* @author lkk
* @date 2019/08/23 10:01
*/
@RequiresApi(api = Build.VERSION_CODES.M)
public class CipherHelper
{
private static CipherHelper instance;
private static final String DEFAULT_KEY_NAME = "defaultKey";
private static final String KEYSTORE_ALIAS = "keyStoreAlias";
private static final String HAS_FINGER_KEY = "hasFingerKey";
private KeyGenerator mKeyGenerator;
private KeyStore keyStore;
private CipherHelper()
{
try
{
keyStore = KeyStore.getInstance("AndroidKeyStore");
}
catch (KeyStoreException e)
{
e.printStackTrace();
}
try
{
mKeyGenerator = KeyGenerator
.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
}
catch (NoSuchAlgorithmException | NoSuchProviderException e)
{
throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
}
}
publicstatic CipherHelper getInstance()
{
if (instance == null)
{
synchronized (CipherHelper.class)
{
if (instance == null)
{
instance = new CipherHelper();
}
}
}
return instance;
}
/**
* @des 创建cipher
* @author lkk
* @date 2019/08/23 10:05
*/
publicCipher createCipher()
{
try
{
return Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
+ KeyProperties.BLOCK_MODE_CBC + "/"
+ KeyProperties.ENCRYPTION_PADDING_PKCS7);
}
catch (NoSuchAlgorithmException | NoSuchPaddingException e)
{
e.printStackTrace();
}
return null;
}
/**
* @des 初始化Cipher ,并判断指纹库是否发生了变化
* @author lkk
* @date 2019/08/23 10:17
*/
publicboolean initCipher(Cipher cipher)
{
try
{
keyStore.load(null);
SecretKey key = (SecretKey) keyStore.getKey(KEYSTORE_ALIAS, null);
if (cipher == null)
{
cipher = createCipher();
}
cipher.init(Cipher.ENCRYPT_MODE, key);
return false;
}
catch (KeyPermanentlyInvalidatedException e)
{
return true;
}
catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException
| NoSuchAlgorithmException | InvalidKeyException e)
{
return false;
//throw new RuntimeException("Failed to init Cipher", e);
}
}
/**
* @param context
* @param createNewKey 是否创建新的密钥
* @des 根据当前指纹库创建一个密钥
* @author lkk
* @date 2019/08/23 10:30
*/
publicvoid createKey(Context context, boolean createNewKey)
{
if (context == null)
{
throw new RuntimeException("context can not be null");
}
SharedPreferences sharedPreferences = context.getSharedPreferences(DEFAULT_KEY_NAME, Context.MODE_PRIVATE);
try
{
//首先通过标志位判断用户之前是否创建了密钥,如果已经创建过了并且不需要重新创建就跳过
if (TextUtils.isEmpty(sharedPreferences.getString(HAS_FINGER_KEY, "")) || createNewKey)
{
//创建新密钥
KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(KEYSTORE_ALIAS,
KeyProperties.PURPOSE_ENCRYPT |
KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
{
builder.setInvalidatedByBiometricEnrollment(true);
}
mKeyGenerator.init(builder.build());
mKeyGenerator.generateKey();
sharedPreferences.edit().putString(HAS_FINGER_KEY, "KEY").apply();
}
}
catch (InvalidAlgorithmParameterException e)
{
//throw new RuntimeException(e);
}
}
}
怎么使用呢?
开始监听
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mCipher = CipherHelper.getInstance().createCipher();
CipherHelper.getInstance().createKey(getActivity(), false);
}
监听判断
if (CipherHelper.getInstance().initCipher(mCipher)){
//关闭指纹登录
//弹窗告知用户
}
重置监听Key
CipherHelper.getInstance().createKey(getActivity(), true);