日々の記録

SNS は無限に時間を溶かすのでやらないことにした

API Level 29 で生態(指紋)認証(Biometric Authentication)の画面を作ってみる

なんかアプリの起動時にポンって指紋認証の画面が出てきて、指紋認証できたら格好良いやん?IDとPassword入力でログインってなんかダサいし、そもそもAndroid Deviceってマルチユーザーで使用しないし、Web applicationのようにIDとPasswordの認証機構作るのって面倒やん?違うか?

ということでAPIいくつからから忘れましたが、いまさら調べるのも億劫なんで調べませんが、どうもGoogleさんが認証機構用の標準APIとテンプレートを作ってくれたようなので、これを利用しない手はないでしょう。

と言うても、Android Developers Guide のチュートリアルにならって作ってみただけです。
これね↓

Show a biometric authentication dialog

ちなみに、このチュートリアル日本語版だと動作させるまでにはかなりハードル高いので、英語版で読むことがお勧めです。それじゃやってみましょう。

Biometric Authentication の概要

概要として以下のことを実施する必要があります。

  1. DeviceのBiometric機能を利用するため、AndroidManifestにuser permission宣言の追加
  2. Biometricのライブラリを利用するため、gradleにライブラリを追加
  3. DeviceのハードウェアにBiometric機能が付いているか、指紋が登録済みかなどのチェック
  4. 指紋認証画面の表示

こんだけ。ちょー簡単なのでやってみましょう!

1. DeviceのBiometric機能を利用するため、AndroidManifestにuser permission宣言の追加

Device上の機能を使うためにマニフェストファイルに、Biometoricのpermissionを宣言しておきましょう。

app/src/main/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
...
    //USE_BIOMETRICのPermissionを追加!
    <uses-permission android:name="android.permission.USE_BIOMETRIC"/> 

    <application
        android:allowBackup="true"
...
    </application>

</manifest>

2. Biometricのライブラリを利用するため、gradleにライブラリを追加

チュートリアルBiometricandroidx.biometric:biometricのライブラリを使用するのでModuleのgradleにライブラリを追加しておきましょう。

app/build.gradle

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
...
    implementation 'androidx.biometric:biometric:1.0.1'
...

とりあえず新しめなバージョンを指定しています。個人的には直接Gradleのファイルに記述するよりGUIから検索して追加する方が、最新版のライブラリバージョンを確認できるので好きです。

  1. Move to Project Structure > Dependancies > Modules > app
  2. Click + button
  3. Select Library Dependency

f:id:techsapp:20200406234021p:plain

  1. Enter biometric at search form in Add Library Dependency
  2. Select implementation in Step 2 and click OK

f:id:techsapp:20200406234118p:plain

ここで注意ですが、API 29で使うライブラリは"androidx.biometric"です。なので、ソースコード上で利用する場合も"androidx.biometric"が利用されていることを確認してください。似たようなライブラリ名でほとんど使い方の同じライブラリがあるので、うっかり別のライブラリを使っているとBiometricManager.fromが宣言できなくてハマったりします。しかもBiometricManagerのキーワードでググるBiometricManager.fromのスタティックメソッドのない類似クラスが出てくるので尚更混乱します。API29でBiometric使うなら、'androidx.biometric`!!絶対!!

チュートリアル間違ってるやん!ってキーボードクラッシャーしそうなところで気付きました。大概は人が間違っているのではなく、99%自分がおっちょこちょいだったりするわけです(ゝω・)テヘペロぺろ

3. DeviceのハードウェアにBiometric機能が付いているか、指紋が登録済みかなどのチェック

はい、あとは簡単。 BiometricManagerを使ってハードウェアデバイスの状態と、指紋情報の登録状況を確認します。

BiometricManager.from()のスタティックメソッドにアクティビティを渡して、'BiometricManager'オブジェクトを生成します。'BiometricManager'のcanAuthenticate()では、デバイスの状況を確認し、生体認証ができるかどうかチェックしてくれます。

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // importしているのが違うライブラリだと、BiometricManager.fromが解決できないし、なんとなくそれっぽく使えちゃうので気付きにくい!!
        BiometricManager biometricManager = BiometricManager.from(MainActivity.this);
        switch (biometricManager.canAuthenticate()){

            //No error detected.
            case BiometricManager.BIOMETRIC_SUCCESS:
                Log.d("Biometric TAG", "App can authenticate using biometrics.");

            //There is no biometric hardware.
            case BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE:
                Log.d("Biometric TAG", "No biometric features available on this device.");

           //The hardware is unavailable.
            case BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE:
                Log.d("Biometric TAG", "Biometric features are currently unavailable.");

           //The user does not have any biometrics enrolled.
            case BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED:
                Log.d("Biometric TAG", "The user hasn't associated any biometric credentials with their account.");
        }

4. 指紋認証画面の表示

BiometricPrompt指紋認証の認証画面を作っていきます。 BiometricPromptのコンストラクタにBiometricPrompt.AuthenticationCallbackのコールバック関数(Javaでもコールバック関数って言うんだっけ?)を指定して、指紋認証の成功時、失敗時などの動作を指定します。

    private Executor executor;
    private BiometricPrompt biometricPrompt;

...
        executor = ContextCompat.getMainExecutor(MainActivity.this);
        biometricPrompt = new BiometricPrompt(MainActivity.this, executor, new BiometricPrompt.AuthenticationCallback() {
            @Override
            public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
                super.onAuthenticationError(errorCode, errString);
                Toast.makeText(getApplicationContext(), "Authentication error: " + errString, Toast.LENGTH_LONG).show();
            }

            @Override
            public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
                super.onAuthenticationSucceeded(result);
                Toast.makeText(getApplicationContext(), "Authentication succeeded!", Toast.LENGTH_LONG).show();
            }

            @Override
            public void onAuthenticationFailed() {
                super.onAuthenticationFailed();
                Toast.makeText(getApplicationContext(), "Authentication failed...", Toast.LENGTH_LONG).show();
            }
        });

BiometricPrompt.PromptInfoには、指紋認証画面に表示されるタイトルなどをセットしていきます。

        private BiometricPrompt.PromptInfo promptInfo;

        promptInfo = new BiometricPrompt.PromptInfo.Builder()
                .setTitle("Biometric login for my app")
                .setSubtitle("Log in using your biometric credential")
                .setNegativeButtonText("Use account password")
                .build();

あとは、指紋認証画面を表示させたいタイミングでBiometricPrompt.authenticateをコールすれば認証画面がポンっと表示されます。

        biometricPrompt.authenticate(promptInfo);

ふーぅっ!かんたーんっ!