Xamarin.Form框架並沒有提供指紋認證功能,需要分平台實現!
Android的Fingerprint Authentication
參考:https://docs.microsoft.com/zh-cn/xamarin/android/platform/fingerprint-authentication/
概述
在 Android 設備上引入指紋掃描儀為應用程序提供了傳統的用戶名/密碼用戶身份驗證的替代方法。相較於用戶名和密碼,采用指紋對用戶進行身份驗證使應用程序安全性的實現更具隱私性。
FingerprintManager API使用指紋掃描儀來定位設備,並且運行的API級別為23(Android 6.0)或更高。 這些API在Android.Hardware.Fingerprints命名空間中找到。 Android支持庫v4提供了適用於舊版Android的指紋API版本。 兼容性API在Android.Support.v4.Hardware.Fingerprint命名空間中找到,通過Xamarin.Android.Support.v4 NuGet包進行分發。
FingerprintManager(及其支持庫對應的FingerprintManagerCompat)是使用指紋掃描硬件的主要類。 此類是圍繞系統級服務的Android SDK包裝,該服務管理與硬件本身的交互。 它負責啟動指紋掃描儀並響應來自掃描儀的反饋。 此類具有一個非常簡單的接口,只有三個成員:
- Authenticate 身份驗證–此方法將初始化硬件掃描程序並在后台啟動服務,等待用戶掃描其指紋。
- EnrolledFingerprints –如果用戶已在設備上注冊一個或多個指紋,則此屬性將返回true。
- HardwareDetected –此屬性用於確定設備是否支持指紋掃描。
以下代碼段是如何使用支持庫兼容性API調用它的示例:
// context is any Android.Content.Context instance, typically the Activity FingerprintManagerCompat fingerprintManager = FingerprintManagerCompat.From(context); fingerprintManager.Authenticate(FingerprintManager.CryptoObject crypto,int flags,CancellationSignal cancel, FingerprintManagerCompat.AuthenticationCallback callback,Handler handler );
第一個參數是用於通過指紋驗證取出AndroidKeyStore中的key的對象,稍后描述。
第二個參數可以用來取消指紋驗證,如果想手動關閉驗證,可以調用該參數的cancel方法。
第三個參數沒什么意義,就是傳0就好了。
第四個參數最重要,由於指紋信息是存在系統硬件中的,app是不可以訪問指紋信息的,所以每次驗證的時候,系統會通過這個callback告訴你是否驗證通過、驗證失敗等。
第五個參數是handler,fingerprint中的消息都通過這個handler來傳遞消息,如果你傳空,則默認創建一個在主線程上的handler來傳遞消息,沒什么用,傳null好了。
————————————————
本指南將討論如何使用FingerprintManager API通過指紋認證來增強Android應用程序。
它將介紹如何實例化和創建CryptoObject來幫助保護指紋掃描儀的結果。 我們將研究應用程序應如何子類化FingerprintManager.AuthenticationCallback並響應指紋掃描儀的反饋。 最后,我們將看到如何在Android設備或仿真器上注冊指紋,以及如何使用adb模擬指紋掃描。
CryptoObjec類封裝了基於javax.crypto.Cipher的CryptoObject的創建
要求
指紋認證需要Android 6.0(API級別23)或更高版本以及具有指紋掃描器的設備。
必須為要認證的每個用戶在設備上注冊一個指紋。
這涉及設置使用密碼,PIN,滑動模式或面部識別的屏幕鎖定。 可以在Android仿真器中模擬某些指紋認證功能。 有關這兩個主題的更多信息,請參見“注冊指紋”部分。
【即 要調用指紋認證的應用,此手機必須設置了一個鎖屏密碼 和 錄制了至少一個指紋】
入門
首先,讓我們先介紹如何配置 Xamarin Android 項目,使應用程序能夠使用指紋身份驗證:
- 更新androidmanifest.xml以聲明指紋 api 所需的權限。
- 獲取對
FingerprintManager
的引用。 - 檢查設備是否能夠進行指紋掃描。
1、Android 應用程序必須在清單中請求 USE_FINGERPRINT
權限。
2、 獲取FingerprintManager的實例
接下來,應用程序必須獲取FingerprintManager或FingerprintManagerCompat類的實例。 為了與舊版本的Android兼容,Android應用程序應使用Android支持v4 NuGet包中提供的兼容性API。 以下代碼段演示了如何從操作系統中獲取適當的對象:
// Using the Android Support Library v4 FingerprintManagerCompat fingerprintManager = FingerprintManagerCompat.From(context); // Using API level 23: FingerprintManager fingerprintManager = context.GetSystemService(Context.FingerprintService) as FingerprintManager;
context是任何Android的 Android.Content.Context。 通常,這是執行身份驗證的Activity 。
3、檢查資格
應用程序必須執行多項檢查,以確保可以使用指紋身份驗證。 總共,應用程序使用五個條件來檢查資格:
- API級別23 –指紋API要求API級別23或更高。 FingerprintManagerCompat類將為您包裝API級別檢查。 因此,建議使用Android Support Library v4 和FingerprintManagerCompat。
- 硬件–首次啟動應用程序時,應檢查設備是否存在指紋掃描儀:
FingerprintManagerCompat fingerprintManager = FingerprintManagerCompat.From(context); if (!fingerprintManager.IsHardwareDetected) { // Code omitted }
- 設備安全–用戶必須使用屏幕鎖保護設備。 如果用戶尚未使用屏幕鎖保護設備,並且安全性對於應用程序很重要,則應通知用戶必須配置屏幕鎖。 以下代碼段顯示了如何檢查此先決條件:
KeyguardManager keyguardManager = (KeyguardManager) GetSystemService(KeyguardService); if (!keyguardManager.IsKeyguardSecure) { }
- 登記(注冊)的指紋–用戶必須至少在操作系統上注冊了一個指紋。 此權限檢查應在每次身份驗證嘗試之前進行:
FingerprintManagerCompat fingerprintManager = FingerprintManagerCompat.From(context); if (!fingerprintManager.HasEnrolledFingerprints) { // Can't use fingerprint authentication - notify the user that they need to // enroll at least one fingerprint with the device. }
- 權限–使用該應用程序之前,該應用程序必須向用戶請求權限。 對於Android 5.0及更低版本,用戶將授予權限作為安裝應用程序的條件。 Android 6.0引入了新的權限模型,該模型可在運行時檢查權限。 此代碼段是如何在Android 6.0上檢查權限的示例:【應用程序必須授予使用指紋掃描儀的權限。在項目屬性的清單中添加】
// The context is typically a reference to the current activity. Android.Content.PM.Permission permissionResult = ContextCompat.CheckSelfPermission(context, Manifest.Permission.UseFingerprint); if (permissionResult == Android.Content.PM.Permission.Granted) { // Permission granted - go ahead and start the fingerprint scanner. } else { // No permission. Go and ask for permissions and don't start the scanner. See // https://developer.android.com/training/permissions/requesting.html }
每次應用程序提供身份驗證選項時,都要檢查所有這些條件,以確保用戶獲得最佳的用戶體驗。 其設備或操作系統的更改或升級可能會影響指紋身份驗證的可用性。 如果您選擇緩存任何這些檢查的結果,請確保滿足升級方案。
有關如何在Android 6.0中請求權限的更多信息,請參閱Android指南“在運行時請求權限”。
掃描指紋
指紋身份驗證工作流的快速概述:【監聽,回調,自己寫UI】
- 調用
FingerprintManager.Authenticate
,同時傳遞CryptoObject
和FingerprintManager.AuthenticationCallback
的實例。CryptoObject
用於確保指紋身份驗證結果未被篡改。 - 將FingerprintManager. authenticationcallback 傳遞給類的子類。 指紋身份驗證開始時,將提供此類的實例以
FingerprintManager
。 指紋掃描器完成后,它將調用此類的一個回調方法。 - 編寫代碼以更新 UI,以讓用戶知道設備已啟動指紋掃描器並等待用戶交互。
- 指紋掃描器完成后,Android 會通過對上一步中提供的
FingerprintManager.AuthenticationCallback
實例調用方法,將結果返回到應用程序。 - 應用程序將向用戶通知指紋身份驗證結果,並根據需要對結果做出反應。
取消指紋掃描
用戶(或應用程序)在啟動指紋掃描后可能需要取消指紋掃描。 在這種情況下,請在提供給FingerprintManager的CancellationSignal上調用IsCancelled方法,並在調用它以啟動指紋掃描時進行身份驗證。
現在我們已經看到了Authenticate方法,讓我們更詳細地研究一些更重要的參數。
首先,我們將研究響應身份驗證回調,它將討論如何對FingerprintManager.AuthenticationCallback進行子類化,從而使Android應用程序能夠對指紋掃描儀提供的結果做出反應。
Creating a CryptoObject
指紋認證結果的完整性對應用程序很重要-這就是應用程序如何知道用戶身份的方式。
從理論上講,第三方惡意軟件可能會攔截和篡改指紋掃描儀返回的結果。 本節將討論一種保留指紋結果有效性的技術。
FingerprintManager.CryptoObject是Java加密API的包裝,FingerprintManager使用它來保護身份驗證請求的完整性。
通常,Javax.Crypto.Cipher對象是用於加密指紋掃描器結果的機制。 Cipher對象【意思:密碼】本身將使用由應用程序使用Android密鑰庫API創建的密鑰。
為了了解這些類如何協同工作,讓我們首先看下面的代碼,該代碼演示如何創建CryptoObject,然后更詳細地進行解釋:

public class CryptoObjectHelper { // This can be key name you want. Should be unique for the app. static readonly string KEY_NAME = "com.xamarin.android.sample.fingerprint_authentication_key"; // We always use this keystore on Android. static readonly string KEYSTORE_NAME = "AndroidKeyStore"; // Should be no need to change these values. static readonly string KEY_ALGORITHM = KeyProperties.KeyAlgorithmAes; static readonly string BLOCK_MODE = KeyProperties.BlockModeCbc; static readonly string ENCRYPTION_PADDING = KeyProperties.EncryptionPaddingPkcs7; static readonly string TRANSFORMATION = KEY_ALGORITHM + "/" + BLOCK_MODE + "/" + ENCRYPTION_PADDING; readonly KeyStore _keystore; public CryptoObjectHelper() { _keystore = KeyStore.GetInstance(KEYSTORE_NAME); _keystore.Load(null); } public FingerprintManagerCompat.CryptoObject BuildCryptoObject() { Cipher cipher = CreateCipher(); return new FingerprintManagerCompat.CryptoObject(cipher); } Cipher CreateCipher(bool retry = true) { IKey key = GetKey(); Cipher cipher = Cipher.GetInstance(TRANSFORMATION); try { cipher.Init(CipherMode.EncryptMode, key); } catch(KeyPermanentlyInvalidatedException e) { _keystore.DeleteEntry(KEY_NAME); if(retry) { CreateCipher(false); } else { throw new Exception("Could not create the cipher for fingerprint authentication.", e); } } return cipher; } IKey GetKey() { IKey secretKey; if(!_keystore.IsKeyEntry(KEY_NAME)) { CreateKey(); } secretKey = _keystore.GetKey(KEY_NAME, null); return secretKey; } void CreateKey() { KeyGenerator keyGen = KeyGenerator.GetInstance(KeyProperties.KeyAlgorithmAes, KEYSTORE_NAME); KeyGenParameterSpec keyGenSpec = new KeyGenParameterSpec.Builder(KEY_NAME, KeyStorePurpose.Encrypt | KeyStorePurpose.Decrypt) .SetBlockModes(BLOCK_MODE) .SetEncryptionPaddings(ENCRYPTION_PADDING) .SetUserAuthenticationRequired(true) .Build(); keyGen.Init(keyGenSpec); keyGen.GenerateKey(); } }
程序將使用應用程序創建的key為每個CryptoObject創建一個新的Cipher。key由在CryptoObjectHelper類的開頭設置的KEY_NAME變量標識。
- 獲取密鑰IKey:方法GetKey將嘗試使用Android Keystore API檢索密鑰。如果密鑰不存在,則方法CreateKey將為應用程序創建一個新密鑰。
- 實例化Cipher:通過調用Cipher.GetInstance實例化cipher,並進行轉換(參數:一個字符串值,該值告訴密碼如何加密和解密數據)。
- 初始化Cipher:對Cipher.Init的調用 將通過提供來自應用程序的密鑰來完成cipher的初始化。
請務必意識到,在某些情況下Android可能會使密鑰無效:
- 設備已注冊了新的指紋。
- 設備沒有登記指紋。
- 用戶已禁用屏幕鎖定。
- 用戶已更改屏幕鎖定(屏幕鎖定的類型或所使用的PIN /圖案)。
發生這種情況時,Cipher.Init將拋出KeyPermanentlyInvalidatedException。上面的示例代碼將捕獲該異常,刪除key,然后創建一個新。
下一節將討論如何創建密鑰並將其存儲在設備上。
創建密鑰key
CryptoObjectHelper類使用Android KeyGenerator來創建密鑰並將其存儲在設備上。 KeyGenerator類可以創建密鑰,但是需要一些有關要創建的密鑰類型的元數據。此信息由KeyGenParameterSpec類的實例提供。
使用GetInstance工廠方法實例化KeyGenerator。該示例代碼使用 高級加密標准(AES)作為加密算法。 AES會將數據分成固定大小的塊,並對每個塊進行加密。
接下來,使用KeyGenParameterSpec.Builder創建一個KeyGenParameterSpec。 KeyGenParameterSpec.Builder包裝了有關要創建的密鑰的以下信息:
- 密鑰名稱。
- 該密鑰對於加密和解密都必須有效。
- 在示例代碼中,BLOCK_MODE設置為密碼塊鏈接(KeyProperties.BlockModeCbc),這意味着每個塊都與前一個塊進行XOR(在每個塊之間創建依賴項)。
- CryptoObjectHelper使用公共密鑰密碼標准7(PKCS7)生成字節,這些字節將填充這些塊以確保它們的大小相同。
- SetUserAuthenticationRequired(true)表示必須先進行用戶認證,然后才能使用密鑰。
一旦創建了KeyGenParameterSpec,它將用於初始化KeyGenerator,它將生成密鑰並將其安全地存儲在設備上。
【總結:Android.KeyGenerator創建密鑰並將其存儲在設備上,然后用Javax.Crypto.Cipher 拿創建的密鑰 加密指紋掃描器結果,防止掃描結果被篡改】
Using the CryptoObjectHelper
現在,示例代碼已將創建CryptoWrapper的大部分邏輯封裝到CryptoObjectHelper類中,讓我們從本指南的開頭重新訪問代碼,並使用CryptoObjectHelper創建密碼並啟動指紋掃描器:
protected void FingerPrintAuthenticationExample() { const int flags = 0; /* always zero (0) */ CryptoObjectHelper cryptoHelper = new CryptoObjectHelper(); cancellationSignal = new Android.Support.V4.OS.CancellationSignal(); // Using the Support Library classes for maximum reach FingerprintManagerCompat fingerPrintManager = FingerprintManagerCompat.From(this); // AuthCallbacks is a C# class defined elsewhere in code. FingerprintManagerCompat.AuthenticationCallback authenticationCallback = new MyAuthCallbackSample(this); // Here is where the CryptoObjectHelper builds the CryptoObject. fingerprintManager.Authenticate(cryptohelper.BuildCryptoObject(), flags, cancellationSignal, authenticationCallback, null); }
Responding to Authentication Callbacks
指紋掃描儀在其自己的后台線程上運行,完成后它將通過在UI線程上調用FingerprintManager.AuthenticationCallback的一種方法來報告掃描結果。 Android應用程序必須提供自己的處理程序,該處理程序擴展此抽象類,並實現以下所有方法:
- OnAuthenticationError(int errorCode,ICharSequence errString)–發生不可恢復的錯誤時調用。 除了可以再試一次以外,應用程序或用戶無法采取其他措施來糾正這種情況。
- OnAuthenticationFailed()–當檢測到指紋但設備無法識別指紋時,將調用此方法。
- OnAuthenticationHelp(int helpMsgId,ICharSequence helpString)–在發生可恢復的錯誤(例如手指在掃描儀上快速滑動)時調用。
- OnAuthenticationSucceeded(FingerprintManagerCompati.AuthenticationResult結果)–識別指紋后調用此方法。
如果在調用Authenticate時使用了CryptoObject,建議在OnAuthenticationSuccessful中調用Cipher.DoFinal。 如果密碼被篡改或初始化不正確,DoFinal將拋出異常,表明指紋掃描儀的結果可能已在應用程序外部被篡改。
具體說明:
1、OnAuthenticationSucceeded檢查調用身份驗證時是否向密碼管理器提供了密碼。如果是這樣,則在密碼上調用DoFinal方法。這將關閉密碼,將其還原到其原始狀態。如果密碼有問題,則DoFinal將引發異常,並且身份驗證嘗試應被視為失敗。
2、OnAuthenticationError和OnAuthenticationHelp回調每個都接收一個整數,指示問題出在哪里。以下部分說明了每種可能的幫助或錯誤代碼。這兩個回調起到類似的作用-通知應用程序指紋認證失敗。它們的不同之處在於嚴重性。 OnAuthenticationHelp是用戶可恢復的錯誤,例如快速滑動指紋。 OnAuthenticationError是更嚴重的錯誤,例如損壞的指紋掃描儀。
請注意,當通過CancellationSignal.Cancel()消息取消指紋掃描時,將調用OnAuthenticationError。 errMsgId參數的值為5(FingerprintState.ErrorCanceled)。根據要求,AuthenticationCallbacks的實現可能會與其他錯誤區別對待。
3、成功掃描指紋但與設備注冊的任何指紋都不匹配時,將調用OnAuthenticationFailed。
指紋身份驗證指南/建議
現在,我們已經了解了圍繞Android 6.0指紋認證的概念和API,下面我們討論一些有關使用指紋API的一般建議。
1、Use the Android Support Library v4 Compatibility APIs –通過從代碼中刪除API檢查,從而簡化應用程序代碼,並使應用程序可以定位到盡可能多的設備。
2、提供指紋認證的替代方法–指紋認證是應用程序認證用戶的一種簡便快捷的方法,但是,不能認為它會一直有效或可用。指紋掃描儀可能會出現故障,鏡頭可能變臟,用戶可能未將設備配置為使用指紋身份驗證,或者此后指紋丟失了。用戶也可能不希望在您的應用程序中使用指紋認證。由於這些原因,Android應用程序應提供備用的身份驗證過程,例如用戶名和密碼。
3、使用Google的指紋圖標–所有應用程序都應使用Google提供的相同指紋圖標。使用標准圖標可以使Android用戶輕松識別應用中使用指紋身份驗證的位置:
Android指紋圖標
4、通知用戶–應用程序應向用戶顯示某種形式的通知,表明指紋掃描儀處於活動狀態並正在等待觸摸或滑動。
IOS的Touch ID and Face ID
參考:Use Touch ID and Face ID with Xamarin.iOS
概述
iOS支持兩種生物識別系統:
- Touch ID使用“主頁”按鈕下的指紋傳感器。
- Face ID使用前置攝像頭傳感器通過面部掃描對用戶進行身份驗證。
iOS 7中引入了Touch ID,iOS 11中引入了Face ID。
這些身份驗證系統依賴於稱為Secure Enclave的基於硬件的安全處理器。 Secure Enclave負責加密面部和指紋數據的數學表示,並使用此信息對用戶進行身份驗證。 根據Apple的說法,面部和指紋數據不會離開設備,也不會備份到iCloud。
應用程序通過本地身份驗證API與Secure Enclave進行交互,並且無法檢索人臉或指紋數據或直接訪問Secure Enclave。
在提供對受保護內容的訪問權限之前,應用程序可以使用Touch ID和Face ID對用戶進行身份驗證。
本地身份驗證上下文
iOS上的生物特征認證依賴於本地認證上下文對象,該對象是LAContext類的實例。 LAContext類使您可以:
- 檢查生物識別硬件的可用性。
- 評估身份驗證策略。
- 評估訪問控制。
- 自定義並顯示身份驗證提示。
- 重用或使身份驗證狀態無效。
- 管理憑據。
您可以使用身份驗證上下文,通過觸摸識別或面部識別等生物識別技術或通過提供設備密碼來評估用戶的身份。 上下文處理用戶交互,並且還連接到Secure Enclave,Secure Enclave是管理生物識別數據的基礎硬件元素。 您創建並配置上下文,並要求其執行身份驗證。 然后,您將收到一個異步回調,該回調提供身份驗證成功或失敗的指示,以及一個錯誤實例,該實例說明失敗的原因(如果有)
更多參考:https://developer.apple.com/documentation/localauthentication/lacontext
檢測可用的身份驗證方法
該示例項目包括一個由AuthenticationViewController支持的AuthenticationView。 此類重寫ViewWillAppear方法以檢測可用的身份驗證方法:

partial class AuthenticationViewController: UIViewController { // ... string BiometryType = ""; public override void ViewWillAppear(bool animated) { base.ViewWillAppear(animated); unAuthenticatedLabel.Text = ""; var context = new LAContext(); var buttonText = ""; // Is login with biometrics possible? if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out var authError1)) { // has Touch ID or Face ID if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0)) { context.LocalizedReason = "Authorize for access to secrets"; // iOS 11 BiometryType = context.BiometryType == LABiometryType.TouchId ? "Touch ID" : "Face ID"; buttonText = $"Login with {BiometryType}"; } // No FaceID before iOS 11 else { buttonText = $"Login with Touch ID"; } } // Is pin login possible? else if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthentication, out var authError2)) { buttonText = $"Login"; // with device PIN BiometryType = "Device PIN"; } // Local authentication not possible else { // Application might choose to implement a custom username/password buttonText = "Use unsecured"; BiometryType = "none"; } AuthenticateButton.SetTitle(buttonText, UIControlState.Normal); } }
當UI將要顯示給用戶時,將調用ViewWillAppear方法。 此方法定義LAContext的新實例,並使用CanEvaluatePolicy方法確定是否啟用了生物特征認證。 如果是這樣,它將檢查系統版本和BiometryType枚舉,以確定哪些生物特征選項可用。
如果未啟用生物特征認證,則該應用會嘗試回退到PIN認證。 如果生物特征認證和PIN認證均不可用,則設備所有者尚未啟用安全功能,並且無法通過本地認證來保護內容。
驗證用戶
示例項目中的AuthenticationViewController包含一個AuthenticateMe方法,該方法負責認證用戶:

partial class AuthenticationViewController: UIViewController { // ... string BiometryType = ""; partial void AuthenticateMe(UIButton sender) { var context = new LAContext(); NSError AuthError; var localizedReason = new NSString("To access secrets"); // Because LocalAuthentication APIs have been extended over time, // you must check iOS version before setting some properties context.LocalizedFallbackTitle = "Fallback"; if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0)) { context.LocalizedCancelTitle = "Cancel"; } if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0)) { context.LocalizedReason = "Authorize for access to secrets"; BiometryType = context.BiometryType == LABiometryType.TouchId ? "TouchID" : "FaceID"; } // Check if biometric authentication is possible if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, out AuthError)) { replyHandler = new LAContextReplyHandler((success, error) => { // This affects UI and must be run on the main thread this.InvokeOnMainThread(() => { if (success) { PerformSegue("AuthenticationSegue", this); } else { unAuthenticatedLabel.Text = $"{BiometryType} Authentication Failed"; } }); }); context.EvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason, replyHandler); } // Fall back to PIN authentication else if (context.CanEvaluatePolicy(LAPolicy.DeviceOwnerAuthentication, out AuthError)) { replyHandler = new LAContextReplyHandler((success, error) => { // This affects UI and must be run on the main thread this.InvokeOnMainThread(() => { if (success) { PerformSegue("AuthenticationSegue", this); } else { unAuthenticatedLabel.Text = "Device PIN Authentication Failed"; AuthenticateButton.Hidden = true; } }); }); context.EvaluatePolicy(LAPolicy.DeviceOwnerAuthentication, localizedReason, replyHandler); } // User hasn't configured any authentication: show dialog with options else { unAuthenticatedLabel.Text = "No device auth configured"; var okCancelAlertController = UIAlertController.Create("No authentication", "This device does't have authentication configured.", UIAlertControllerStyle.Alert); okCancelAlertController.AddAction(UIAlertAction.Create("Use unsecured", UIAlertActionStyle.Default, alert => PerformSegue("AuthenticationSegue", this))); okCancelAlertController.AddAction(UIAlertAction.Create("Cancel", UIAlertActionStyle.Cancel, alert => Console.WriteLine("Cancel was clicked"))); PresentViewController(okCancelAlertController, true, null); } } }
響應於用戶點擊登錄按鈕,調用AuthenticateMe方法。 實例化一個新的LAContext對象,並檢查設備版本,以確定要在本地身份驗證上下文上設置的屬性。
調用CanEvaluatePolicy方法以檢查是否啟用了生物特征認證,並在可能的情況下退回PIN認證,如果沒有可用的認證,則最終提供不安全的模式。 如果有身份驗證方法可用,則使用EvaluatePolicy方法顯示UI並完成身份驗證過程。
該示例項目包含模擬數據和一個視圖,如果身份驗證成功,該視圖將顯示數據。