android指纹解锁_Android指纹锁

android指纹解锁

In this tutorial, we’ll be discussing the Android Fingerprint API and implement a Fingerprint Dialog in our android application.

在本教程中,我们将讨论Android Fingerprint API,并在android应用程序中实现Fingerprint Dialog。

Android指纹管理器 (Android Fingerprint Manager)

Fingerprint Manager is the class used to access the Fingerprint hardware from the device (if it exists).

指纹管理器是用于从设备(如果存在)访问指纹硬件的类。

Google recommends authenticating fingerprint in applications by displaying a DialogFragment with a Fingerprint icon to the user.

Google建议通过向用户显示带有指纹图标的DialogFragment来对应用程序中的指纹进行身份验证。

In order to implement Fingerprint Authentication, you need to add the following permission in the AndroidManifest.xml file:

为了实现指纹认证,您需要在AndroidManifest.xml文件中添加以下权限

<uses-permission android:name="android.permission.USE_FINGERPRINT" />

Following are the steps to implement Fingerprint Authentication in your application:

以下是在您的应用程序中实现指纹认证的步骤:

  • Check whether there is a secure lock on the lock screen

    检查锁屏上是否有安全锁
  • Check whether the Fingerprint Hardware is available using the FingerprintManager class.

    使用FingerprintManager类检查指纹硬件是否可用。
  • Check whether the user has enrolled at least one fingerprint.

    检查用户是否注册了至少一个指纹。
  • Get access to Android keystore to store a key used to initiate a Cipher.

    获取对Android密钥库的访问权限,以存储用于启动密码的密钥。
  • Start the Authentication Method and add the callback methods

    启动身份验证方法并添加回调方法

The Android Keystore system lets you store cryptographic keys in a container to make it more difficult to extract from the device.

Android Keystore系统可让您将加密密钥存储在容器中,以使其更难从设备中提取。

项目结构 (Project Structure)

(Code)

The code for the activity_main.xml layout is given below:

下面给出了activity_main.xml布局的代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="START AUTHENTICATION"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


</android.support.constraint.ConstraintLayout>

The code for the dialog_fingerprint.xml is given below:

下面给出了dialog_fingerprint.xml的代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="24dp"
    android:paddingTop="24dp"
    android:paddingRight="24dp"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent">

    <TextView
        android:id="@+id/titleTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Fingerprint Dialog"
        android:textAppearance="?android:attr/textAppearanceLarge"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

    <TextView
        android:id="@+id/subtitleTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="Confirm fingerprint to continue."
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/titleTextView" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="28dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@id/subtitleTextView"
        app:srcCompat="@drawable/ic_fingerprint_white_24dp" />

    <TextView
        android:id="@+id/errorTextView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="16dp"
        android:gravity="center_vertical"
        android:text="Touch sensor"
        app:layout_constraintBottom_toBottomOf="@id/fab"
        app:layout_constraintLeft_toRightOf="@id/fab"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="@id/fab" />

    <LinearLayout
        android:id="@+id/buttons"
        style="?android:attr/buttonBarStyle"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:gravity="end"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/fab">

        <Button
            android:id="@+id/btnCancel"
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Cancel" />
    </LinearLayout>


</android.support.constraint.ConstraintLayout>

The FingerprintHelper.java class is where we define the methods for authentication and initialization of Fingerprint and related class objects:

在FingerprintHelper.java类中,我们定义了指纹和相关类对象的身份验证和初始化方法:

package com.journaldev.androidfingerprintapi;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.CancellationSignal;
import android.support.v4.app.ActivityCompat;

public class FingerprintHelper extends FingerprintManager.AuthenticationCallback {


    private Context mContext;
    private FingerprintManager mFingerprintManager;
    private CancellationSignal mCancellationSignal;
    private Callback mCallback;


    public FingerprintHelper(FingerprintManager fingerprintManager, Context context, Callback callback) {
        mContext = context;
        mFingerprintManager = fingerprintManager;
        mCallback = callback;

    }


    public boolean isFingerprintAuthAvailable() {

        return mFingerprintManager.isHardwareDetected()
                && mFingerprintManager.hasEnrolledFingerprints();
    }


