溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Android指紋識(shí)別API講解,一種更快更好的用戶體驗(yàn)

發(fā)布時(shí)間:2020-10-23 13:19:35 來源:腳本之家 閱讀:150 作者:guolin 欄目:移動(dòng)開發(fā)

我發(fā)現(xiàn)了一個(gè)比較怪的現(xiàn)象。在iPhone上使用十分普遍的指紋認(rèn)證功能,在Android手機(jī)上卻鮮有APP使用,我簡單觀察了一下,發(fā)現(xiàn)Android手機(jī)上基本上只有支付寶、微信和極少APP支持指紋認(rèn)證功能,就連銀行和金融類的應(yīng)用都基本不支持,甚至很多開發(fā)者都不知道Android系統(tǒng)是有指紋認(rèn)證的官方API的。

Android指紋識(shí)別API講解,一種更快更好的用戶體驗(yàn)

事實(shí)上,Android從6.0系統(tǒng)開始就支持指紋認(rèn)證功能了,但是指紋功能還需要有硬件支持才行,而Android手機(jī)的硬件都是由各廠商生產(chǎn)的,手機(jī)檔次也參差不齊,因此不能像iPhone那樣保證所有的手機(jī)都是支持指紋認(rèn)證功能的。所以,可能很多開發(fā)者就覺得,即使做了指紋認(rèn)證功能,也無法兼容所有的手機(jī),還是要配合圖案解鎖或密碼等功能一起使用才行,那么索性就只用圖案和密碼好了,一勞永逸。

看似這樣解釋好像也合情合理,但其實(shí)受傷的是數(shù)以億計(jì)的Android手機(jī)用戶。明明有更輕松更快捷的使用方式,卻因?yàn)锳PP不予支持,最終只能使用更加原始和笨拙的方式。在國內(nèi),絕大多數(shù)Android手機(jī)的指紋認(rèn)證功能都僅僅只局限于用來解鎖手機(jī)而已,很少有使用到APP的功能邏輯當(dāng)中。

其實(shí)將指紋認(rèn)證功能使用到APP的功能邏輯當(dāng)中是有很多功能場景的,比如說金融銀行類APP可以使用指紋認(rèn)證來快速登錄,應(yīng)用商店類APP可以使用指紋認(rèn)證來下載安裝軟件,股票證券類APP可以使用指紋認(rèn)證來操作和交易等等。

雖然有了應(yīng)用場景,還有很多開發(fā)者可能會(huì)擔(dān)心,指紋認(rèn)證功能實(shí)現(xiàn)起來會(huì)不會(huì)很復(fù)雜?因?yàn)楫吘怪С值脑O(shè)備有限,還要配合圖案和密碼來使用才行,如果實(shí)現(xiàn)起來非常復(fù)雜,又只能支持部分設(shè)備的話,那投入產(chǎn)出比就太低了,或許這也是很多APP不肯去實(shí)現(xiàn)指紋認(rèn)證功能的原因。這里我不得不說,Android官方提供的指紋認(rèn)證Demo的確是挺復(fù)雜的,看著讓人望而卻步。但是大家不用擔(dān)心,本篇文章中我會(huì)帶著大家一起去實(shí)現(xiàn)一個(gè)最簡版的指紋認(rèn)證Demo,直接復(fù)制粘貼本文中的代碼到大家各自的項(xiàng)目中,即可一步集成指紋認(rèn)證功能。

那么話不多說,首先新建一個(gè)FingerprintTest項(xiàng)目,并選擇添加一個(gè)Empty Activity。然后修改activity_main.xml中的代碼,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="已進(jìn)入App主界面"
    android:textSize="18sp"
    android:layout_gravity="center"
    />
</FrameLayout>

這里我們修改了MainActivity中的布局文件,在界面上添加了一個(gè) 已進(jìn)入App主界面 的TextView,待會(huì)在指紋認(rèn)證通過之后,就會(huì)讓APP跳轉(zhuǎn)到此界面。

接下來我們開始編寫指紋認(rèn)證界面,新建fingerprint_dialog.xml,代碼如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:orientation="vertical"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
  <ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center_horizontal"
    android:src="@drawable/ic_fp_40px"
    />
  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_marginTop="20dp"
    android:text="請(qǐng)驗(yàn)證指紋解鎖"
    android:textColor="#000"
    android:textSize="16sp"
    />
  <TextView
    android:id="@+id/error_msg"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:layout_marginTop="5dp"
    android:maxLines="1"
    android:textSize="12sp"
    android:textColor="#f45"
    />
  <View
    android:layout_width="match_parent"
    android:layout_height="0.5dp"
    android:layout_marginTop="10dp"
    android:background="#ccc"
    />
  <TextView
    android:id="@+id/cancel"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:gravity="center"
    android:text="取消"
    android:textColor="#5d7883"
    android:textSize="16sp"
    />
