一篇文章教你從入門到精通 Google 指紋驗證功能

本文首發於 vivo互聯網技術 微信公衆號
連接:mp.weixin.qq.com/s/EHomjBy4T…
做者:Sun Daxiangandroid

Google 從 Android 6.0開始,提供了開放的指紋識別相關 API,經過此篇文章能夠幫助開發者接入指紋驗證的基礎功能,而且提供了系統應用基於指紋驗證的功能擴展,如指紋驗證登陸功能核心流程圖和關鍵代碼分析。json

1、基礎篇

從Android 6.0開始,Android 系統支持指紋識別功能,指紋識別的API主要是FingerprintManager。bash

FingerprintManager提供的公共方法有,判斷系統是否支持指紋,系統是否錄入過指紋,發起指紋驗證,取消驗證,驗證結果回調。服務器

隱藏方法有,獲取系統中指紋列表,獲取指紋id等信息。然而 Android 9.0之後 Google官方不推薦使用FingerprintManager 接口, 推薦使用微信

BiometricPrompt代替, 由於BiometricPrompt接口不可以自定義彈框樣式,各業務線還未統一使用,下面會介紹此接口接入方法:app

一、 效果演示和demo結構介紹

1.1 指紋驗證效果

1.2 demo的代碼結構

1.3 核心類說明

因指紋功能有Android 6.0和 Android 9.0適配問題,因此使用FingerprintVersionM和FingerprintVersionP分別實現對不一樣 Android 版本的封裝實現。ide

FingerprintManagerWrapper, FIngerpintVersionM,FingerprintVersionP都實現IFingerprintInterface接口,統一經過startAuth() cancelAuth方法。ui

調起指紋驗證和取消指紋驗證加密

核心類說明:spa

核心類的關係圖:


二、接入流程

經過下面的6步接入後,能夠正常使用指紋驗證功能,包括系統是否支持指紋,是否錄入過指紋,拉起指紋驗證,取消指紋驗證,指紋驗證結果回調,適配Android 6.0和Android 9.0。

第一步:在manifest文件中增長以下指紋權限功能 ,詳細權限見2.1章節

第二步:組合判斷,當前系統版本是否支持指紋功能,而且rom中已經錄入過指紋 ,判斷方法見2.5 和 2.6章節

第三步:使用FingerprintManagerWrapper對象調用IFingerprintInterface統一接口中startAuth方法,拉起指紋驗證功能 方法見2.2章節

第四步:FingerprintVersionM和FingerprintVersionP分別實現IFingerprintInterface接口,分別實現 Android 6.0和 Android 9.0調起指紋驗證功能

第五步:分別在FingerprintVersionM和FingerprintVersionP註冊指紋驗證成功的回調接口AuthenticationCallback 實現代碼見 2.3章節

第六步:在activity生命週期onStop()調用取消驗證接口,關閉指紋驗證功能 見2.4章節

2.1 增長指紋使用權限

<!--android 9.0及以上系統使用指紋權限 -->
<uses-permission android:name="android.permission.USE_BIOMETRIC"/>
<!--android 6.0至8.0及以上系統使用指紋權限 -->
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
<!--android 6.0及以上,獲取指紋信息權限,系統應用提高篇中會使用到 -->
<uses-permission android:name="android.permission.MANAGE_FINGERPRINT"/>複製代碼

2.2 調起指紋驗證

FingerprintVersionP和FingerprintVersionM分別兼容 Android 6.0和 Android9.0指紋驗證功能,FingerprintManagerWrapper,FingerprintVersionP,FingerprintVersionM統一實現IFingerprintInterface接口

public FingerprintManagerWrapper() {
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            mFingerprintImp = new FingerprintVersionP();
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            mFingerprintImp = new FingerprintVersionM();
        }
    }
}
/**
 * 先判斷系統是否支持指紋,系統是否錄入過指紋,再調用指紋認證統一方法
 */
