⌚️

TouchID と FaceID についておさらいしよう!!(AppleWatch認証はまだないけど)

2021/05/12に公開

パスコード認証、touchID認証、faceID認証…
そして、第四の認証となった AppleWatch認証。

iOS 14.5 では、まだアプリ側では使えません
とはいえ、ここらで認証についておさらいしておくのもいいかと思います。
Mac だと前から使えたよね。

info.plist に追加

最初に追加しておきましょう
NSFaceIDUsageDescription keyを追加するだけ。
Xcode上では、「Privacy - Face ID Usage Description」と表示されています。

InfoPlist.strings によるローカライズもお忘れずに。

info.plist に追加しなくても、FaceIDの許可は聞かれます。
ただ、代わりに「Face IDには対応してしない可能性があります」等のメッセージが表示されます。注意ですね。

実際に書いていく🖋

import LocalAuthentication

LocalAuthentication をインポートしておく必要があります。

どの生体認証が使えるのかチェック

iPhoneX(10)以降の端末には、TouchIDではなくFaceIDが搭載されています
biometryType は、そのデバイスが所有する生体認証を表示します。

case .touchID
touchID が使用可能。

case .faceID
faceID が使用可能。

case .none
使用できる生体認証が存在しない。

初期値は .none であり、一度 LAContext の処理に通さないと、初期値のままです。
そのため、canEvaluatePolicy を使用する必要があります

let context = LAContext()
var error: NSError?

if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
  
  switch context.biometryType {
  case .touchID:
    // touchID が使える場合
  case .faceID:
    // faceID が使える場合
  default:
    // 新たな生体認証が増えた場合、呼ばれる可能性あり
    break
  }
  
} else {
  // 生体認証が使えない場合(faceID を許可していない場合)
  print("BiometryType Error: " + (error?.localizedDescription ?? "Unknown Error"))
}

生体認証を許可していない場合は、

User has denied the use of biometry for this app.

というコードが確認できます。

なお、biometryTypeiOS 11 以降追加されました。(それ以前は touchID のみなので)
iOS 10 以前をサポートしている場合は、以下のような処理も必要ですね。

・・・
if #available(iOS 11.0, *) {
  switch context.biometryType {
  case .touchID:
    // touchID が使える場合
  case .faceID:
    // faceID が使える場合
  default:
    // 新たな生体認証が増えた場合、呼ばれる可能性あり
    break
  }
} else {
  // touchID のみ
}
・・・

認証を実行

let context = LAContext()
let localizedReason = "ロックの解除に、認証を使用します。"
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: localizedReason, reply: {success, error in
  if success {
    // 認証成功時の処理
  } else {
    // キャンセルされた場合
    print("Authenticate Cancel: " + (error?.localizedDescription ?? "Unknown Error"))
  }
})

ちなみに、ユーザーがキャンセルボタンを押した場合は、

Canceled by user.

という error が返されます。

policy
認証に使用する方法。
詳しくは下記にて。

localizedReason
認証画面で表示される、認証を要求する理由(テキスト)。
詳しくは下記にて。

reply
認証が終了した時点で呼び出されるブロック。

success
​ 認証成功時は true
​ 失敗時、またはキャンセルした場合は false

error
​ 認証成功時は nil
​ 失敗時やキャンセル時にのみ返される。

1.認証方法

LAPolicy を指定して、認証の方法を指定できます。(ゆーて、iOSだと2種類だけだけど。)

Case rawValue iOS
deviceOwnerAuthenticationWithBiometrics 生体認証TouchID または FaceID 1 iOS 8~
deviceOwnerAuthenticationWithWatch AppleWatch による認証 3 非対応
deviceOwnerAuthenticationWithBiometricsOrWatch 生体認証 または AppleWatch 4 非対応
deviceOwnerAuthentication Apple Watch (iOSは不可)、生物測定パスコード のいずれか 2 iOS 9~

AppleWatch認証は、macOS 限定みたいですね。

'deviceOwnerAuthenticationWithWatch' is unavailable in iOS
\1. 'deviceOwnerAuthenticationWithWatch' has been explicitly marked unavailable here (LocalAuthentication.LAPolicy)

iPhoneも iOS14.5から新実装(ロック解除に)されたので、そのうちにアプリでも使用可能になる…?
(…のか??)

deviceOwnerAuthentication の場合

生体認証を行った後、失敗した場合は パスコード 認証を選択できます。

FaceID を 無効にしている場合パスコード 認証にスキップされます。

deviceOwnerAuthenticationWithBiometrics の場合

生体認証TouchID または FaceID)のみを行います。
もっと正確にいうと、パスコード入力を許可しない設定 です。

そのため、注意点が2つ。

  • 「パスコードを入力」を非表示にすること。

認証失敗後、パスコード入力ができる項目が表示されますが…

Fallback authentication mechanism selected.

押しても特に何も表示されません。
iOS9からの仕様みたいですね。

let context = LAContext()
context.localizedFallbackTitle = ""