</LinearLayout>

這是一個(gè)非常簡易的指紋認(rèn)證界面,相信沒什么需要解釋的地方。界面大致樣式如下圖所示:

Android指紋識(shí)別API講解,一種更快更好的用戶體驗(yàn)

注意,通常為了讓用戶清楚的知道現(xiàn)在需要進(jìn)行指紋認(rèn)證,Google官方建議最好使用一個(gè)通用的指紋圖標(biāo),而不應(yīng)該由各APP制作自己的指紋圖標(biāo)。為此,Google也特意提供了一套指紋認(rèn)證的組圖。

接著我們創(chuàng)建一個(gè)FingerprintDialogFragment類,并讓它繼承自DialogFragment,用于作為提示用戶進(jìn)行指紋認(rèn)證的對(duì)話框,代碼如下所示:

@TargetApi(23)
public class FingerprintDialogFragment extends DialogFragment {
  private FingerprintManager fingerprintManager;
  private CancellationSignal mCancellationSignal;
  private Cipher mCipher;
  private LoginActivity mActivity;
  private TextView errorMsg;
  /**
   * 標(biāo)識(shí)是否是用戶主動(dòng)取消的認(rèn)證。
   */
  private boolean isSelfCancelled;
  public void setCipher(Cipher cipher) {
    mCipher = cipher;
  }
  @Override
  public void onAttach(Context context) {
    super.onAttach(context);
    mActivity = (LoginActivity) getActivity();
  }
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    fingerprintManager = getContext().getSystemService(FingerprintManager.class);
    setStyle(DialogFragment.STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog);
  }
  @Nullable
  @Override
  public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.fingerprint_dialog, container, false);
    errorMsg = v.findViewById(R.id.error_msg);
    TextView cancel = v.findViewById(R.id.cancel);
    cancel.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        dismiss();
        stopListening();
      }
    });
    return v;
  }
  @Override
  public void onResume() {
    super.onResume();
    // 開始指紋認(rèn)證監(jiān)聽
    startListening(mCipher);
  }
  @Override
  public void onPause() {
    super.onPause();
    // 停止指紋認(rèn)證監(jiān)聽
    stopListening();
  }
  private void startListening(Cipher cipher) {
    isSelfCancelled = false;
    mCancellationSignal = new CancellationSignal();
    fingerprintManager.authenticate(new FingerprintManager.CryptoObject(cipher), mCancellationSignal, 0, new FingerprintManager.AuthenticationCallback() {
      @Override
      public void onAuthenticationError(int errorCode, CharSequence errString) {
        if (!isSelfCancelled) {
          errorMsg.setText(errString);
          if (errorCode == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT) {
            Toast.makeText(mActivity, errString, Toast.LENGTH_SHORT).show();
            dismiss();
          }
        }
      }
      @Override
      public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
        errorMsg.setText(helpString);
      }
      @Override
      public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
        Toast.makeText(mActivity, "指紋認(rèn)證成功", Toast.LENGTH_SHORT).show();
        mActivity.onAuthenticated();
      }
      @Override
      public void onAuthenticationFailed() {
        errorMsg.setText("指紋認(rèn)證失敗,請(qǐng)?jiān)僭囈淮?);
      }
    }, null);
  }
  private void stopListening() {
    if (mCancellationSignal != null) {
      mCancellationSignal.cancel();
      mCancellationSignal = null;
      isSelfCancelled = true;
    }
  }
}

說了是實(shí)現(xiàn)一個(gè)最簡版的指紋認(rèn)證Demo,因此這里的代碼也都是非常簡單的,基本上就是一個(gè)Fragment類的最普通實(shí)現(xiàn),下面我?guī)Т蠹液唵谓馕鲆幌隆?/p>

首先setCipher()方法用于接受一個(gè)Cipher對(duì)象,這個(gè)參數(shù)在待會(huì)進(jìn)行指紋認(rèn)證的時(shí)候會(huì)用到。

