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
看注释: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
@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()。
也成功的读取到系统的指纹项列表的数据,我的系统里设置了两个指纹,指纹ID、分组ID和指纹名都获取到了,但是设备ID是0,很奇怪不应该是一组字串啥的吗?我换了一个真机测试设备ID还是0,不知为啥?有懂的大神可以评论一下:
下面就是最关键的那四个方法的Log()输出,说明我们可以使用这些api了,我在手机系统里又添加了两个指纹,重新起了个指纹名,所以应该是4个:
进一步的使用你可以结合具体业务处理。有机会再补充!