localizedFallbackTitle を空にしておくと、表示されなくなります。
こちらが無難ですね。

  • FaceID を 無効にしている場合、即時キャンセルされる。

User has denied the use of biometry for this app.

生体認証が使えない場合は、そもそもこの処理を行わないようにした方が無難です。
または、エラー内容によって処理を分ける…など。

2.認証の使用目的

認証を行う際、その理由を表示します。
FaceIDを使用する際は確認できませんが、TouchIDパスコード入力時 に表示されます。

let context = LAContext()
let localizedReason = "ロックの解除に、認証を使用します。"

※ 画像は、一部ローカライズしてます。

ここまでの内容だけで、処理は実装完了です。
細かい内容について気づいた点を、以下にまとめておきます。

キャンセルされた理由に応じて処理を分ける

let context = LAContext()
let localizedReason = "ロックの解除に、認証を使用します。"
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: localizedReason, reply: {success, error in
  
  if let error = error {
    switch LAError(_nsError: error as NSError).code {
    case .appCancel:
      // システムによるキャンセル① アプリのコード
    case .systemCancel:
      // システムによるキャンセル② システム
    case .userCancel:
      // ユーザーによってキャンセルされた場合
    case .biometryLockout:
      // 生体認証エラー① 失敗制限に達した際のロック
    case .biometryNotAvailable:
      // 生体認証エラー② 許可していない
    case .biometryNotEnrolled:
      // 生体認証エラー③ 生体認証IDが1つもない
    case .authenticationFailed:
      // 認証に失敗してエラー
    case .invalidContext:
      // システムによるエラー① すでに無効化済み
    case .notInteractive:
      // システムによるエラー② 非表示になっている
    case .passcodeNotSet:
      // パスコード認証エラー① パスコードを設定していない
    case .userFallback:
      // パスコード認証エラー② LAPolicyによって無効化
    default:
      // そのほかの未対応エラー
    }
  } else if success {
    // 認証成功時の処理
  } else {
    // 予期せぬエラーの場合
  }
  
  if !success {
    print("Authenticate Cancel: " + (error?.localizedDescription ?? "Unknown Error"))
  }
})
LAError.code 理由 説明
.appCancel システムによるキャンセル invalidate() で明示的に無効化した場合
.systemCancel システムによるキャンセル アプリを閉じるなどをした場合
.userCancel ユーザーによってキャンセルされた場合 ユーザーがキャンセルをタップした場合(他の理由があっても、キャンセルボタンを押した場合はこちらになります)
.biometryLockout 生体認証エラー 認証の失敗回数が一定回数に達し、生体認証がロックされている状態
.biometryNotAvailable 生体認証エラー 生体認証(FaceID)の許可が、拒否されている場合
.biometryNotEnrolled 生体認証エラー 生体認証ID(FaceIDまたはTouchID)が1つもない場合
.authenticationFailed 認証に失敗してエラー 認証に失敗した場合?(キャンセルを押すと.userCancelになるので未確認)
.invalidContext システムによるエラー invalidate() で無効化済みの Context を使っている場合
.notInteractive システムによるエラー interactionNotAllowedtrue になっていて、認証UIの表示ができない場合
.passcodeNotSet パスコード認証エラー パスコードが設定されていない場合
.userFallback パスコード認証エラー LAPolicy がパスコード認証を使わないタイプの場合、「パスコードを入力」を押しても認証画面は表示されない。

デバイス内の事情によるエラー、コード等によるシステム的なエラーの半々といったところでしょうか。
実際に使いそうなのは上半分ですね。

なお、.biometryLockout などの 生体認証に関するエラー は、iOS11 で旧項目から置き換わったものです。
iOS10 以前は、touchIDしかありませんでしたからね。
以下の旧項目は、現在非推奨となっています。

case .touchIDNotAvailable:
  // touchID認証エラー① 失敗制限に達した際のロック
case .touchIDNotEnrolled:
  // touchID認証エラー② 許可していない
case .touchIDLockout:
  // touchID認証エラー③ touchIDが1つもない

シミュレーターで行う方法

[ Features ] → [ Face ID ] → [ Enrolled ] で認証可能になります。
[ Matching Face ] で認証成功アクション。
[ Non-matching Face ] で認証失敗アクション。

TouchID端末では、 FaceIDではなくTouchIDになります。
やり方はほぼ同じです。

参考

ということでね

端末内で完結している認証なので、実装自体はカンタンです。
殴り書きなので、至らぬ点がありましたらぜひぜひ。

まだ AppleWatch認証 は、アプリ側では使えませんね。(今後使えるようになるかは不明)
とはいえ、追加される可能性があるなら、この辺は覗いておいた方がいいですね。

外ではマスク必須の今では、FaceIDはあまり役に立ちません。
そこで大きく役に立ち始めた AppleWatch認証…

とても便利です。ええ。
とはいえ、ロック解除以外(アプリ以外も含めて)には使えないけど。

ところで、 touchID 復活はまだでしょうか🤔

Discussion