接下來幾個(gè)生命周期方法都很簡單,在onAttach()方法中獲取了Activity的實(shí)例,在onCreate()方法獲取了FingerprintManager的實(shí)例,在onCreateView()方法中加載了我們剛剛創(chuàng)建的fingerprint_dialog.xml布局,都是一些常規(guī)操作。

緊接著重點(diǎn)的要來了,在onResume()方法中調(diào)用了startListening()方法開始指紋認(rèn)證監(jiān)聽,在onPause()方法中調(diào)用了stopListening()方法停止指紋認(rèn)證監(jiān)聽。為什么要這么做呢?因?yàn)橹讣y傳感器和攝像頭類似,是不能多個(gè)程序同時(shí)使用的,因此任何一個(gè)程序都不應(yīng)該在非前臺(tái)時(shí)刻占用著指紋傳感器的資源,所以需要在onPause()方法中及時(shí)釋放資源。

那么,現(xiàn)在我們只需要把所有的目光都放在startListening()和stopListening()這兩個(gè)方法上就可以了。在startListening()方法中,調(diào)用了FingerprintManager的authenticate()方法來開啟指紋指紋監(jiān)聽。authenticate()方法接收五個(gè)參數(shù),第一個(gè)參數(shù)是CryptoObject對(duì)象,這里我們只需要將剛才傳入的Cipher對(duì)象包裝成CryptoObject對(duì)象就可以了。第二個(gè)參數(shù)是CancellationSignal對(duì)象,可以使用它來取消指紋認(rèn)證操作。第三個(gè)參數(shù)是可選參數(shù),官方的建議是直接傳0就可以了。第四個(gè)參數(shù)用于接收指紋認(rèn)證的回調(diào),上述代碼中我將所有的回調(diào)可能都進(jìn)行了界面提示,方便大家觀察。第五個(gè)參數(shù)用于指定處理回調(diào)的Handler,這里直接傳null表示回調(diào)到主線程即可。

而在stopListening()方法中的邏輯則簡單得多了,我們只需要調(diào)用CancellationSignal的cancel()方法將指紋認(rèn)證操作取消就可以了。

這樣我們就將FingerprintDialogFragment中的代碼全部完成了,這段代碼可以直接復(fù)制到任意項(xiàng)目當(dāng)中來作為指紋認(rèn)證提醒對(duì)話框。

最后,我們?cè)賮砭帉懸粋€(gè)簡單的登錄界面,整個(gè)指紋認(rèn)證過程就完整了。創(chuàng)建LoginActivity,代碼如下所示:

public class LoginActivity extends AppCompatActivity {
  private static final String DEFAULT_KEY_NAME = "default_key";
  KeyStore keyStore;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login);
    if (supportFingerprint()) {
      initKey();
      initCipher();
    }
  }
  public boolean supportFingerprint() {
    if (Build.VERSION.SDK_INT < 23) {
      Toast.makeText(this, "您的系統(tǒng)版本過低,不支持指紋功能", Toast.LENGTH_SHORT).show();
      return false;
    } else {
      KeyguardManager keyguardManager = getSystemService(KeyguardManager.class);
      FingerprintManager fingerprintManager = getSystemService(FingerprintManager.class);
      if (!fingerprintManager.isHardwareDetected()) {
        Toast.makeText(this, "您的手機(jī)不支持指紋功能", Toast.LENGTH_SHORT).show();
        return false;
      } else if (!keyguardManager.isKeyguardSecure()) {
        Toast.makeText(this, "您還未設(shè)置鎖屏,請(qǐng)先設(shè)置鎖屏并添加一個(gè)指紋", Toast.LENGTH_SHORT).show();
        return false;
      } else if (!fingerprintManager.hasEnrolledFingerprints()) {
        Toast.makeText(this, "您至少需要在系統(tǒng)設(shè)置中添加一個(gè)指紋", Toast.LENGTH_SHORT).show();
        return false;
      }
    }
    return true;
  }
  @TargetApi(23)
  private void initKey() {
    try {
      keyStore = KeyStore.getInstance("AndroidKeyStore");
      keyStore.load(null);
      KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
      KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(DEFAULT_KEY_NAME,
          KeyProperties.PURPOSE_ENCRYPT |
              KeyProperties.PURPOSE_DECRYPT)
          .setBlockModes(KeyProperties.BLOCK_MODE_CBC)
          .setUserAuthenticationRequired(true)
          .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7);
      keyGenerator.init(builder.build());
      keyGenerator.generateKey();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  @TargetApi(23)
  private void initCipher() {
    try {
      SecretKey key = (SecretKey) keyStore.getKey(DEFAULT_KEY_NAME, null);
      Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
          + KeyProperties.BLOCK_MODE_CBC + "/"
          + KeyProperties.ENCRYPTION_PADDING_PKCS7);
      cipher.init(Cipher.ENCRYPT_MODE, key);
      showFingerPrintDialog(cipher);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
  private void showFingerPrintDialog(Cipher cipher) {
    FingerprintDialogFragment fragment = new FingerprintDialogFragment();
    fragment.setCipher(cipher);
    fragment.show(getFragmentManager(), "fingerprint");
  }
  public void onAuthenticated() {
    Intent intent = new Intent(this, MainActivity.class);
    startActivity(intent);
    finish();
  }
}

首先在onCreate()方法中,調(diào)用了supportFingerprint()方法來判斷當(dāng)前設(shè)備是否支持指紋認(rèn)證功能。這一點(diǎn)是非常重要的,因?yàn)楫?dāng)設(shè)備不支持指紋認(rèn)證的時(shí)候,還需要及時(shí)切換到如圖案、密碼等其他的認(rèn)證方式。