    public void startAuthentication(FingerprintManager manager, FingerprintManager.CryptoObject cryptoObject) {

        if (!isFingerprintAuthAvailable())
            return;

        mCancellationSignal = new CancellationSignal();
        if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.USE_FINGERPRINT) != PackageManager.PERMISSION_GRANTED) {
            return;
        }

        manager.authenticate(cryptoObject, mCancellationSignal, 0, this, null);
    }


    public void stopListening() {
        if (mCancellationSignal != null) {
            mCancellationSignal.cancel();
            mCancellationSignal = null;
        }
    }

    @Override
    public void onAuthenticationError(int errMsgId, CharSequence errString) {
        mCallback.onError(errString.toString());
    }


    @Override
    public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
        mCallback.onHelp(helpString.toString());
    }


    @Override
    public void onAuthenticationFailed() {
        mCallback.onAuthenticated(false);
    }


    @Override
    public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
        mCallback.onAuthenticated(true);
    }


    public interface Callback {

        void onAuthenticated(boolean b);

        void onError(String s);

        void onHelp(String s);
    }
}

manager.authenticate(cryptoObject, mCancellationSignal, 0, this, null); starts the authentication.

manager.authenticate(cryptoObject, mCancellationSignal, 0, this, null); 开始认证。

The Callback interface is used to pass the information to the UI which eventually gets displayed to the user.

回调接口用于将信息传递到UI,最终将其显示给用户。

The code for the MainActivity.java class is given below:

MainActivity.java类的代码如下:

package com.journaldev.androidfingerprintapi;

import android.support.v4.hardware.fingerprint.FingerprintManagerCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;