public void startAuth(FingerprintManagerWrapper.FingerVerifyResultListener listener) {
    Log.i(TAG, "------startFingerAuthenticate() enter --------");
    //判斷指紋設備當前是否可使用
    if (!isHardwareDetected()) {
        Log.e(TAG, "------hardware detected!!!--------");
        return;
    }
  
    //判斷當前是否有指紋
    if (!hasEnrolledFingerprints()) {
        Log.e(TAG, "-----has no Fingerprints!!!--------");
        return;
    }
    mFingerprintImp.startAuth(listener);
}
  
  
/**
 * android6.0android9.0統一驗證和取消接口
 */
interface IFingerprintInterface {
    public void startAuth(FingerprintManagerWrapper.FingerVerifyResultListener listener);
  
    public void canceAuth();
}複製代碼

FingerprintVersionM中實現 Android 6.0指紋驗證代碼以下:

public class FingerprintVersionM implements IFingerprintInterface {
  
  
  @Override
  public void startAuth(FingerprintManagerWrapper.FingerVerifyResultListener listener) {
  
  
     //取消指紋驗證類
     CancellationSignal  mCancellationSignal = new CancellationSignal();
  
     MyAuthenticationCallback authenticationCallback = new MyAuthenticationCallback();
     /**
       * 參數說明:
       * CryptoObject - 若是須要的話能夠添加加密對象CryptoObject
       * CancellationSignal - 用來取消指紋驗證,若是想手動取消驗證,調用該參數的cancel方法
       * int - 沒意義,默認傳0
       * AuthenticationCallback -  回調驗證的結果,成功、失敗等
       * Handler - 傳null則默認建立一個在主線程上的Handler來傳遞消息
       */
     mFingerprintManager.authenticate(null, mCancellationSignal, 0, authenticationCallback, null); //調用識別接口
     }
  
  
}複製代碼

FingerprintVersionP中實現 Android 9.0指紋驗證代碼以下:

public class FingerprintVersionP implements IFingerprintInterface {
  
  
    @Override
    public void startAuth(FingerprintManagerWrapper.FingerVerifyResultListener listener) {
  
  
        //用來取消指紋驗證
        CancellationSignal mCancellationSignal = new CancellationSignal();
        //回調驗證的結果,成功、失敗等
        AuthenticationCallback mAuthenticationCallback = new BiometricPrompt.AuthenticationCallback(){}
        //開始驗證
        mBiometricPrompt.authenticate(mCancellationSignal, mContext.getMainExecutor(), mAuthenticationCallback);
    }
}複製代碼

2.3 指紋驗證回調

// 指紋驗證失敗回調方法
onAuthenticationFailed()
//指紋驗證成功回調方法 ,  有系統權限能夠經過AuthenticationResult 獲取指紋的信息,指紋名稱,指紋id等
onAuthenticationSucceeded(AuthenticationResult result)
//指紋驗證失敗回調,helpMsgId=1006,helpString=6 手指移除太快
onAuthenticationHelp(int helpMsgId, CharSequence helpString)
//指紋嘗試屢次後,指紋主動關閉。errMsgId=5,errString=指紋操做已取消。
onAuthenticationError(int errMsgId, CharSequence errString)複製代碼
// android9.0如下使用 android.hardware.fingerprint.FingerprintManager.AuthenticationCallback
//android 9.0以上使用  android.hardware.biometrics.BiometricPrompt.AuthenticationCallback
  
  
private class MyAuthenticationCallback extends AuthenticationCallback {
  
    @Override
    public void onAuthenticationFailed() {
         //指紋驗證失敗回調方法
    }
  
    @Override
    public void onAuthenticationSucceeded(AuthenticationResult result) {
        //指紋驗證成功回調方法 ,  有系統權限能夠經過AuthenticationResult 獲取指紋的信息,指紋名稱,指紋id等
    }
  
    @Override
    public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
        //指紋驗證失敗回調,helpMsgId=1006,helpString=6 手指移除太快
    }
  
  
    @Override
    public void onAuthenticationError(int errMsgId, CharSequence errString) {
        //指紋嘗試屢次後,指紋主動關閉。errMsgId=5,errString=指紋操做已取消。
    }
  
}複製代碼

