Android中通过反射机制获取手机系统内部的指纹数据

Google从Android6.0(api 23)开始支持指纹识别的功能,我们可以通过FingerprintManager类来调用官方暴露的api,来启用手机上的指纹识别设备完成指纹验证操作,具体文章见:https://blog.csdn.net/luqingshuai_eloong/article/details/105194595

如果你没有关注我,可能看不到上面的文章,因为我好多文章都设置了粉丝可见,那就看原文吧!https://www.jianshu.com/p/1eae12582a31

本片文章是上一篇文章的继续,记录了指纹验证成功后如何获取你在手机系统内录入的指纹数据项,便于将指纹数据应用到app中进行诸如登录验证操作、指纹支付验证操作等!

FingerprintManager类的部分源码如下,通过阅读注释我们知道要想获取指纹数据项需要使用到getEnrolledFingerprints()方法,它有两种形式带参数和不带参数,仔细看会发现这两个方法都是被隐藏@hide了的,不能直接使用,需要使用Java的反射机制来获取改方法才可以使用。


import java.security.Signature;
import java.util.List;

import javax.crypto.Cipher;
import javax.crypto.Mac;

import static android.Manifest.permission.INTERACT_ACROSS_USERS;
import static android.Manifest.permission.MANAGE_FINGERPRINT;
import static android.Manifest.permission.USE_FINGERPRINT;

/**
 * A class that coordinates access to the fingerprint hardware.
 */
@SystemService(Context.FINGERPRINT_SERVICE)
public class FingerprintManager {
    private static final String TAG = "FingerprintManager";
    private static final boolean DEBUG = true;
    private static final int MSG_ENROLL_RESULT = 100;
    private static final int MSG_ACQUIRED = 101;
    private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
    private static final int MSG_AUTHENTICATION_FAILED = 103;
    private static final int MSG_ERROR = 104;
    private static final int MSG_REMOVED = 105;
    private static final int MSG_ENUMERATED = 106;

    //
    // Error messages from fingerprint hardware during initilization, enrollment, authentication or
    // removal. Must agree with the list in fingerprint.h
    //

    /**
     * The hardware is unavailable. Try again later.
     */
    public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;

    /**
     * Error state returned when the sensor was unable to process the current image.
     */
    public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2;

    /**
     * Error state returned when the current request has been running too long. This is intended to
     * prevent programs from waiting for the fingerprint sensor indefinitely. The timeout is
     * platform and sensor-specific, but is generally on the order of 30 seconds.
     */
    public static final int FINGERPRINT_ERROR_TIMEOUT = 3;

    /**
     * Error state returned for operations like enrollment; the operation cannot be completed
     * because there's not enough storage remaining to complete the operation.
     */
    public static final int FINGERPRINT_ERROR_NO_SPACE = 4;

    /**
     * The operation was canceled because the fingerprint sensor is unavailable. For example,
     * this may happen when the user is switched, the device is locked or another pending operation
     * prevents or disables it.
     */
    public static final int FINGERPRINT_ERROR_CANCELED = 5;

    /**
     * The {@link FingerprintManager#remove} call failed. Typically this will happen when the
     * provided fingerprint id was incorrect.
     *
     * @hide
     */
    public static final int FINGERPRINT_ERROR_UNABLE_TO_REMOVE = 6;

   /**
     * The operation was canceled because the API is locked out due to too many attempts.
     */
    public static final int FINGERPRINT_ERROR_LOCKOUT = 7;

    /**
     * Hardware vendors may extend this list if there are conditions that do not fall under one of
     * the above categories. Vendors are responsible for providing error strings for these errors.
     * @hide
     */
    public static final int FINGERPRINT_ERROR_VENDOR = 8;

    /**
     * The operation was canceled because FINGERPRINT_ERROR_LOCKOUT occurred too many times.
     * Fingerprint authentication is disabled until the user unlocks with strong authentication
     * (PIN/Pattern/Password)
     * @hide
     */
    public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9;

    /**
     * @hide
     */
    public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;

    //
    // Image acquisition messages. Must agree with those in fingerprint.h
    //

    /**
     * The image acquired was good.
     */
    public static final int FINGERPRINT_ACQUIRED_GOOD = 0;

    /**
     * Only a partial fingerprint image was detected. During enrollment, the user should be
     * informed on what needs to happen to resolve this problem, e.g. "press firmly on sensor."
     */
    public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1;

    /**
     * The fingerprint image was too noisy to process due to a detected condition (i.e. dry skin) or
     * a possibly dirty sensor (See {@link #FINGERPRINT_ACQUIRED_IMAGER_DIRTY}).
     */
    public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2;

