Android指纹识别



在开始之前,我们需要知道使用指纹识别硬件的基本步骤: 
1.在AndroidManifest.xml中申明如下权限:
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
2.获得FingerprintManager的对象引用 
3.在运行是检查设备指纹识别的兼容性,比如是否有指纹识别设备等。下面我们详细说一下上面的步骤:

申明权限
这一步比较简单,只要在AndroidManifest.xml中添加上面说到的权限就可以了。

获得FingerprintManager对象引用
这是app开发中获得系统服务对象的常用方式,如下:
// Using the Android Support Library v4
fingerprintManager = FingerprintManagerCompat.from(this);
// Using API level 23:
fingerprintManager = (FingerprintManager)getSystemService(Context.FINGERPRINT_SERVICE);
 
上面给出两种方式,第一种是通过V4支持包获得兼容的对象引用,这是google推行的做法;还有就是直接使用api 23 framework中的接口获得对象引用。

之后就可以直接使用,或者是考虑加密后再使用。因为这里主要是讲解如何使用,方便上手操作,详细的就不多说了,注释里见!

下面直接给出使用时的demo。

因为我们使用的时候主要是用到开启指纹的识别,识别后成功、失败回调的方法。

多于的东西自行了解,多多益善。

我这里才用的是对称加密,其实不加密也可以运行。

package com.zq.sensoradapter;

