android 在较低的 API 中使用指纹授权时出现 VerifyError

VerifyError in using FingerPrint authorization in lower APIs in android

我想在我的应用程序中使用指纹授权。但是当我在 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.access0(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'
}

如何在较低的 API 中解决 VerifyError 和 运行 我的应用程序? 感谢您的帮助。

更新: 我使用@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.access0(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.access0(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) 

请参考我的Sample FingerPrint应用程序,它支持传统指纹设备、棉花糖设备和三星设备。