利用指紋識別或面部識別,為應用新增私密保護功能

xDEHANG發表於2018-04-22

OneSwift - iOS Tips Based On Swift

從最初做應用開始,我就密切關注使用者的反饋和評論。有時他們的要求確實並不合理,但當大多數人提到一項功能時,就該我們做產品的人反思了。 私密保護功能是使用者在評論中提到的,恰好像OneDay這樣比較私密的內容確實可以增加這項功能。

指紋識別和麵部識別雖然是兩個很不相同的互動,但從開發的角度他們卻只需要一套程式碼就可以搞定。在做之前我先解釋下整個實現過程的重要環節:

原理圖

1.我們需要一個資料來儲存開關資料,在設定中心,使用者根據喜好選擇是否開啟保護

2.一旦使用者開啟應用,通過判斷是否保護來載入遮擋頁面

3.在遮擋頁面自動實現解鎖過程,同時使用者也可以點選後解鎖

4.根據機型的不同,在設定中心需要顯示不同的解鎖名稱

一、基礎配置工作

實現指紋識別與面部識別,都是通過新增LocalAuthentication Framework來實現的。

![匯入LocalAuthentication Framework](https://bjdehang.github.io/OneSwift/img/12/匯入LocalAuthentication Framework.png)

之後在需要用到認證的頁面,匯入LocalAuthentication即可:

import LocalAuthentication
複製程式碼

二、遮蓋頁建立與設定中心開關建立

在設定中心增加一欄開關,暫且叫做Touch ID,最後會進行標題文字的修復。 建立一個單獨的遮蓋頁,只需要放置一句話及按鈕即可,按鈕將呼叫認證過程,檔案為LockViewContrller.swift

認證頁面

為了方便呼叫,給遮蓋頁設定了StoryBoard IDLockController

設定ID

四、設定中心實現資料的修改

利用CoreData將開關的資料儲存在ifProtect中,0表示開,1表示關。 設定資料的過程不會像其他資料那樣直接改變,必須判斷是否為使用者本人進行開關。所以在SettingViewController.swift中,需要新增認證的相關函式。

1.先匯入LocalAuthentication

import LocalAuthentication
複製程式碼

2.操作函式:

func touchID(){
        let context = LAContext()
        var error: NSError?
        if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
            // 開始進入識別狀態,以閉包形式返回結果。閉包的 success 是布林值,代表識別成功與否。error 為錯誤資訊。
            context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "請用指紋解鎖", reply: {success, error in
                if success {
                    // 成功之後的邏輯, 通常使用多執行緒來實現跳轉邏輯。
                    print("解鎖成功 success,允許設定")

                    if self.appDelegate.mysetting.ifProtect == Int64(1){
                        self.appDelegate.mysetting.ifProtect = Int64(0)
                    }else{
                        self.appDelegate.mysetting.ifProtect = Int64(1)
                    }

                    self.appDelegate.saveContext()
                }else {

                    if let error = error as? NSError {
                        // 獲取錯誤資訊
                        let message = self.errorMessageForLAErrorCode(errorCode: error.code)
                        print(message)
                    }
                    //失敗之後
                    print("失敗了")
                }

                self.SettingTableView.reloadData()
            })
        }

    }
複製程式碼

當是使用者本人且認證成功時,開關資料被改變;當不是使用者本人或認證不成功,開關資料不會改變。 為了保持頁面與資料統一,函式執行後我們需要重新整理頁面self.SettingTableView.reloadData()

3.獲取錯誤情況:

func errorMessageForLAErrorCode(errorCode: Int) -> String {
        var message = ""

        switch errorCode {
        case LAError.appCancel.rawValue:
            message = "Authentication was cancelled by application"

        case LAError.authenticationFailed.rawValue:
            message = "The user failed to provide valid credentials"

        case LAError.invalidContext.rawValue:
            message = "The context is invalid"

        case LAError.passcodeNotSet.rawValue:
            message = "Passcode is not set on the device"

        case LAError.systemCancel.rawValue:
            message = "Authentication was cancelled by the system"

        case LAError.touchIDLockout.rawValue:
            message = "Too many failed attempts."

        case LAError.touchIDNotAvailable.rawValue:
            message = "TouchID is not available on the device"
            //            showPassWordInput()

        case LAError.userCancel.rawValue:
            message = "The user did cancel"

        case LAError.userFallback.rawValue:
            message = "The user chose to use the fallback"

        default:
            message = "Did not find error code on LAError object"
        }
        return message
    }
複製程式碼

設定中心實現資料的修改

五、首頁載入遮蓋頁

來到首頁HomeViewController,在viewDidLoad中加入下面程式碼,來判斷每一次開啟應用是否需要認證解鎖。 如果不需要,首頁可以正常顯示; 如果需要,將直接跳轉到LockController

if self.appDelegate.mysetting.ifProtect == Int64(1){

   print(self.appDelegate.mysetting.ifProtect)
   print("需要解鎖")
     if let lockVC = storyboard?.instantiateViewController(withIdentifier: "LockController") as? LockViewController {
         self.present(lockVC,animated: false,completion: nil)
     }else{

     }
  }else{
   print("不需要解鎖")

}
複製程式碼

六、在遮蓋頁中實現認證

遮蓋頁LockController的背景通過虛化處理,可以到達遮蓋的目的。同時擁有認證函式,當認證成功後頁面自動消失返回首頁。 因為需要認證過程,因此也需要三個核心步驟。

1.匯入LocalAuthentication

import LocalAuthentication
複製程式碼

2.操作函式:

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

    if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {

        // 開始進入識別狀態,以閉包形式返回結果。閉包的 success 是布林值,代表識別成功與否。error 為錯誤資訊。

        context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "請用指紋解鎖", reply: {success, error in

            if success {
                // 成功之後的邏輯, 通常使用多執行緒來實現跳轉邏輯。
                print("解鎖成功 success")

                self.dismiss(animated: true, completion: nil)
            }else {

                if let error = error as? NSError {
                    // 獲取錯誤資訊
                    let message = self.errorMessageForLAErrorCode(errorCode: error.code)
                    print(message)
                }
                //失敗之後
                print("失敗了")

            }

        })
    }

}
複製程式碼

認證過程成功後,頁面會自動消失:self.dismiss(animated: true, completion: nil)

3.當使用者進入頁面時自動調取認證過程:

override func viewWillAppear(_ animated: Bool) {
       touchID()
}
複製程式碼

4.或者通過手動點選開始認證:

@IBAction func AuthenAction(_ sender: Any) {
        touchID()
}
複製程式碼

5.捕獲錯誤跟設定頁面一樣。

在遮蓋頁中實現認證

七、根據螢幕尺寸修改開關標題

最後,我們來修復設定中心按鈕的標題文字。當判斷手機為iPhone X時,文字顯示為“面部識別”或“Touch ID”;當不是iPhone X時,顯示為“指紋識別”或“Touch ID”。這裡我們用到了UIDevice來獲取了螢幕的高度:

if UIDevice().userInterfaceIdiom == .phone && UIScreen.main.nativeBounds.height == 2436 {

    cell.SwitchTitle.text  = "Face ID"
    cell.SwitchImage.image = UIImage(named: "btn_setting_faceid")?.withRenderingMode(.alwaysTemplate)
}else{
    cell.SwitchTitle.text  = "Touch ID"
    cell.SwitchImage.image = UIImage(named: "btn_setting_touchid")?.withRenderingMode(.alwaysTemplate)
}

複製程式碼

以上的過程便可實現私密保護,不過不會像系統解鎖那樣可以通過密碼解鎖。要實現密碼解鎖,還需要單獨開發該功能。

GitHub:OneSwift - iOS Tips Based On Swift

微博:xDEHANG

相關文章