我想在我的应用中使用FingerPrint授权。但是当我在安装了Android 4.1的三星GT-N8000上运行时,它已停止并显示VerifyError
(此设备不支持指纹传感器)。
import android.Manifest;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Typeface;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.os.Bundle;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.graphics.drawable.TintAwareDrawable;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
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 javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.security.cert.CertificateException;
import banknote.maxsoft.com.banknote.DataBaseClass;
import banknote.maxsoft.com.banknote.MainActivity;
import banknote.maxsoft.com.banknote.R;
public class LogUpInActivity extends Activity {
// sign in with password
public View signIn_passwordContent;
// sign in with finger print
public View signIn_fingerPrintContent;
private KeyguardManager keyguardManager;
private FingerprintManager fingerprintManager;
private KeyStore keyStore;
private KeyGenerator keyGenerator;
private TextView msg_fingerPrint;
private Cipher cipher;
private static final String KEY_NAME = "mohrOmoom";
private FingerprintManager.CryptoObject cryptoObject;
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_container);
signIn_passwordContent = findViewById(R.id.signIn_password_container);
signIn_fingerPrintContent = findViewById(R.id.fingerprint_container);
msg_fingerPrint = (TextView) findViewById(R.id.fingerprint_description);
// Initializing both Android Keyguard Manager and Fingerprint Manager
if (Build.VERSION.SDK_INT>=23) {
keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
fingerprintManager = (FingerprintManager) getSystemService(FINGERPRINT_SERVICE);
}
// Check whether the device has a Fingerprint sensor.
if ((!fingerprintManager.isHardwareDetected()) && (Build.VERSION.SDK_INT>+23)){
signIn_fingerPrintContent.setVisibility(View.GONE);
} else {
signIn_fingerPrintContent.setVisibility(View.VISIBLE);
// Checks whether fingerprint permission is set on manifest
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
msg_fingerPrint.setVisibility(View.VISIBLE);
msg_fingerPrint.setText(R.string.fingerPrint_not_avable);
msg_fingerPrint.setTextColor(getResources().getColor(R.color.red_color));
} else {
// Check whether at least one fingerprint is registered
if (!fingerprintManager.hasEnrolledFingerprints()) {
msg_fingerPrint.setVisibility(View.VISIBLE);
msg_fingerPrint.setText(R.string.fingerPrint_not_register);
msg_fingerPrint.setTextColor(getResources().getColor(R.color.red_color));
} else {
// Checks whether lock screen security is enabled or not
if (!keyguardManager.isKeyguardSecure()) {
msg_fingerPrint.setVisibility(View.VISIBLE);
msg_fingerPrint.setText(R.string.fingerPrint_not_register);
msg_fingerPrint.setTextColor(getResources().getColor(R.color.red_color));
} else {
generateKey();
if (cipherInit()) {
cryptoObject = new FingerprintManager.CryptoObject(cipher);
FingerprintHandler helper = new FingerprintHandler(this);
helper.startAuth(fingerprintManager, cryptoObject);
}
}
}
}
}
}
...
} // on create
/*
sign in with finger print
*/
@TargetApi(Build.VERSION_CODES.M)
protected void generateKey() {
try {
keyStore = KeyStore.getInstance("AndroidKeyStore");
} catch (Exception e) {
e.printStackTrace();
}
try {
keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
//startActivity(new Intent(LogUpInActivity.this,MainActivity.class));
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
throw new RuntimeException("Failed to get KeyGenerator instance", e);
}
try {
keyStore.load(null);
keyGenerator.init(new
KeyGenParameterSpec.Builder(KEY_NAME,
KeyProperties.PURPOSE_ENCRYPT |
KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_CBC)
.setUserAuthenticationRequired(true)
.setEncryptionPaddings(
KeyProperties.ENCRYPTION_PADDING_PKCS7)
.build());
keyGenerator.generateKey();
} catch (NoSuchAlgorithmException |
InvalidAlgorithmParameterException
| IOException e) {
throw new RuntimeException(e);
} catch (java.security.cert.CertificateException e) {
e.printStackTrace();
}
}
@TargetApi(Build.VERSION_CODES.M)
public boolean cipherInit() {
try {
cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_CBC + "/" + KeyProperties.ENCRYPTION_PADDING_PKCS7);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new RuntimeException("Failed to get Cipher", e);
}
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 | UnrecoverableKeyException | IOException
| NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException("Failed to init Cipher", e);
} catch (java.security.cert.CertificateException e) {
e.printStackTrace();
}
return true;
}
public void onFinish(){
editor_password.putString("password",logIn_password).commit();
}
这是错误日志:
FATAL EXCEPTION: main
java.lang.VerifyError: PACKAGE NAME/LogUpInActivity
at java.lang.Class.newInstanceImpl(Native Method)
at java.lang.Class.newInstance(Class.java:1319)
at android.app.Instrumentation.newActivity(Instrumentation.java:1068)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2025)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2135)
at android.app.ActivityThread.access$700(ActivityThread.java:140)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4921)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
at dalvik.system.NativeStart.main(Native Method)
和这个si Build.grdle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.1"
defaultConfig {
applicationId "banknote.maxsoft.com.banknote"
minSdkVersion 15
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.0.1'
compile 'com.android.support:design:25.0.1'
compile 'junit:junit:4.12'
compile 'com.getbase:floatingactionbutton:1.10.1'
}
如何解决VerifyError
并在较低的API中运行我的应用?
谢谢你的帮助。
更新: 我使用@MuthukrishnanRajendran回答,如下:
public class LogActivity extends Activity implements FPStatusListener {
// sign up statue
private SharedPreferences StatuSharePreference;
private SharedPreferences.Editor editor_state;
public boolean state_signUp, default_state, state_check;
private LogUpInActivity.Stage mStage;
// sign up with password
private View signUpContent;
private EditText signUp_pasword_editText, signUp_conf_password_editText, signIn_password_editText;
public static SharedPreferences save_password_sharePreference;
public static SharedPreferences.Editor editor_password;
public static String logIn_password = null;
// sign in with password
public View signIn_passwordContent;
public int times_of_signIn=3;
// sign in with finger print
public View signIn_fingerPrintContent;
private LFingerPrint mLFingerPrint;
private TextView msg_fingerPrint;
private static final String KEY_NAME = "mohrOmoom";
// sign in after unlocking
public boolean sign_in_again;
private Button cancelBTN, stateBTN;
private TextView msg_state_conf;
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog_container);
TextView who = (TextView) findViewById(R.id.who);
who.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/mehr.ttf"));
TextView signInPassTitle = (TextView) findViewById(R.id.password_description);
signInPassTitle.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/nazanin.ttf"));
TextView signUpPassTitle = (TextView) findViewById(R.id.signUp_title);
signUpPassTitle.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/nazanin.ttf"));
StatuSharePreference = getSharedPreferences("signUp", Context.MODE_PRIVATE);
editor_state = StatuSharePreference.edit();
signUpContent = findViewById(R.id.signup_content);
signUp_pasword_editText = (EditText) findViewById(R.id.pass);
signUp_conf_password_editText = (EditText) findViewById(R.id.conf_pass);
signIn_password_editText = (EditText) findViewById(R.id.password);
msg_state_conf = (TextView) findViewById(R.id.notConfiration_msg);
save_password_sharePreference = getSharedPreferences("password", Context.MODE_PRIVATE);
editor_password = save_password_sharePreference.edit();
signIn_passwordContent = findViewById(R.id.signIn_password_container);
signIn_fingerPrintContent = findViewById(R.id.fingerprint_container);
msg_fingerPrint = (TextView) findViewById(R.id.fingerprint_description);
mLFingerPrint = new LFingerPrint(this, this);
// check if sign up is done or not
if (!default_state) {
state_signUp = false;
default_state = true;
} else {
state_signUp = true;
}
state_check = StatuSharePreference.getBoolean("signUp", state_signUp);
if (!state_check) {
// register user password
signIn_passwordContent.setVisibility(View.GONE);
signUpContent.setVisibility(View.VISIBLE);
mStage = LogUpInActivity.Stage.SIGNUP;
} else {
signUpContent.setVisibility(View.GONE);
signIn_passwordContent.setVisibility(View.VISIBLE);
// Check whether the device has a Fingerprint sensor.
if ((!mLFingerPrint.getManager().isFingerPrintAvailable())){
signIn_fingerPrintContent.setVisibility(View.GONE);
} else {
signIn_fingerPrintContent.setVisibility(View.VISIBLE);
// Checks whether fingerprint permission is set on manifest
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
msg_fingerPrint.setVisibility(View.VISIBLE);
msg_fingerPrint.setText(R.string.fingerPrint_not_avable);
msg_fingerPrint.setTextColor(getResources().getColor(R.color.red_color));
} else {
// Check whether at least one fingerprint is registered
if (!mLFingerPrint.getManager().hasFingerprintRegistered()) {
msg_fingerPrint.setVisibility(View.VISIBLE);
msg_fingerPrint.setText(R.string.fingerPrint_not_register);
msg_fingerPrint.setTextColor(getResources().getColor(R.color.red_color));
} else {
mLFingerPrint.getManager().startListening();
}
}
}
mStage = LogUpInActivity.Stage.SIGNIN_PASSWORD;
}
cancelBTN = (Button) findViewById(R.id.cancel_button);
cancelBTN.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
logIn_password = save_password_sharePreference.getString("password", logIn_password);
stateBTN = (Button) findViewById(R.id.second_dialog_button);
stateBTN.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
public void onClick(View view) {
switch (mStage) {
case SIGNUP: //get user password and register it
registerPassword();
break;
/*case SIGNIN_FINGERPRINT:// open sign in with password
signInWithPassword();
break;*/
case SIGNIN_PASSWORD://checking passsword entry
verifyPassword();
break;
}
}
});
} // on create
/**
* get user password from Edit text , check its lengh , confirm it
**/
public void registerPassword() {
String passString = signUp_pasword_editText.getText().toString();
String confPassString = signUp_conf_password_editText.getText().toString();
if ((passString.equals(confPassString)) &&
(passString.length() == 12) &&
(confPassString.length() == 12)) {
logIn_password = passString;
editor_password.putString("password", logIn_password).commit();
Toast.makeText(this, logIn_password, Toast.LENGTH_LONG).show();
msg_state_conf.setVisibility(View.VISIBLE);
msg_state_conf.setText(R.string.msg_conf);
msg_state_conf.setTextColor(getResources().getColor(R.color.green_color));
editor_state.putBoolean("signUp", true).commit();
//state_signUp = true;
//mina! ***checking fingerPrint sensor***
/* + : finger primt authorization
** - : sign in with password
*/
mStage = LogUpInActivity.Stage.SIGNIN_PASSWORD;
signUpContent.setVisibility(View.GONE);
signIn_passwordContent.setVisibility(View.VISIBLE);
} else {
msg_state_conf.setVisibility(View.VISIBLE);
msg_state_conf.setText(R.string.msg_not_conf);
msg_state_conf.setTextColor(getResources().getColor(R.color.red_color));
//not confirm
editor_state.putBoolean("signUp", false).commit();
}
}
/**
* Checks whether the current entered password is correct, and dismisses the the dialog and
* let's the activity know about the result.
*/
private void verifyPassword() {
logIn_password = save_password_sharePreference.getString("signUp", logIn_password);
Toast.makeText(this, logIn_password, Toast.LENGTH_LONG).show();
if (signIn_password_editText.getText().toString().equals(logIn_password)) {
startActivity(new Intent(LogActivity.this, MainActivity.class));
LogActivity.this.finish();
} else {
--times_of_signIn;
Toast.makeText(this, times_of_signIn + "تعداد ورود باقیمانده:", Toast.LENGTH_LONG).show();
signIn_password_editText.setText(null);
if (times_of_signIn == 0) {
Toast.makeText(this, R.string.restart_app, Toast.LENGTH_LONG).show();
MainActivity.sqlDB.delete(DataBaseClass.BANK_TABLE_NAME, null, null);
logIn_password = null;
editor_password.putString("password", logIn_password).commit();
state_signUp = false;
editor_state.putBoolean("signUp", state_signUp).commit();
signIn_passwordContent.setVisibility(View.GONE);
signUpContent.setVisibility(View.VISIBLE);
mStage = LogUpInActivity.Stage.SIGNUP;
}
}
}
public void onFinish(){
editor_password.putString("password",logIn_password).commit();
}
/**
* Enumeration to indicate which authentication method the user is trying to authenticate with.
*/
public enum Stage {
SIGNUP,
SIGNIN_FINGERPRINT,
SIGNIN_PASSWORD
}
@Override
public void fpAuthSuccess() {
Intent intent=new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
}
@Override
public void fpAuthFailed(@Nullable String error) {
Toast.makeText(this,R.string.fingerPrint_retry,Toast.LENGTH_LONG).show();
}
}
但是当我在三星N8000上运行时,这个错误告诉我:
FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{...LogActivity}: java.lang.NullPointerException
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2110)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2135)
at android.app.ActivityThread.access$700(ActivityThread.java:140)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4921)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at banknote.maxsoft.com.banknote.authorization.LogActivity.onCreate(LogActivity.java:135)
at android.app.Activity.performCreate(Activity.java:5188)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2074)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2135)
at android.app.ActivityThread.access$700(ActivityThread.java:140)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4921)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
at dalvik.system.NativeStart.main(Native Method)