[SwiftUI] 앱에 Face ID 잠금 기능 적용하기

2025. 7. 8. 13:54·Apple/SwiftUI
728x90
반응형

안녕하세요! 피피아노입니다 🎵

 

이번 포스팅에서는 제가 공부용으로 진행하고 있는 일기앱 프로젝트에서 Face ID 잠금 기능을 도입해봤는데 도입 과정을 정리해보려고 합니다.

 

그럼 바로 시작하겠습니다!

 

Face ID 기능 설계 개요

앱 실행 시 사용자의 얼굴 인증을 통해 잠금을 해제하고, 인증 성공 시에만 홈 화면(HomeView)으로 진입할 수 있도록 구현하였습니다.

 

구조는 아래처럼 구현하였습니다.

앱 실행 → 잠금화면(Face ID 요청) → 인증 성공 → HomeView 진입
                                         ↘ 인증 실패 시 에러 표시

이 기능을 구현하기 위해서 크게 3가지를 구현했습니다.

  1. Face ID 인증 로직을 담은 AuthViewModel
  2. 인증 인터페이스를 담당하는 LockScreenView
  3. 앱 진입 지점인 JournalApp.swift에서 인증 상태에 따른 뷰 전환 처리

 

LocalAuthentication 프레임워크

iOS 앱에서 Face ID를 구현하려면 LocalAuthentication 프레임워크를 사용해야 합니다. 이 프레임워크는 Face ID 및 Touch ID를 사용하여 사용자의 생체 정보를 인증하는 기능을 제공하는 프레임워크입니다.

https://developer.apple.com/documentation/localauthentication

 

Local Authentication | Apple Developer Documentation

Authenticate users biometrically or with a passphrase they already know.

developer.apple.com

 

 

LocalAuthentication 프레임워크의 주요 클래스는 LAContext이고 핵심 메서드는 canEvaluatePolicy(_:error:) 와 evaluatePolicy(_:localizedReason:reply:)입니다.

  • canEvaluatePolicy(_:error:): 생체 인증 사용 가능 여부 확인
  • evaluatePolicy(_:localizedReason:reply:): Face ID 인증 요청

LAContext는 생체 인증 및 기기 패스코드를 통한 사용자 인증을 위한 컨텍스트 객체입니다.

 

evaluatePolicy(_:localizedReason:reply:) 메서드는 시스템 인증 창을 띄워 사용자 인증을 수행하며, 인증 성공 여부는 클로저의 Bool 값으로 전달된다. 인증 UI는 시스템이 제공하며, 사용자가 명확하게 인증 사유를 알 수 있도록 localizedReason 설명을 반드시 제공해야 합니다.

let context = LAContext()
var error: NSError?

if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
    context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "Face ID를 사용해 앱을 잠금 해제합니다.") { success, error in
        if success {
            // 인증 성공
        } else {
            // 인증 실패
        }
    }
}

iOS 11 이상부터 Face ID를, iOS 8 이상부터 Touch ID를 사용할 수 있습니다.

 

AuthViewModel - Face ID 인증 로직

Face ID 인증은 LocalAuthentication 프레임워크의 LAContext를 활용해서 구현하였습니다.

import Foundation
import LocalAuthentication

class AuthViewModel: ObservableObject {
    @Published var isUnlocked = false
    @Published var authError: String?

    func authenticate() {
        let context = LAContext()
        var error: NSError?

        if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
            context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics,
                                   localizedReason: "앱 잠금 해제를 위해 Face ID를 사용합니다.") { success, error in
                DispatchQueue.main.async {
                    self.isUnlocked = success
                    self.authError = success ? nil : error?.localizedDescription
                }
            }
        } else {
            DispatchQueue.main.async {
                self.authError = "Face ID를 사용할 수 없습니다."
            }
        }
    }
}

 

이 코드에서 isUnlocked는 인증 성공 여부를 나타내는 상태 값이고 authError는 인증 실패 메시지를 UI에 표시하기 위한 문자열입니다.

 

LockScreenView - Face ID UI 구성

struct LockScreenView: View {
    @ObservedObject var authVM: AuthViewModel

    var body: some View {
        VStack(spacing: 20) {
            Image(systemName: "faceid")
                .resizable()
                .frame(width: 100, height: 100)
                .foregroundColor(.blue)

            Text("Face ID로 잠금 해제")
                .font(.title2)

            if let error = authVM.authError {
                Text(error)
                    .foregroundColor(.red)
                    .font(.caption)
            }

            Button("잠금 해제 시도") {
                authVM.authenticate()
            }
            .buttonStyle(.borderedProminent)
        }
        .onAppear {
            authVM.authenticate()
        }
    }
}

앱 실행 시 자동으로 Face ID 인증을 시도하고, 실패 시 버튼을 눌러서 재시도할 수 있도록 UI를 구성하였습니다.

 

JournalApp.swift – 인증 상태에 따른 화면 전환

struct JournalApp: App {
    @StateObject private var authVM = AuthViewModel()

    var sharedModelContainer: ModelContainer = {
        let schema = Schema([
            JournalEntry.self,
        ])
        let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)

        do {
            return try ModelContainer(for: schema, configurations: [modelConfiguration])
        } catch {
            fatalError("Could not create ModelContainer: \(error)")
        }
    }()

    var body: some Scene {
        WindowGroup {
            if authVM.isUnlocked {
                HomeView()
            } else {
                LockScreenView(authVM: authVM)
            }
        }
        .modelContainer(sharedModelContainer)
    }
}

앱의 진입점에서 authVM.isUnlocked 상태를 기준으로 HomeView() 또는 LockScreenView()를 표시하도록 구성하였습니다.

 

Info.plist 설정 추가

Face ID를 사용하기 위해 다음 항목을 Info.plist에 추가해야 합니다.

<key>NSFaceIDUsageDescription</key>
<string>앱 잠금 해제를 위해 Face ID를 사용합니다.</string>

코드를 제대로 다 구현해도 해당 항목이 없으면 앱이 인증을 요청할 때 크래시가 발생할 수 있으니 꼭 추가를 해줘야 합니다!

 

마무리

SwiftUI와 LocalAuthentication을 활용하면 비교적 간단한 구조로 Face ID 인증을 구현할 수 있었습니다.

하지만 단순히 기능이 된다고 끝내기보다, 실패 시 재시도 UX나, 설정에서 잠금 기능을 끌 수 있도록 하는 유연한 확장성까지 고려하고 싶다는 생각이 들었습니다.

 

이번 경험은 기능 하나를 구현하는 데 그치지 않고,

앱의 신뢰도를 높이고 사용자 입장에서 어떤 인증 흐름이 좋은지 고민해보는 계기가 되었습니다.

 

예를 들어 앱을 열자마자 인증이 자동으로 이뤄지는 흐름이 좋은지, 실패했을 때 다시 시도할 수 있는 여지를 어떻게 줄지, 또는 인증 자체를 사용자가 원하지 않을 수도 있다는 점까지 고려하면서 보안과 사용성 사이의 균형을 생각해볼 수 있었습니다.

 

앞으로는 백그라운드 복귀 시 재인증, 패스코드 대체, 설정 토글 등 사용자 중심으로 보안 기능을 세분화하는 방향으로 발전시켜볼 계획입니다!


감사합니다.

 

잘못된 내용이 있거나 더 좋은 내용 피드백은 언제나 환영합니다!

궁금하신 부분은 댓글로 질문 부탁드립니다!

728x90
반응형

'Apple > SwiftUI' 카테고리의 다른 글

[SwiftUI] SwiftUI 상태 동기화 트러블슈팅  (1) 2025.06.25
[SwiftUI] CADisplayLink를 활용한 부드러운 ProgressView 애니메이션 구현 트러블슈팅  (6) 2025.06.06
[SwiftUI] NavigationStack 사용 시 화면 전환 안 되는 문제와 title 깨짐 문제 트러블슈팅  (0) 2025.06.03
[SwiftUI] SwiftUI로 카메라 기능 구현하기  (2) 2025.03.01
[SwiftUI] ProgressView 생성하기  (15) 2025.01.15
'Apple/SwiftUI' 카테고리의 다른 글
  • [SwiftUI] SwiftUI 상태 동기화 트러블슈팅
  • [SwiftUI] CADisplayLink를 활용한 부드러운 ProgressView 애니메이션 구현 트러블슈팅
  • [SwiftUI] NavigationStack 사용 시 화면 전환 안 되는 문제와 title 깨짐 문제 트러블슈팅
  • [SwiftUI] SwiftUI로 카메라 기능 구현하기
P_Piano
P_Piano
Apple 생태계 개발자가 되기 위한 학습과 경험의 기록
    반응형
    250x250
  • P_Piano
    피피아노의 개발 일지
    P_Piano
  • 전체
    오늘
    어제
    • 분류 전체보기 (213)
      • Apple (131)
        • iOS (23)
        • visionOS (4)
        • Swift (70)
        • UIKit (2)
        • SwiftUI (24)
        • RxSwift (2)
        • Xcode (5)
      • C언어 (5)
      • C++ (8)
      • Dart (1)
      • Python (3)
      • JavaScript (17)
      • Git (1)
      • CS (39)
        • 디자인 패턴 (6)
        • 네트워크 (20)
        • 운영체제 (8)
        • Database (5)
        • 자료구조 (0)
      • IT 지식 (2)
      • IT 뉴스 (4)
      • 출처 표기 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    클래스
    옵셔널
    함수
    프로세스
    코딩테스트
    네트워크
    티스토리챌린지
    combine
    연산자
    SWIFT
    프로그래머스
    운영체제
    Initializers
    스위프트
    Vision Pro
    이니셜라이저
    변수
    프로퍼티 래퍼
    디자인패턴
    swiftUI
    자바스크립트
    오블완
    UIKit
    제어문
    ios
    비동기
    visionOS
    Xcode
    Apple
    배열
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
P_Piano
[SwiftUI] 앱에 Face ID 잠금 기능 적용하기
상단으로

티스토리툴바