public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    Button button;
    FingerprintManagerCompat managerCompat;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        button = findViewById(R.id.button);
        button.setOnClickListener(this);

    }

    private void showFingerPrintDialog() {

        FingerprintDialog fragment = new FingerprintDialog();
        fragment.setContext(this);
        fragment.show(getSupportFragmentManager(), "");


    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.button:
                managerCompat = FingerprintManagerCompat.from(MainActivity.this);

                if (managerCompat.isHardwareDetected() && managerCompat.hasEnrolledFingerprints()) {
                    showFingerPrintDialog();
                } else {
                    Toast.makeText(getApplicationContext(), "Fingerprint not supported", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }

}

managerCompat = FingerprintManagerCompat.from(MainActivity.this); initialises the FingerprintCompat class object.

managerCompat = FingerprintManagerCompat.from(MainActivity.this); 初始化FingerprintCompat类对象。

isHardwareDetected() and hasEnrolledFingerprints() are used to check whether the fingerprint authentication is possible before showing the Dialog.

isHardwareDetected()hasEnrolledFingerprints()用于在显示对话框之前检查指纹身份验证是否可行。

The code for the FingerprintDialog.java is given below:

FingerprintDialog.java的代码如下:

package com.journaldev.androidfingerprintapi;

import android.app.KeyguardManager;
import android.content.Context;
import android.content.Intent;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.support.v4.app.DialogFragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
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 java.security.cert.CertificateException;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;

public class FingerprintDialog extends DialogFragment
        implements FingerprintHelper.Callback {

    Button mCancelButton;
    public static final String DEFAULT_KEY_NAME = "default_key";
    FingerprintManager mFingerprintManager;

    private FingerprintManager.CryptoObject mCryptoObject;
    private FingerprintHelper mFingerprintHelper;

    KeyStore mKeyStore = null;
    KeyGenerator mKeyGenerator = null;
    KeyguardManager mKeyguardManager;

    private Context mContext;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setRetainInstance(true);
        setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog);

        try {
            mKeyStore = KeyStore.getInstance("AndroidKeyStore");

        } catch (KeyStoreException e) {
            e.printStackTrace();
        }

        try {
            mKeyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchProviderException e) {
            e.printStackTrace();
        }

        Cipher defaultCipher;
        try {
            defaultCipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
                    + KeyProperties.BLOCK_MODE_CBC + "/"
                    + KeyProperties.ENCRYPTION_PADDING_PKCS7);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new RuntimeException("Failed to get an instance of Cipher", e);
        }

        mKeyguardManager = getContext().getSystemService(KeyguardManager.class);
        mFingerprintManager = getContext().getSystemService(FingerprintManager.class);

        mFingerprintHelper = new FingerprintHelper(mFingerprintManager, getContext(), this);

        if (!mKeyguardManager.isKeyguardSecure()) {
            Toast.makeText(getContext(),
                    "Lock screen not set up.\n"
                            + "Go to 'Settings -> Security -> Fingerprint' to set up a fingerprint",
                    Toast.LENGTH_LONG).show();
            return;
        }

        createKey(DEFAULT_KEY_NAME);

        if (initCipher(defaultCipher, DEFAULT_KEY_NAME)) {
            mCryptoObject = new FingerprintManager.CryptoObject(defaultCipher);
        }
    }

    private boolean initCipher(Cipher cipher, String keyName) {
        try {
            mKeyStore.load(null);
            SecretKey key = (SecretKey) mKeyStore.getKey(keyName, null);
            cipher.init(Cipher.ENCRYPT_MODE, key);


            return true;
        } catch (KeyPermanentlyInvalidatedException e) {
            Toast.makeText(mContext, "Keys are invalidated after created. Retry the purchase\n"
                            + e.getMessage(),
                    Toast.LENGTH_LONG).show();

            return false;
        } catch (KeyStoreException | CertificateException | UnrecoverableKeyException | IOException
                | NoSuchAlgorithmException | InvalidKeyException e) {
            Toast.makeText(mContext, "Failed to init cipher", Toast.LENGTH_LONG).show();
            return false;
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.dialog_fingerprint, container, false);
        mCancelButton = v.findViewById(R.id.btnCancel);
        mCancelButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dismiss();
            }
        });

        return v;
    }

    @Override
    public void onResume() {
        super.onResume();

        if (mCryptoObject != null) {
            mFingerprintHelper.startAuthentication(mFingerprintManager, mCryptoObject);
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        mFingerprintHelper.stopListening();
    }

    public void setContext(Context context) {
        mContext = context;
    }


    public void createKey(String keyName) {
        try {
            mKeyStore.load(null);
           

            KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keyName,
                    KeyProperties.PURPOSE_ENCRYPT |
                            KeyProperties.PURPOSE_DECRYPT)
                    .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
                    .setUserAuthenticationRequired(true)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);

            mKeyGenerator.init(builder.build());
            mKeyGenerator.generateKey();
        } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException
                | CertificateException | IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void onAuthenticated(boolean b) {
        if (b) {
            Toast.makeText(mContext.getApplicationContext(), "Auth success", Toast.LENGTH_LONG).show();
            dismiss();
        } else
            Toast.makeText(mContext.getApplicationContext(), "Auth failed", Toast.LENGTH_LONG).show();
    }

    @Override
    public void onError(String s) {
        Toast.makeText(mContext.getApplicationContext(), s, Toast.LENGTH_LONG).show();
    }

    @Override
    public void onHelp(String s) {
        Toast.makeText(mContext.getApplicationContext(), "Auth help message:" + s, Toast.LENGTH_LONG).show();
    }
}

setRetainInstance(true); is used to prevent multiple instances of the DialogFragment from getting created when the config changes.

setRetainInstance(true); 用于防止在配置更改时创建DialogFragment的多个实例。

The output of the above application in action is given below:

上面应用程序的输出如下:

So on my phone when I authenticated with the correct fingerprint, it showed the appropriate Toast message.

因此,当我使用正确的指纹进行身份验证时,手机上会显示相应的Toast消息。

That brings an end to this tutorial. You can download the project from the link below:

这样就结束了本教程。 您可以从下面的链接下载项目:

Note: Fingerprint API is deprecated since API 28 and replaced by the BiometricPrompt. We’ll discuss that in another tutorial. 注意 :自API 28开始不推荐使用指纹API,并由BiometricPrompt代替。 我们将在另一个教程中进行讨论。

翻译自: https://www.journaldev.com/23881/android-fingerprint-lock

android指纹解锁

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值