【SwiftUI/iOS】FaceIDを実装してみる(顔認証)

目次

概要

たまにはログインを実装したい時もあると思う。
その時、最も手軽に行えるのがFaceID。iPhone端末を使っていればログインする時に当たり前のように使っているはずだ。
Apple公式から出ていいるもので手軽に使えるので、今回記載しておく。

ソースコード

import SwiftUI

@main
struct TestApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            TouchAuthView()
        }
    }
}
import SwiftUI

struct TouchAuthView: View {
    
    @ObservedObject private var viewModel = TouchAuthViewModel()
    
    var body: some View {
        VStack {
            if viewModel.loginStatus == .logout {
                loginView()
            } else {
                mainView()
            }
        }
    }
    
    func loginView() -> some View {
        return VStack {
            Button {
                viewModel.auth()
            } label: {
                Text("認証開始")
            }
        }
    }
    
    func mainView() -> some View {
        return VStack {
            Text("メイン画面")
        }
    }
}
import Foundation
import LocalAuthentication

enum LoginStatus {
    case login
    case logout
}

final class TouchAuthViewModel: ObservableObject {
    @Published private(set) var loginStatus: LoginStatus = .logout
    
    var context: LAContext = LAContext()
    
    func auth() {
        context.localizedCancelTitle = "パスワード入力で認証する"
        var error: NSError?
        guard context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) else {
            print(error?.localizedDescription ?? "生体認証不可")
            return
        }
        
        let reason = "Face IDを使用する場合は設定より\nアクセスの許可を変更してください。"
        context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) { isSuccess, error in
            if let error {
                print(error)
            }
            
            DispatchQueue.main.async {
                self.loginStatus = isSuccess ? .login : .logout
            }

            if isSuccess {
                print("認証成功")
            } else {
                print("認証失敗")
            }
        }
    }
}

デモ動画

詳細

LocalAuthenticationを使用することで顔認証を行える。
今回は顔認証のみで、パスワード認証も追加で実装することは可能。

まずは顔認証が使えるかどうかをチェックする。
LAContextクラスのcanEvaluatePolicyメソッドを使用する。
使えない場合は処理を中止する。実用的な実装をするならパスワード認証を行うのがいいだろう。

guard context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) else {
    print(error?.localizedDescription ?? "生体認証不可")
    return
}

evaluatePolicyメソッドを使用して、実際の顔認証の処理を行う。
isSuccessがtrueとなるは認証が完了した時に行われる。
isSuccessがfalseとなるのは認証をパスしなかった時、「パスワード入力を行う」を選択した時だ。
本来なら、このタイミングでパスワード入力画面へ遷移する。

context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) { isSuccess, error in
    if let error {
        print(error)
    }
    
    DispatchQueue.main.async {
        self.loginStatus = isSuccess ? .login : .logout
    }
    
    if isSuccess {
        print("認証成功")
    } else {
        print("認証失敗")
    }
}

参考ページ