import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
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 FingerActivity extends AppCompatActivity {

    public static final  String TAG = "Finger";

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fingerprint);

        Button button = findViewById(R.id.sure_btn);
        
        //点击开始识别
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                createKey();
                checkFinger();
            }
        });




    }

    /**
     * 检查是否支持指纹识别
     * 若支持则开启指纹识别
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    private void checkFinger(){
        FingerprintManager fingerprintManager = getFingerprintManager(this);//获取指纹识别管理器
        if (fingerprintManager == null){
            Toast.makeText(this,"此设备无法指纹识别",Toast.LENGTH_LONG);
        }else {

            sureFinger(fingerprintManager);
        }
    }

    /**
     * 获取指纹识别管理器
     * @param context
     * @return
     */
    public static FingerprintManager getFingerprintManager(Context context) {
        FingerprintManager fingerprintManager = null;
        try {
            fingerprintManager = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
        } catch (Throwable e) {
            Log.e(TAG,"have not class FingerprintManager");
        }
        return fingerprintManager;
    }

    /**
     * 开始指纹识别
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    private void sureFinger(FingerprintManager fingerprintManager){
        //第一个参数是一个加密对象。这里的 CryptoObject 对象就是使用 Cipher 对象创建创建出来的:new FingerprintManager.CryptoObject(cipher)。
        //第二个参数是一个 CancellationSignal 对象,该对象提供了取消操作的能力。创建该对象也很简单,使用 new CancellationSignal() 就可以了。
        //第三个参数是一个标志,默认为0。
        //第四个参数是 AuthenticationCallback 对象,它本身是 FingerprintManager 类里面的一个抽象类。该类提供了指纹识别的几个回调方法,包括指纹识别成功、失败等。需要我们重写。
        //最后一个 Handler,可以用于处理回调事件,可以传null。
        fingerprintManager.authenticate(new FingerprintManager.CryptoObject(defaultCipher),
                new CancellationSignal(), 0, new FingerprintManager.AuthenticationCallback() {
            //连续识别错误后,识别时调用的方法,一般持续30s-60s。
            @Override
            public void onAuthenticationError(int errorCode, CharSequence errString) {
                super.onAuthenticationError(errorCode, errString);
                Log.e(TAG,errorCode +"onAuthenticationError 识别错误:" + errString);
            }

            //告诉你除开识别失败后的错误信息
            @Override
            public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
                super.onAuthenticationHelp(helpCode, helpString);
                Log.e(TAG,helpCode + ":onAuthenticationHelp 识别帮助 " + helpString);
            }

            //识别成功后给予的回调
            @Override
            public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
                super.onAuthenticationSucceeded(result);


                Log.e(TAG,"onAuthenticationSucceeded 识别成功"+  result.getClass().getDeclaredFields());
                for (Field  params:result.getClass().getDeclaredFields()) {
                    Log.e(TAG,"onAuthenticationSucceeded params = "+  params.getName() );
                }
                try {
                    //因为mfrangerprint 和与之有关的都是属于hide所以要通过反射去获取
                    //然而就算这么写了 却并不能获取到Fingerprint这个的值(个人认为是本地拦截了,
                    // 为了保密,不然随便写个软件都能获取,指纹信息随便泄漏)
                    Field field = result.getClass().getDeclaredField("mFingerprint");
                    field.setAccessible(true);
                    Log.e(TAG,"getDeclaredField params = "+  field.getName());

                    Object fingerPrint = field.get(result);
                    Log.e(TAG,"field.get(result) params = "+  field.get(result));

                   /*  Class<?> clzz = Class.forName("android.hardware.fingerprint.Fingerprint");
                   Method getName = clzz.getDeclaredMethod("getName");
                    Method getFingerId = clzz.getDeclaredMethod("getFingerId");
                    Method getGroupId = clzz.getDeclaredMethod("getGroupId");
                    Method getDeviceId = clzz.getDeclaredMethod("getDeviceId");

                    CharSequence name = (CharSequence) getName.invoke(fingerPrint);
                    int fingerId = (int) getFingerId.invoke(fingerPrint);
                    int groupId = (int) getGroupId.invoke(fingerPrint);
                    long deviceId = (long) getDeviceId.invoke(fingerPrint);

                    Log.d(TAG, "name: " + name);
                    Log.d(TAG, "fingerId: " + fingerId);
                    Log.d(TAG, "groupId: " + groupId);
                    Log.d(TAG, "deviceId: " + deviceId);*/
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
            //手指指纹识别错误,可以继续识别,连续错的次数一般在五次左右,就会关闭一段时间只回调onAuthenticationError
            @Override
            public void onAuthenticationFailed() {
                super.onAuthenticationFailed();
                Log.e(TAG,"onAuthenticationFailed 识别失败");
            }
        }, null);
    }

    
    //这里用到的是对称加密
    KeyStore mKeyStore;//是用于存储、获取密钥(Key)的容器
    KeyGenerator mKeyGenerator;//对称加密,就需要 KeyGenerator 类
    Cipher defaultCipher;//Cipher 对象是一个按照一定的加密规则,将数据进行加密后的一个对象。

    /**
     * 创建并初始化的Cipher对象
     */
    @RequiresApi(api = Build.VERSION_CODES.M)
    private void createKey(){
        //创建keyStore
       /* KeyStore mKeyStore;
        KeyGenerator mKeyGenerator;
        Cipher defaultCipher;*/
        try {
             mKeyStore = KeyStore.getInstance("AndroidKeyStore");
        } catch (KeyStoreException e) {
            throw new RuntimeException("Failed to get an instance of KeyStore", e);
        }

        // 对称加密, 创建 KeyGenerator 对象
//        KeyGenerator mKeyGenerator;
        try {
              mKeyGenerator = KeyGenerator
                    .getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
        } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
            throw new RuntimeException("Failed to get an instance of KeyGenerator", e);
        }
        String defaultKeyName = "crypto_object_fingerprint_key";
        //获得 KeyGenerator 对象后,就可以生成一个 Key 了
        try {
            mKeyStore.load(null);
            KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(defaultKeyName,
                    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();
        } catch (CertificateException | NoSuchAlgorithmException | IOException | InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }

        //创建 Cipher 对象
//        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("创建Cipher对象失败", e);
        }

        //初始化 Cipher 对象:
        try {
            mKeyStore.load(null);
            SecretKey key = (SecretKey) mKeyStore.getKey(defaultKeyName, null);
            defaultCipher.init(Cipher.ENCRYPT_MODE, key);
//            return true;
        } catch (IOException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException | KeyStoreException | InvalidKeyException e) {
            throw new RuntimeException("初始化 cipher 失败", e);
        }

    }


}

  

 这里主要是讲解如何去使用,而并未详细的讲解指纹识别的流程。      

 想要了解更多的可点击:参考文章链接



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值