SwiftUI 開發之旅:Face ID 的使用技巧

語言: CN / TW / HK

theme: smartblue

開啟掘金成長之旅!這是我參與「掘金日新計劃 · 12 月更文挑戰」的第2天,點擊查看活動詳情

好久不見,我是 new_cheng。

蘋果在 iPhone X 上發佈 Face ID 後,這一功能基本已經成為 iPhone 系列的標配了;在 IOS 開發中也會經常用到 Face ID。

以下簡稱 面容 ID。

在使用面容 ID 之前,我們先來看看,它的常用場景:

  • APP 解鎖
  • 支付

這裏我們以解鎖的場景為例,看看如何使用面容 ID:

從 App 解鎖的使用角度來看,用户會有以下相關操作: 1. 首先用户要去 app 的設置頁面開啟 faceid 解鎖選項。 2. 開啟面容 ID 解鎖時需要檢查 app 是否擁有面容id的授權。 3. 沒有面容id的授權時,彈窗提醒,用户點擊確認後需要跳轉去系統設置頁面給app開啟面容id授權。 4. 授權完成後,用户可以打開 faceid 解鎖選項。 5. 重新進入app的時候,顯示一個解鎖頁面,調用面容 ID解鎖,如果用户取消了解鎖,那就無法顯示 app 的其他內容

以上是涉及到面容 ID 解鎖的一個基本業務流程,下面我們來完成具體實現。

面容 ID 解鎖的開關設置

我們先要在 app 的設置頁面裏面加入一個 Face ID 解鎖 的開關設置,先來簡單的編寫這個頁面。

image.png

Setting.swift:

```swift struct Settings: View { @EnvironmentObject var appSetting: AppSetting

@State private var isOpenFaceIdLock = false

var body: some View {
    ScrollView {
        VStack(alignment: .leading) {
            // ...
            HStack {
                Toggle(isOn: $isOpenFaceIdLock) {
                    HStack {
                        Text("😃")
                            .font(.system(size: 16))
                        Text("FaceID 解鎖")
                            .font(.body)
                            .fontWeight(.medium)
                            .foregroundColor(.gray)
                        Spacer()
                        Image(systemName: "chevron.right")
                            .foregroundColor(Color.gray)
                            .font(.system(size: 14))
                    }
                }
                .onChange(of: isOpenFaceIdLock) { value in
                    // 將用户設置保存起來
                    appSetting.isOpenFaceIdLock = value
                }
            }
        }
    }
     .onAppear {
        // 初始化時,使用 AppSetting 的值

self.isOpenFaceIdLock = UserDefaults.standard.bool(forKey: "isOpenFaceIdLock") } } } ```

一個簡單的設置頁面就完成了,在這裏我們還引入了 AppSetting,用於持久化存儲用户的設置,上一次我們在 SwiftUI 開發之旅:適配深色模式 中用到了它。現在,我們會繼續在原有的基礎上往 AppSetting 中添加關於面容 ID 的內容。

對 AppSetting 有不瞭解的可以點擊適配深色模式的鏈接前往查看。

我們要在 AppSetting 中加入一個新的字段 isOpenFaceIdLock,用於存儲 面容 ID 解鎖的設置:

swift // 是否開啟 FaceId 解鎖 @Published var isOpenFaceIdLock: Bool = UserDefaults.standard.bool(forKey: "isOpenFaceIdLock") { didSet { // 監聽數據變化,持久化數據 UserDefaults.standard.set(self.isOpenFaceIdLock, forKey: "isOpenFaceIdLock")     }  }

檢查是否授權使用面容 ID

面容 ID 解鎖默認是不開啟的,當用户開啟該設置的時候,我們要先檢查我們的 App 是否被系統授權使用 面容 ID 解鎖。

在 Setting.swift 中新增 authenticate 函數和用於提示用户需要開啟授權的控制變量 isGoOpenAuth

  1. 先引入 LocalAuthentication 依賴:

swift import LocalAuthentication

  1. 新增函數和變量:

```swift // 是否需要前往設置頁面開啟權限 @State private var isGoOpenAuth: Bool = false

// 先檢測是否開啟面容id授權 func authenticate() { let context = LAContext() var error: NSError? // 檢查是否可以進行生物特徵識別 if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) { self.isGoOpenAuth = false } else { // 沒有生物指紋識別功能 if (error?.code == -6) { self.isGoOpenAuth = true print("沒有生物指紋識別功能") } } } ```

  1. 當系統沒有授權使用面容 ID 時,提醒用户前往開啟授權

swift ScrollView { // ... } .alert("", isPresented: $isGoOpenAuth) { Button(role: .cancel) { self.isGoOpenAuth = false self.isOpenFaceIdLock = false } label: { Text("取消") } Button() { // 前往設置頁面進行授權 guard let url = URL(string: UIApplication.openSettingsURLString) **else** { return } if #available(iOS 10.0, *) { UIApplication.shared.open(url, options: [:], completionHandler: nil) } else { UIApplication.shared.openURL(url) } } label: { Text("去開啟") } } message: { Text("開啟面容 ID 權限才能夠使用解鎖哦") }

2721669086717_.pic.jpg

請用真機運行。

點擊 【去開啟】 後,會直接跳轉到系統設置中對應 App 的設置頁面。

到這裏,一個檢查授權面容 ID 和持久化用户設置的功能就完成了。

面容 ID 的解鎖頁面

在用面容 ID 解鎖前,為了用户信息安全,是不能顯示 App 內的頁面內容的。這時候我們就需要一個專用與解鎖的頁面,當沒有進行解鎖的時候, App 會一直顯示該頁面直到解鎖成功。

FaceIdLock.swift:

```swift import SwiftUI

struct FaceIdLock: View {     @EnvironmentObject var appSetting: AppSetting // 是否需要前往設置頁面開啟權限     @State private var isGoOpenAuth: Bool = false

// 先檢測是否開啟面容id授權     func authenticateFaceId() {         let context = LAContext()         var error: NSError?         // 檢查是否可以進行生物特徵識別         if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {            self.isGoOpenAuth = false         } else {             // 沒有生物指紋識別功能             if (error?.code == -6) {                 self.isGoOpenAuth = true                 print("沒有生物指紋識別功能")             }         }     }

var body: some View {         ZStack {             Color("mainBg").edgesIgnoringSafeArea(.all)             VStack {                 Button(action: { // 如果用户不小心取消了解鎖,需要提供一個點擊重新解鎖的方式:當用户點擊時,調用面容 ID 解鎖                     authenticateFaceId() // 還是先檢查系統是否授權了面容 ID                     if !isGoOpenAuth {                         appSetting.authenticate()                     }                 }, label: {                     VStack {                         Image(systemName: "faceid")                             .foregroundColor(Color.blue)                             .font(.system(size: 54))                             .padding()                         Text("點擊進行面容 ID 登錄")                             .foregroundColor(Color.textColor)                     }                 })             }         } .alert("", isPresented: $isGoOpenAuth) {             Button(role: .cancel) {                 self.isGoOpenAuth = false             } label: {                 Text("取消")             }             Button() {                // 前往設置頁面進行授權                guard let url = URL(string: UIApplication.openSettingsURLString) else {                    return                }                if #available(iOS 10.0, *) {                    UIApplication.shared.open(url, options: [:], completionHandler: nil)                } else {                    UIApplication.shared.openURL(url)                }             } label: {                 Text("去開啟")             }         } message: {             Text("開啟面容 ID 權限才能夠使用解鎖哦")         }         .ignoresSafeArea(edges: .top)         .onAppear { // 初始化顯示時,先判斷是否授權了faceid             authenticateFaceId()             if !isGoOpenAuth {                 appSetting.authenticate()             }         }     } }

struct FaceIdLock_Previews: PreviewProvider {     static var previews: some View {         FaceIdLock()             .environmentObject(AppSetting())     } } ```

image.png

在 FaceIdLock 頁面,我們同樣需要檢測是否授權了面容 ID 權限,不然,App 會一直停留在該頁面,且無法調起面容 ID 進行解鎖。

接着在入口頁面 ContentView.swift 中添加一個條件判斷:

```swift struct ContentView: View { @EnvironmentObject var appSetting: AppSetting

var body: some View {
    VStack {
        if appSetting.isOpenFaceIdLock && !appSetting.isUnlocked {

FaceIdLock()                     .frame(maxHeight: .infinity)             } else { // ... } } } } ```

調用面容 ID API

接下來我們需要完成在 FaceIdLock.swift 中解鎖時調用的 AppSetting 的 authenticate 函數。

AppSetting.swift:

```swift import LocalAuthentication

class AppSetting: ObservableObject { // 是否已解鎖,只有在使用 faceid 的前提下才能使用該變量,用於判斷後面的操作是否能進行     @Published var isUnlocked: Bool = false

func authenticate() {
    let context = LAContext()
    var error: NSError?
    // 檢查是否可以進行生物特徵識別
    if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
        // 如果可以,執行識別
        let reason = "開啟面容 ID 權限才能夠使用解鎖哦"
        context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, authenticationError **in**
            // 鑑權完成
            DispatchQueue.main.async {
                if success {
                    // 鑑權成功
                    self.isUnlocked = true
                } else {
                    // 鑑權失敗
                    self.isUnlocked = false
                }
            }
        }
    } else {
        // 沒有生物指紋識別功能
        if (error?.code == -6) {
            print("沒有生物指紋識別功能")
        }
    }
}

} ```

到這裏,我們已經完成了一個比較完整的使用面容 ID 解鎖的功能了🎉

總結

我們通過實操,完成了一個面容 ID 的使用功能,完整還原了使用面容 ID 的的業務流程。除了自己編寫代碼來使用面容 ID,你還可以通過諸如 BiometricAuthentication 的第三方庫來完成面容 ID 或者指紋識別的使用。合理的運用蘋果提供的功能,來提升你應用的用户體驗吧。

這是 SwiftUI 開發之旅專欄的文章,是 swiftui 開發學習的經驗總結及實用技巧分享,歡迎關注該專欄,會堅持輸出。同時歡迎關注我的個人公眾號 @JSHub:提供最新的開發信息速報,優質的技術乾貨推薦。或是查看我的個人博客:Devcursor

👍點贊:如果有收穫和幫助,請點個贊支持一下!

🌟收藏:歡迎收藏文章,隨時查看!

💬評論:歡迎評論交流學習,共同進步!