當(dāng)設(shè)備支持指紋認(rèn)證的時(shí)候,再分為兩步,第一步生成一個(gè)對(duì)稱加密的Key,第二步生成一個(gè)Cipher對(duì)象,這都是Android指紋認(rèn)證API要求的標(biāo)準(zhǔn)用法。得到了Cipher對(duì)象之后,我們創(chuàng)建FingerprintDialogFragment的實(shí)例,并將Cipher對(duì)象傳入,再將FingerprintDialogFragment顯示出來就可以了。

最后的最后,當(dāng)指紋認(rèn)證成功之后,會(huì)在FingerprintDialogFragment的回調(diào)當(dāng)中調(diào)用LoginActivity的onAuthenticated()方法,然后界面會(huì)跳轉(zhuǎn)到MainActivity,整個(gè)指紋認(rèn)證過程就此結(jié)束。

總共就這些代碼了,總體來說還是相當(dāng)簡單的,現(xiàn)在我們來運(yùn)行一下看看實(shí)際的效果吧。打開應(yīng)用之后會(huì)立刻彈出指紋認(rèn)證對(duì)話框,此時(shí)先使用錯(cuò)誤的手指來進(jìn)行認(rèn)證:

Android指紋識(shí)別API講解,一種更快更好的用戶體驗(yàn)

可以看到,當(dāng)指紋驗(yàn)證失敗的時(shí)候,會(huì)在界面上顯示相應(yīng)的錯(cuò)誤提示信息。

接下來使用正確的手指來進(jìn)行認(rèn)證:

Android指紋識(shí)別API講解,一種更快更好的用戶體驗(yàn)

OK,指紋驗(yàn)證成功,并自動(dòng)跳轉(zhuǎn)到了MainActivity界面。

這樣一個(gè)最簡版的指紋認(rèn)證Demo就此完成,大家如果想要在自己的APP中集成指紋認(rèn)證功能,只需要復(fù)制粘貼本文中的代碼就可以輕松實(shí)現(xiàn)了。

在文章的結(jié)尾我還想再補(bǔ)充幾句,雖然本文中的指紋認(rèn)證Demo實(shí)現(xiàn)過程很簡單,但是切記它是不能單獨(dú)使用的,必須要配合著圖案或其他認(rèn)證方式一起來使用,因?yàn)橐欢ㄒ峁┮粋€(gè)在設(shè)備不支持指紋情況下的其他認(rèn)證方式。

另外,比較遺憾的是,雖然是剛剛寫出來的文章,但是FingerprintManager在最新的Android 9.0系統(tǒng)上已經(jīng)被廢棄了。因?yàn)锳ndroid 9.0系統(tǒng)提供了更加強(qiáng)大的生物識(shí)別認(rèn)證功能,包括指紋識(shí)別、面部識(shí)別、甚至是虹膜識(shí)別等等,因此僅僅只能用于指紋識(shí)別的FingerprintManager已經(jīng)不能滿足新系統(tǒng)的強(qiáng)大需求了。不過大家也不用擔(dān)心,雖然被標(biāo)為廢棄,但是至少在較長一段時(shí)間內(nèi),F(xiàn)ingerprintManager還是可以正常使用的。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)億速云的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI