In this paper, starting from vivo Internet technology WeChat public links: mp.weixin.qq.com/s/EHomjBy4T… Author: Sun Daxiang

Since Android 6.0, Google has provided open API related to fingerprint identification. Through this article, developers can access the basic functions of fingerprint verification, and provide system applications based on fingerprint verification function extension, such as fingerprint verification login function core flow chart and key code analysis.

First, the foundation

Since Android 6.0, Android system supports fingerprint recognition function, fingerprint recognition API is mainly FingerprintManager.

The common methods provided by FingerprintManager are to determine whether the system supports fingerprints, whether a fingerprint has been recorded in the system, to initiate fingerprint verification, to cancel the verification, and to call back the verification result.

The hiding methods include obtaining the fingerprint list in the system and obtaining the fingerprint ID. However, after Android 9.0, Google officially does not recommend using the FingerprintManager interface

Instead of BiometricPrompt, because the BiometricPrompt interface cannot customize the pop-up style and has not been uniformly used by all lines of business, the access method of this interface will be introduced below:

1. Effect demonstration and demo structure introduction

1.1 Fingerprint verification Effect

1.2 Code structure of Demo

1.3 Core Classes

Because the fingerprint function has adaptation problems in Android 6.0 and Android 9.0, FingerprintVersionM and FingerprintVersionP are used to encapsulate different Android versions respectively.

FingerprintManagerWrapper FIngerpintVersionM, FingerprintVersionP implements IFingerprintInterface interface, Unified by startAuth() cancelAuth method.

Enable or disable fingerprint authentication

Core class description:

Diagram of the core class:


2. Access process

After the following six steps are performed, the fingerprint verification function can be used normally, including whether the system supports fingerprint verification, whether fingerprint is recorded, enabling fingerprint verification, disabling fingerprint verification, and callback fingerprint verification results for Android 6.0 and Android 9.0.

Step 1: Add the following fingerprint permissions to the manifest file. For details, see Section 2.1

Step 2: Combination judgment: whether the current system version supports the fingerprint function and whether the fingerprint has been recorded in ROM, see section 2.5 and 2.6 for the judgment method

Step 3: use FingerprintManagerWrapper object call IFingerprintInterface startAuth method in a unified interface to pull up the fingerprint authentication method see section 2.2

Step 4: FingerprintVersionM and FingerprintVersionP implement IFingerprintInterface and enable fingerprint authentication in Android 6.0 and Android 9.0 respectively

Step 5: See Section 2.3 for the implementation code of the AuthenticationCallback interface that registers fingerprint verification success in FingerprintVersionM and FingerprintVersionP respectively

Step 6: Call onStop() in the activity lifecycle to cancel the validation interface and disable fingerprint authentication. See Section 2.4

2.1 Enabling fingerprint Users

<! -- Android 9.0 and later uses fingerprint permission --> <uses-permission Android :name="android.permission.USE_BIOMETRIC"/ > <! --> <uses-permission Android :name="android.permission.USE_FINGERPRINT"/ > <! -- Android 6.0 or above, obtain fingerprint information permission, system application promotion section will use --> <uses-permission Android :name="android.permission.MANAGE_FINGERPRINT"/>Copy the code


2.2 Enabling fingerprint Verification

FingerprintVersionP and FingerprintVersionM are compatible with Android 6.0 and Android9.0 fingerprint verification, respectively. FingerprintManagerWrapper FingerprintVersionP, FingerprintVersionM unified IFingerprintInterface interface

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(); }}} /** * Check whether the system supports fingerprints and whether the system has recorded fingerprints. Then call fingerprint authentication unified method * / public void startAuth (FingerprintManagerWrapper. FingerVerifyResultListener listener) {Log. I (TAG,"------startFingerAuthenticate() enter --------"); // Determine whether the fingerprint device is currently availableif(! isHardwareDetected()) { Log.e(TAG,"------hardware detected!!! -- -- -- -- -- -- -- --");
        return; } // Check whether there are any fingerprintsif(! 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(); }Copy the code


The Android 6.0 fingerprint verification code in FingerprintVersionM is as follows:

public class FingerprintVersionM implements IFingerprintInterface { @Override public void StartAuth (FingerprintManagerWrapper FingerVerifyResultListener listener) {/ / cancel the fingerprint verification CancellationSignal mCancellationSignal = new CancellationSignal(); MyAuthenticationCallback authenticationCallback = new MyAuthenticationCallback(); /** * Parameters: * CryptoObject - Add CryptoObject * CancellationSignal - to cancel fingerprint validation, if you want to cancel manually, call the cancel method * int - meaningless, Default to pass 0 * AuthenticationCallback - result of callback validation, * Handler - pass null, such success, failure, create a Handler on the main thread by default the message * / mFingerprintManager authenticate (null, mCancellationSignal, 0, authenticationCallback, null); // Call the identification interface}}Copy the code


Implementation of Android 9.0 fingerprint verification code in FingerprintVersionP:

public class FingerprintVersionP implements IFingerprintInterface { @Override public void StartAuth (FingerprintManagerWrapper FingerVerifyResultListener listener) {/ / used to cancel the fingerprint verification CancellationSignal mCancellationSignal = new CancellationSignal(); AuthenticationCallback mAuthenticationCallback = new BiometricPromptAuthenticationCallback() {} / / validation mBiometricPrompt. Authenticate (mCancellationSignal, mContext getMainExecutor (), mAuthenticationCallback); }}Copy the code


2.3 Fingerprint Verification Callback

// Fingerprint verification fails callback method onAuthenticationFailed() // Fingerprint verification succeeds callback method. You can use AuthenticationResult to obtain fingerprint information and fingerprint name. Fingerprint id onAuthenticationSucceeded (AuthenticationResult result) / / fingerprint authentication failed callback,helpMsgId=1006,helpString=6 Finger removed too soon onAuthenticationHelp(inthelpMsgId, CharSequence helpString) // Fingerprint automatically closes after multiple attempts. ErrMsgId =5,errString= The fingerprint operation is canceled. onAuthenticationError(int errMsgId, CharSequence errString)Copy the code


/ / android9.0 below using android. Hardware. Fingerprint. FingerprintManager. AuthenticationCallback/use/android 9.0 above android.hardware.biometrics.BiometricPrompt.AuthenticationCallback private class MyAuthenticationCallback extends AuthenticationCallback { @Override public voidonAuthenticationFailed() {/ / fingerprint authentication failed callback methods} @ Override public void onAuthenticationSucceeded (AuthenticationResult result) {/ / fingerprint verification success callback methods, } @override public void onAuthenticationHelp(int) {Override public void onAuthenticationHelp(int)helpMsgId, CharSequence helpString) {// Fingerprint verification failed callback,helpMsgId=1006,helpString=6 Finger removed too fast} @Override public void onAuthenticationError(int errMsgId, CharSequence errString) {// Fingerprint is automatically disabled after multiple attempts. ErrMsgId =5,errString= The fingerprint operation is canceled. }}Copy the code


2.4 Disabling Fingerprint Verification

Disable fingerprint verification in the activity’s onStop method

// If the home button is overwritten by other pages, you need to close it and pull @Override protected void againonStop() { super.onStop(); / / tuning up fingerprint authentication methods above, the incoming object CancellationSignal mCancellationSignal. Cancel (); }Copy the code


2.5 Checking whether the current system supports fingerprints

Although not recommended for Android 9.0 or later, FingerprintManager is available on all Versions of Google systems, and 9.0 or later does not provide an API to determine whether fingerprinting is supported or not

/** * Check whether the current fingerprint function is available ** @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;
}Copy the code


2.6 Checking whether fingerprints are recorded in the system

Use FingerprintManager to check whether a fingerprint has been recorded in the system

/** * Check whether fingerprints have been recorded ** @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;
}Copy the code


The above basic chapter introduces the public API provided by Google, which basically meets the function of fingerprint verification.

The following describes how to obtain the fingerprint ID and fingerprint list to meet other service requirements, such as account login and payment.

Two, system application promotion

1. Obtain the fingerprint ID

After the success of the fingerprint verification, according to the FingerprintManager. AuthenticationResult object can be obtained by reflection to the fingerprint id (fingerprint id is hidden attribute), you need to add permissions

Android. Permission. MANAGE_FINGERPRINT, there are differences between the Fingerprint in the android 6.0 and Android9.0 object:

Fingerprint in Android 6.0 contains the Fingerprint ID attribute mFingerprintId and the public method getFingerprintId

Fingerprint in Android 9.0 class inheritance BiometricAuthenticator Identifer, also in such id and fingerprints, attributes, called mBiometricId method for getBiometricId

(Android 9.0 related class dependencies)

(Android6.0 Class Diagram dependencies)

Therefore, the method of obtaining Fingerprint object and Fingerprint ID using reflection needs to be adapted to Android 6.0 and Android 9.0. The detailed method is as follows:

In Android 6.0, the AuthenticationResult reflection obtains the Fingerprint object, and the Fingerprint object getFingerId obtains the Fingerprint ID

On Android 9.0 or later, Fingerprint information is stored in the parent class of Fingerprint. Therefore, you need to use clzz.getSuperclass() to obtain the parent class object and use the reflection method getBiometricId to obtain the Fingerprint 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;
}Copy the code


2. Obtain the fingerprint list in the system

The system records the fingerprint, and the fingerprint information can be obtained from the fingerprint list through reflection method

Get fingerprint list after reflection JSON string:

Android6.0: [{"mDeviceId": 0."mFingerId": 1147763748,"mGroupId": 0."mName":1 "fingerprint"}, {"mDeviceId": 0."mFingerId": 412764029,"mGroupId": 0."mName":2 "fingerprint"[{}] android9.0:"mGroupId": 0."mBiometricId": - 714471355."mDeviceId": 517254275456,"mName":1 "fingerprint"}, {"mGroupId": 0."mBiometricId": - 803114291."mDeviceId": 517254275456,"mName":2 "fingerprint"}]Copy the code


The detailed reflection code is as follows:

1: Convert the fingerprint list reflected json string into an AccountFingerprint object using gson (compatible with Android6.0 to 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 "fingerprint"}, {"mDeviceId": 0."mFingerId": 412764029,"mGroupId": 0."mName":2 "fingerprint"/ / android10.0 [{}]"mGroupId": 0."mBiometricId": - 714471355."mDeviceId": 517254275456,"mName":1 "fingerprint"}, {"mGroupId": 0."mBiometricId": - 803114291."mDeviceId": 517254275456,"mName":2 "fingerprint"}] List<AccountFingerprint> list = gson.fromJson(fingerListString, new TypeToken<List<AccountFingerprint>>() {}.getType()); 2: Reflection FingerprintManager call getEnrolledFingerprints method to obtain a list has been input fingerprint/reflection for the current user's * * * all * * @ param FM FingerprintManagerWrapper fingerprint information list * @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);
     }
   
    returnnull; } 3: custom AccountFingerprint bean compatible with Android6-Android10 // Created fingerprint 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;
}Copy the code


3. Practical Scenarios for Fingerprint Authentication (Fingerprint Login Account function)

For example: after obtaining the fingerprint ID and fingerprint list, you can realize the fingerprint login function

  1. First, obtain the fingerprint list of the device and synchronize it to the server. The server records accounts, devices, fingerprint list, and binding relationships
  2. The user uses the ID, account, and device to initiate a login request
  3. The server verifies the current account, fingerprint ID, and device, and returns the verification result

Fingerprint Login Effect


Sequence diagram of fingerprint login interaction

For more content, please pay attention to vivo Internet technology wechat public account

Note: To reprint the article, please contact our wechat account: Labs2020.