LoginSignup
18
12

More than 5 years have passed since last update.

指紋認証APIのエラーハンドリングで気をつけること

Last updated at Posted at 2015-12-15

概要

株式会社 Zaim で提供している家計簿アプリ Zaim では、12/16(水)にアプリの画面ロック機能の方法として指紋認証を追加しました。

capture.png

パスワードによるロックに比べて、とても使いやすいのでぜひ触ってみてください。(Android 6.0 以上の端末でのみ利用可能です。)

今回はこの機能の開発中にエラーハンドリングの部分でハマったので、注意点をまとめてみました。

指紋認証 API について

指紋認証APIについては、公式ブログおよび(手前味噌ですが)以下のブログなどで紹介されていますので、ここでは使い方などの説明は省きます。

また Google のサンプルコードも公開されています。

指紋センサーとのやり取り

指紋センサーによる読み取りを準備(warm up)するには、 FingerprintManager#authenticate() をコールします。

このメソッドがコールされた後、指紋センサーでスキャンすることが出来るようになります。この状態は、 AuthenticationCallback クラスの onAuthenticationError()onAuthenticationSucceeded() が呼ばれるまで維持されます。

authenticate() メソッドの Parameter は以下となっています。

  • crypto: オブジェクトの呼び出しに関連づけられる
  • cancel: 認証をキャンセルできるオブジェクト
  • flags: オプションフラグ(0をセットすべき)
  • callback: 認証イベントを受け取るオブジェクト
  • handler: callbackイベントを扱うオプションハンドラー

このうち、callback には次の4つのメソッドがあります。

  • onAuthenticationError : 以下のどれにも当てはまらない復帰不可能なエラーを検出したとき
  • onAuthenticationFailed : 指紋は読み取れたけど未登録と判断したとき
  • onAuthenticationHelp : 復帰可能なエラーを検出したとき
  • onAuthenticationSucceeded : 指紋を登録済みのものと判断したとき

エラーハンドリングが必要なケース

この中で onAuthenticationError は、以下の場合にコールされます。
1. CancellationSignal が発動したとき
2. 所定回数、指紋の読み取りに失敗したとき

Google のサンプルでは、上記1と2の発生を区別するために、以下のように mSelfCancelled というフラグで処理を分岐させています。

    // このメソッドはFragmentのonResume()で呼ばれます
    public void startListening(FingerprintManager.CryptoObject cryptoObject) {
        if (!isFingerprintAuthAvailable()) {
            return;
        }
        mCancellationSignal = new CancellationSignal();
        mSelfCancelled = false;
        mFingerprintManager
                .authenticate(cryptoObject, mCancellationSignal, 0 /* flags */, this, null);
        mIcon.setImageResource(R.drawable.ic_fp_40px);
    }

    // このメソッドはFragmentのonPause()で呼ばれます
    public void stopListening() {
        if (mCancellationSignal != null) {
            mSelfCancelled = true;
            mCancellationSignal.cancel();
            mCancellationSignal = null;
        }
    }

    @Override
    public void onAuthenticationError(int errMsgId, CharSequence errString) {
        // stopListening()が呼ばれなかったときはif文の中の処理が動きます
        if (!mSelfCancelled) {
            showError(errString);
            mIcon.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mCallback.onError();
                }
            }, ERROR_TIMEOUT_MILLIS);
        }
    }

ところが、1のケースには特殊なケースがありました。
authenticate() で指紋センサーの応答を待機しているときに、電源ボタンを押すと onPause()より早いタイミングで CancellationSignal が発動されます。

そのためサンプルコードのままだと、mSelfCancelled が false のまま onAuthenticationError() に入ってきてしまいます。

onAuthenticationError() の実装内容にもよりますが、そのことを考慮しておかないと意図しない挙動になるケースもありますので、注意した方がよさそうです。

回避するなら

電源ボタン押下による CancellationSignal 発動を考慮するのであれば、以下のように onAuthenticationError() を修正するのが簡単かと思います。

    @Override
    public void onAuthenticationError(int errMsgId, CharSequence errString) {
        // 電源ボタンを押したときなど
        if (errMsgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED) {
            return;
        }

        // stopListening()が呼ばれなかったときはif文の中の処理が動きます
        if (!mSelfCancelled) {
            showError(errString);
            mIcon.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mCallback.onError();
                }
            }, ERROR_TIMEOUT_MILLIS);
        }
    }

まとめ

onAuthenticationError()が呼ばれるケースは、

  1. CancellationSignal が発動したとき
    • 明示的に CancellationSignal#cancel() を呼ぶ
    • 指紋センサー準備中に電源ボタンを押す
  2. 所定回数、指紋の読み取りに失敗したとき

該当のリファレンス

18
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
12