    /**
     * The fingerprint image was too noisy due to suspected or detected dirt on the sensor.
     * For example, it's reasonable return this after multiple
     * {@link #FINGERPRINT_ACQUIRED_INSUFFICIENT} or actual detection of dirt on the sensor
     * (stuck pixels, swaths, etc.). The user is expected to take action to clean the sensor
     * when this is returned.
     */
    public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 3;

    /**
     * The fingerprint image was unreadable due to lack of motion. This is most appropriate for
     * linear array sensors that require a swipe motion.
     */
    public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 4;

    /**
     * The fingerprint image was incomplete due to quick motion. While mostly appropriate for
     * linear array sensors,  this could also happen if the finger was moved during acquisition.
     * The user should be asked to move the finger slower (linear) or leave the finger on the sensor
     * longer.
     */
    public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 5;

    /**
     * Hardware vendors may extend this list if there are conditions that do not fall under one of
     * the above categories. Vendors are responsible for providing error strings for these errors.
     * @hide
     */
    public static final int FINGERPRINT_ACQUIRED_VENDOR = 6;
    /**
     * @hide
     */
    public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;

    private IFingerprintService mService;
    private Context mContext;
    private IBinder mToken = new Binder();
    private AuthenticationCallback mAuthenticationCallback;
    private EnrollmentCallback mEnrollmentCallback;
    private RemovalCallback mRemovalCallback;
    private EnumerateCallback mEnumerateCallback;
    private CryptoObject mCryptoObject;
    private Fingerprint mRemovalFingerprint;
    private Handler mHandler;

    private class OnEnrollCancelListener implements OnCancelListener {
        @Override
        public void onCancel() {
            cancelEnrollment();
        }
    }

    private class OnAuthenticationCancelListener implements OnCancelListener {
        private CryptoObject mCrypto;

        public OnAuthenticationCancelListener(CryptoObject crypto) {
            mCrypto = crypto;
        }

        @Override
        public void onCancel() {
            cancelAuthentication(mCrypto);
        }
    }
  ... 
  ...
  ...
    /**
     * 获取录入的指纹模板列表
     * Obtain the list of enrolled fingerprints templates.
     * 返回当前指纹项列表
     * @return list of current fingerprint items
     *
     * @hide
     */
    @RequiresPermission(USE_FINGERPRINT)
    public List getEnrolledFingerprints(int userId) {
        if (mService != null) try {
            return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        return null;
    }

   /**
     * 获取录入的指纹模板列表
     * Obtain the list of enrolled fingerprints templates.
     * 返回当前指纹项列表
     * @return list of current fingerprint items
     *
     * @hide
     */
    @RequiresPermission(USE_FINGERPRINT)
    public List getEnrolledFingerprints() {
        return getEnrolledFingerprints(UserHandle.myUserId());
    }

  ...
  ...

}

getEnrolledFingerprints()方法的返回值是一个指纹项的列表List ,这个Fingerprint类定义了什么呢?来看源码:

看注释:Container for fingerprint metadata.意思指这个类是指纹元数据容器。这些数据包括:

    private CharSequence mName; //指纹的名称,比如你录入手机系统时的指纹1、指纹2等
    private int mGroupId;    //某个指纹在录入系统时,被放在哪个组的ID
    private int mFingerId;    //手机的ID,也就是指纹的ID
    private long mDeviceId; //指纹录入的手机设备的ID

我们要获取的也就是上面的数据!

/*
 * Copyright (C) 2015 The Android Open Source Project
 */
package android.hardware.fingerprint;

import android.os.Parcel;
import android.os.Parcelable;

/**指纹元数据容器
 * Container for fingerprint metadata.
 * @hide
 */
public final class Fingerprint implements Parcelable {
    private CharSequence mName;
    private int mGroupId;
    private int mFingerId;
    private long mDeviceId; // physical device this is associated with

    public Fingerprint(CharSequence name, int groupId, int fingerId, long deviceId) {
        mName = name;
        mGroupId = groupId;
        mFingerId = fingerId;
        mDeviceId = deviceId;
    }

    private Fingerprint(Parcel in) {
        mName = in.readString();
        mGroupId = in.readInt();
        mFingerId = in.readInt();
        mDeviceId = in.readLong();
    }

    /**获取给定指纹的可读名称。
     * Gets the human-readable name for the given fingerprint.
     * @return name given to finger
     */
    public CharSequence getName() { return mName; }

    /**获取特定设备的手指id。设置使用该id将名称映射到特定的指纹模板。
     * Gets the device-specific finger id.  Used by Settings to map a name to a specific fingerprint template.
     * @return device-specific id for this finger
     * @hide
     */
    public int getFingerId() { return mFingerId; }

    /**获取指纹被录入的特定组的ID
     * Gets the group id specified when the fingerprint was enrolled.
     * @return group id for the set of fingerprints this one belongs to.
     * @hide
     */
    public int getGroupId() { return mGroupId; }

    /**获取指纹所属的设备ID
     * Device this fingerprint belongs to.
     * @hide
     */
    public long getDeviceId() { return mDeviceId; }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel out, int flags) {
        out.writeString(mName.toString());
        out.writeInt(mGroupId);
        out.writeInt(mFingerId);
        out.writeLong(mDeviceId);
    }

    public static final Parcelable.Creator CREATOR
            = new Parcelable.Creator() {
        public Fingerprint createFromParcel(Parcel in) {
            return new Fingerprint(in);
        }

        public Fingerprint[] newArray(int size) {
            return new Fingerprint[size];
        }
    };
};

因为getEnrolledFingerprints()方法返回值是:List ,所以当我们通过反射机制调用完改该方法时会获得一个内部元素都是Fingerprint对象的的列表(即这个列表的item项就是Fingerprint对象),这个对象就是指纹元数据容器对象。知道了这点对于下面的反射代码就好理解了,暂且将获取指纹数据的反射代码放在指纹验证成功时的回调方法里:

                @Override
                public void onSucceeded() {
                    //获取指纹验证系统服务:指纹管理器对象(我们要反射获取的就是这个类里的方法getEnrolledFingerprints())
                    FingerprintManager fingerprintManager = mActivity.getSystemService(FingerprintManager.class);
                    try {
                      //获取FingerprintManager类中的getEnrolledFingerprints()方法,返回值是一个Method对象
                      Method getEnFingerMethod = FingerprintManager.class.getDeclaredMethod("getEnrolledFingerprints");
                      //通过这个Method对象调用它的invoke()方法,来实现对getEnrolledFingerprints()的调用,相当于fingerprintManager.getEnrolledFingerprints(),注意这里的返回值应该是List类型,这里用Object接收指纹项列表
                      Object fingerListObj = getEnFingerMethod.invoke(fingerprintManager);
                      //如果指纹项列表不为空,则遍历指纹项列表
                      if(fingerListObj!=null){
                          for(int i=0;i<((List)fingerListObj).size();i++){
                              //指纹项列表里获得的就是Fingerprint类型的指纹项对象了,用Object接收,注意Fingerprint类型对象在下面的反射调用中需要使用
                              Object fingerPrintItem = ((List) fingerListObj).get(i);
                              //继续通过反射机制获取Fingerprint类里的4个方法
                              Class clazz = Class.forName("android.hardware.fingerprint.Fingerprint");
                              //获取要使用的4个方法,返回的是Method对象
                              Method getName = clazz.getDeclaredMethod("getName");
                              Method getFingerId = clazz.getDeclaredMethod("getFingerId");
                              Method getGroupId = clazz.getDeclaredMethod("getGroupId");
                              Method getDeviceId = clazz.getDeclaredMethod("getDeviceId");
                              //对4个方法的调用,相当于fingerPrintItem.getName()、fingerPrintItem.getGroupId()等
                              Log.d("HomeHeadBarBiometric","指纹"+i+"的名字:"+getName.invoke(fingerPrintItem)+
                                                                           " 指纹库ID:"+getGroupId.invoke(fingerPrintItem)+
                                                                           " 指纹ID:"+getFingerId.invoke(fingerPrintItem)+
                                                                           " 设备的ID:"+getDeviceId.invoke(fingerPrintItem));
                          }
                      }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    Toast.makeText(mActivity, "指纹验证成功了!", Toast.LENGTH_SHORT).show();
                }

下面是代码的验证:两次反射都成功了第一次是获取FingerprintManager类中的getEnrolledFingerprints()方法,第二次是获取Fingerprint类里的4个方法getName()、getFingerId()、getGroupId()、getDeviceId()。

Android中通过反射机制获取手机系统内部的指纹数据_第1张图片

也成功的读取到系统的指纹项列表的数据,我的系统里设置了两个指纹,指纹ID、分组ID和指纹名都获取到了,但是设备ID是0,很奇怪不应该是一组字串啥的吗?我换了一个真机测试设备ID还是0,不知为啥?有懂的大神可以评论一下:

Android中通过反射机制获取手机系统内部的指纹数据_第2张图片

下面就是最关键的那四个方法的Log()输出,说明我们可以使用这些api了,我在手机系统里又添加了两个指纹,重新起了个指纹名,所以应该是4个:

进一步的使用你可以结合具体业务处理。有机会再补充! 

你可能感兴趣的:(android)