2.4 取消指紋驗證

在activity的onStop方法中取消指紋驗證功能

// 屏下指紋彈框home鍵或者被其餘頁面所有覆蓋後,須要關閉,從新拉起
@Override
protected void onStop() {
    super.onStop();
    //上面調起指紋驗證方法中,傳入的CancellationSignal對象
    mCancellationSignal.cancel();
}複製代碼

2.5 判斷當前系統是否支持指紋

FingerprintManager雖然在 Android 9.0之後不推薦使用,可是Google各系統版本都支持FingerprintManager,並且9.0及以上版本暫未提供判斷是否支持指紋功能的 API

/**
 * 判斷當前指紋功能是否可用
 *
 * @return
 */
public boolean isHardwareDetected() {
    boolean isHardwareSupport = false;
    try {
        if (mFingerprintManager != null) {
            isHardwareSupport = mFingerprintManager.isHardwareDetected();
        }
    } catch (Exception e) {
        Log.e(TAG, "isHardwareDetected err ", e);
    }
    Log.e(TAG, "isHardwareDetected(), isHardwareSupport= " + isHardwareSupport);
    return isHardwareSupport;
}複製代碼

2.6 判斷系統是否錄入過指紋

同上使用FingerprintManager判斷系統是否錄入過指紋

/**
 * 判斷是否錄入過指紋
 *
 * @return
 */
public boolean hasEnrolledFingerprints() {
    boolean hasEnrolledFinger = false;
    try {
        if (mFingerprintManager != null) {
            hasEnrolledFinger = mFingerprintManager.hasEnrolledFingerprints();
        }
    } catch (Exception e) {
        Log.e(TAG, "hasEnrolledFingerprints err ", e);
    }
    Log.e(TAG, "hasEnrolledFingerprints(), hasEnrolledFinger= " + hasEnrolledFinger);
    return hasEnrolledFinger;
}複製代碼

以上基礎篇介紹了 Google提供的公共 API , 基本知足指紋驗證的功能。

下面介紹獲取指紋id和指紋列表方法,能夠知足其餘業務需求,好比賬號登陸,支付等功能。

2、系統應用提高篇

一、獲取到指紋id

指紋驗證成功後,根據FingerprintManager.AuthenticationResult 對象能夠經過反射方法獲取到指紋id(指紋id是隱藏屬性),須要添加權限

android.permission.MANAGE_FINGERPRINT, Android 6.0和 Android9.0中Fingerprint對象有差別:

Android 6.0中Fingerprint中包含有指紋id的屬性mFingerprintId和public方法getFingerprintId

Android 9.0 中Fingerprint類繼承BiometricAuthenticator.Identifer,而且指紋id也放入此類中,屬性名爲mBiometricId ,方法爲getBiometricId

(Android 9.0 相關類依賴關係)

(Android6.0類圖依賴關係)

所以使用反射獲取Fingerprint對象和指紋id方法須要適配 Android 6.0和 Android 9.0,詳細方法以下:

Android 6.0中AuthenticationResult反射獲取Fingerprint對象,Fingerprint對象getFingerId獲取到指紋id

Android 9.0以上指紋信息放在Fingerprint的父類中,因此須要經過clzz.getSuperclass()獲取父類對象,在反射方法getBiometricId獲取指紋 id

private static int getFingerId(AuthenticationResult result) {
    int fingerId = -1;
    try {
        Field field = result.getClass().getDeclaredField("mFingerprint");
        field.setAccessible(true);
        Object fingerPrint = field.get(result);
  
        Class<?> clzz = Class.forName("android.hardware.fingerprint.Fingerprint");
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
            Log.i(TAG, "-------ANDROID Q-------");
            Class<?> supClass = clzz.getSuperclass();
            Method getBiometricId = supClass.getDeclaredMethod("getBiometricId");
            fingerId = (int) getBiometricId.invoke(fingerPrint);
        } else {
            Log.i(TAG, "------- ANDROID M-P-------");
            Method getFingerId = clzz.getDeclaredMethod("getFingerId");
            fingerId = (int) getFingerId.invoke(fingerPrint);
        }
        Log.d(TAG, "fingerId=" + fingerId);
  
    } catch (Exception e) {
        Log.e(TAG, "", e);
    }
    return fingerId;
}複製代碼

二、獲取系統中指紋列表

系統錄入指紋,能夠經過反射方法獲取到指紋列表中,各指紋信息

經過反射後獲取指紋列表json字符串:

android6.0:[{"mDeviceId":0,"mFingerId":1147763748,"mGroupId":0,"mName":"指紋 1"},{"mDeviceId":0,"mFingerId":412764029,"mGroupId":0,"mName":"指紋 2"}]  
android9.0: [{"mGroupId":0,"mBiometricId":-714471355,"mDeviceId":517254275456,"mName":"指紋 1"},{"mGroupId":0,"mBiometricId":-803114291,"mDeviceId":517254275456,"mName":"指紋 2"}]複製代碼

詳細的反射代碼以下:

1: 將反射獲取的指紋列表json字符串,使用gson轉爲AccountFingerprint對象(兼容android6.0-android10.0)
   
 Gson gson = new Gson();
 Object object = getEnrolledFingerprints(mFingerprintManager);
 String fingerListString = gson.toJson(object)
 // android6.0-android9.0   [{"mDeviceId":0,"mFingerId":1147763748,"mGroupId":0,"mName":"指紋 1"},{"mDeviceId":0,"mFingerId":412764029,"mGroupId":0,"mName":"指紋 2"}]
// android10.0    [{"mGroupId":0,"mBiometricId":-714471355,"mDeviceId":517254275456,"mName":"指紋 1"},{"mGroupId":0,"mBiometricId":-803114291,"mDeviceId":517254275456,"mName":"指紋 2"}]
 List<AccountFingerprint> list = gson.fromJson(fingerListString, new TypeToken<List<AccountFingerprint>>() {}.getType());
  
  
2:反射FingerprintManager調用getEnrolledFingerprints方法獲取已錄入指紋列表
   
   
/**
 * 反射獲取當前用戶的全部指紋信息列表
 *
 * @param fm FingerprintManagerWrapper
 * @return 指紋信息列表
 */
public static Object getEnrolledFingerprints(FingerprintManager fm) {
    try {
        if (fm != null) {
            Object obj = invokeMethod(fm, "getEnrolledFingerprints");
         return obj;
         }
    } catch (Exception e) {
        VLog.e(TAG, "getEnrolledFingerprints()", e);
     }
   
    return null;
}
  
  
3: 自定義的AccountFingerprint bean,兼容android6-android10
   
   
//建立的指紋bean
public class AccountFingerprint {
   
    @SerializedName("mBiometricId")
    private int mBiometricId;
   
 @SerializedName("mFingerId")
    private int mFingerId;
   
 @SerializedName("mGroupId")
    private int mGroupId;
   
 @SerializedName("mDeviceId")
    private long mDeviceId;
   
 @SerializedName("mName")
    private String mPrintName;
}複製代碼

三、指紋認證明用場景介紹(指紋登陸賬號功能)

舉個栗子:獲取指紋id和指紋列表後能夠實現指紋登陸功能

  1. 首先獲取設備的指紋列表同步給服務器,服務器記錄賬號,設備,指紋列表,綁定關係
  2. 用戶使用指紋驗證的id + 賬號+設備發起登陸請求
  3. 服務器校驗當前賬號,指紋id,設備,是否有同步保存記錄,並返回驗證結果

指紋登陸效果


指紋登陸交互時序圖

更多內容敬請關注 vivo 互聯網技術 微信公衆號

注:轉載文章請先與微信號:Labs2020 聯繫。

相關文章
相關標籤/搜索