簡(jiǎn)介
Touch ID是蘋果公司的一種指紋識(shí)別技術(shù),從iPhone 5s開始,早已為人們所熟知。
Touch ID不存儲(chǔ)用戶的任何指紋圖像,只保存代表指紋的數(shù)字字符。蘋果公司提供Touch ID給第三方應(yīng)用程序使用,程序只會(huì)收到認(rèn)證是否成功的通知,而無(wú)法訪問 Touch ID 或與已注冊(cè)指紋相關(guān)的數(shù)據(jù),這一點(diǎn)對(duì)安全而言尤為重要。
現(xiàn)在有很多銀行類APP、涉及到支付類的APP都集成了指紋、手勢(shì)等二次驗(yàn)證功能,從而使APP獲得更高的安全性。今天我們就來(lái)分析一下指紋識(shí)別登錄功能的具體實(shí)現(xiàn)。
實(shí)現(xiàn)步驟
1.首先引入指紋解鎖的庫(kù)文件
#import <LocalAuthentication/LocalAuthentication.h>
2.兩個(gè)主要方法
///這個(gè)方法是判斷設(shè)備是否支持TouchID的
- (BOOL)canEvaluatePolicy:(LAPolicy)policy error:(NSError * __autoreleasing *)error __attribute__((swift_error(none)))
API_AVAILABLE(macos(10.10), ios(8.0), watchos(3.0), tvos(10.0));
///這個(gè)是用來(lái)驗(yàn)證TouchID的,會(huì)有彈出框出來(lái)
- (void)evaluatePolicy:(LAPolicy)policy
localizedReason:(NSString *)localizedReason
reply:(void(^)(BOOL success, NSError * __nullable error))reply
API_AVAILABLE(macos(10.10), ios(8.0), watchos(3.0), tvos(10.0));
3.核心源碼
- (void)touchID {
//創(chuàng)建LAContext
LAContext *context = [LAContext new];
//這個(gè)屬性是設(shè)置指紋輸入失敗之后的彈出框的選項(xiàng)
context.localizedFallbackTitle = @"沒有忘記密碼";
///錯(cuò)誤信息
NSError *error = nil;
///這個(gè)方法是判斷設(shè)備是否支持TouchID的
BOOL isUseTouchID = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
if (isUseTouchID) {
NSLog(@"支持指紋識(shí)別");
//這個(gè)是用來(lái)驗(yàn)證TouchID的,會(huì)有彈出框出來(lái)
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:@"請(qǐng)按home鍵指紋登錄" reply:^(BOOL success, NSError * _Nullable error) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"驗(yàn)證成功");
});
}else{
NSLog(@"%@",error.localizedDescription);
switch (error.code) {
case LAErrorSystemCancel:
{
NSLog(@"系統(tǒng)取消授權(quán),如其他APP切入");
break;
}
case LAErrorUserCancel:
{
NSLog(@"用戶取消驗(yàn)證Touch ID");
break;
}
case LAErrorAuthenticationFailed:
{
NSLog(@"授權(quán)失敗");
break;
}
case LAErrorPasscodeNotSet:
{
NSLog(@"系統(tǒng)未設(shè)置密碼");
break;
}
case LAErrorBiometryNotAvailable:
{
NSLog(@"設(shè)備Touch ID不可用,例如未打開");
break;
}
case LAErrorBiometryNotEnrolled:
{
NSLog(@"設(shè)備Touch ID不可用,用戶未錄入");
break;
}
case LAErrorUserFallback:
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"用戶選擇輸入密碼,切換主線程處理");
}];
break;
}
default:
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"其他情況,切換主線程處理");
}];
break;
}
}
}
}];
}else{
NSLog(@"不支持指紋識(shí)別");
switch (error.code) {
case LAErrorBiometryNotEnrolled:
{
NSLog(@"TouchID is not enrolled TouchID未注冊(cè)");
break;
}
case LAErrorPasscodeNotSet:
{
NSLog(@"A passcode has not been set 未設(shè)置密碼");
break;
}
default:
{
NSLog(@"TouchID not available TouchID不可用");
break;
}
}
NSLog(@"%@",error.localizedDescription);
}
}
原文鏈接:iOS 指紋識(shí)別登錄功能實(shí)現(xiàn)
============
項(xiàng)目中的優(yōu)化
實(shí)際項(xiàng)目中這個(gè)業(yè)務(wù)實(shí)現(xiàn)的難點(diǎn)在于,首次登錄成功并啟用指紋授權(quán)--->退出APP后--->二次啟動(dòng)APP,如何判斷是否要啟用指紋登錄驗(yàn)證呢?這時(shí)就需要我們對(duì)數(shù)據(jù)持久化和數(shù)據(jù)共享有較深的理解,很多APP開發(fā)者,在開發(fā)登錄保持的時(shí)候,大都會(huì)使用持久化數(shù)據(jù)的方式,存儲(chǔ)成功登錄的標(biāo)記。但對(duì)于安全性較高的APP,每次重新啟動(dòng)時(shí)都會(huì)校驗(yàn)登錄狀態(tài),單靠持久化數(shù)據(jù)是不夠的。
我的解決方案是:
通過三個(gè)數(shù)據(jù)進(jìn)行登錄保持
loginState:持久化數(shù)據(jù),用于存儲(chǔ)用戶登錄成功,未激活狀態(tài);
startAutoLoginState:持久化數(shù)據(jù),是否開啟指紋識(shí)別授權(quán);
isAppCurrentLoginState:共享數(shù)據(jù),登錄激活狀態(tài),該狀態(tài)的特點(diǎn),每次重新啟動(dòng)APP都會(huì)重新初始化數(shù)據(jù)。
原文鏈接:iOS指紋識(shí)別登錄流程及實(shí)現(xiàn)
typedef NS_ENUM(NSInteger, LAError)
{
//身份驗(yàn)證不成功,因?yàn)橛脩魺o(wú)法提供有效的憑據(jù)。
LAErrorAuthenticationFailed = kLAErrorAuthenticationFailed,
//認(rèn)證被用戶取消(例如了取消按鈕)。
LAErrorUserCancel = kLAErrorUserCancel,
//認(rèn)證被取消了,因?yàn)橛脩衾没赝税粹o(輸入密碼)。
LAErrorUserFallback = kLAErrorUserFallback,
//身份驗(yàn)證被系統(tǒng)取消了(如另一個(gè)應(yīng)用程序去前臺(tái))。
LAErrorSystemCancel = kLAErrorSystemCancel,
//身份驗(yàn)證無(wú)法啟動(dòng),因?yàn)樵O(shè)備沒有設(shè)置密碼。
LAErrorPasscodeNotSet = kLAErrorPasscodeNotSet,
//身份驗(yàn)證無(wú)法啟動(dòng),因?yàn)橛|摸ID不可用在設(shè)備上。
LAErrorTouchIDNotAvailable NS_ENUM_DEPRECATED(10_10, 10_13, 8_0, 11_0, "use LAErrorBiometryNotAvailable") = kLAErrorTouchIDNotAvailable,
//身份驗(yàn)證無(wú)法啟動(dòng),因?yàn)闆]有登記的手指觸摸ID。
LAErrorTouchIDNotEnrolled NS_ENUM_DEPRECATED(10_10, 10_13, 8_0, 11_0, "use LAErrorBiometryNotEnrolled") = kLAErrorTouchIDNotEnrolled,
//驗(yàn)證不成功,因?yàn)橛刑嗟氖〉挠|摸ID嘗試和觸///摸現(xiàn)在ID是鎖著的。
//解鎖TouchID必須要使用密碼,例如調(diào)用LAPolicyDeviceOwnerAuthenti//cationWithBiometrics的時(shí)候密碼是必要條件。
//身份驗(yàn)證不成功,因?yàn)橛刑嗍〉挠|摸ID嘗試和觸摸ID現(xiàn)在被鎖定。
LAErrorTouchIDLockout NS_ENUM_DEPRECATED(10_11, 10_13, 9_0, 11_0, "use LAErrorBiometryLockout")
__WATCHOS_DEPRECATED(3.0, 4.0, "use LAErrorBiometryLockout") __TVOS_DEPRECATED(10.0, 11.0, "use LAErrorBiometryLockout") = kLAErrorTouchIDLockout,
//應(yīng)用程序取消了身份驗(yàn)證(例如在進(jìn)行身份驗(yàn)證時(shí)調(diào)用了無(wú)效)。
LAErrorAppCancel NS_ENUM_AVAILABLE(10_11, 9_0) = kLAErrorAppCancel,
//LAContext傳遞給這個(gè)調(diào)用之前已經(jīng)失效。
LAErrorInvalidContext NS_ENUM_AVAILABLE(10_11, 9_0) = kLAErrorInvalidContext,
//身份驗(yàn)證無(wú)法啟動(dòng),因?yàn)樯镒R(shí)別驗(yàn)證在當(dāng)前這個(gè)設(shè)備上不可用。
LAErrorBiometryNotAvailable NS_ENUM_AVAILABLE(10_13, 11_0) __WATCHOS_AVAILABLE(4.0) __TVOS_AVAILABLE(11.0) = kLAErrorBiometryNotAvailable,
//身份驗(yàn)證無(wú)法啟動(dòng),因?yàn)樯镒R(shí)別沒有錄入信息。
LAErrorBiometryNotEnrolled NS_ENUM_AVAILABLE(10_13, 11_0) __WATCHOS_AVAILABLE(4.0) __TVOS_AVAILABLE(11.0) = kLAErrorBiometryNotEnrolled,
//身份驗(yàn)證不成功,因?yàn)樘啻蔚尿?yàn)證失敗并且生物識(shí)別驗(yàn)證是鎖定狀態(tài)。此時(shí),必須輸入密碼才能解鎖。例如LAPolicyDeviceOwnerAuthenticationWithBiometrics時(shí)候?qū)⒚艽a作為先決條件。
LAErrorBiometryLockout NS_ENUM_AVAILABLE(10_13, 11_0) __WATCHOS_AVAILABLE(4.0) __TVOS_AVAILABLE(11.0) = kLAErrorBiometryLockout,
//身份驗(yàn)證失敗。因?yàn)檫@需要顯示UI已禁止使用interactionNotAllowed屬性。 據(jù)說(shuō)是beta版本
LAErrorNotInteractive API_AVAILABLE(macos(10.10), ios(8.0), watchos(3.0), tvos(10.0)) = kLAErrorNotInteractive,
} NS_ENUM_AVAILABLE(10_10, 8_0) __WATCHOS_AVAILABLE(3.0) __TVOS_AVAILABLE(10.0);
FaceID
注意要添加權(quán)限
Privacy - Face ID Usage Description
1.首先引入指紋解鎖的庫(kù)文件
#import <LocalAuthentication/LocalAuthentication.h>
2.核心源碼
-(void)faceID{
NSError *error;
LAContext *context = [[LAContext alloc]init];
BOOL canAuthentication = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error];
if (canAuthentication) {
[context evaluatePolicy:LAPolicyDeviceOwnerAuthentication localizedReason:@"FaceID驗(yàn)證" reply:^(BOOL success, NSError * _Nullable error) {
//注意iOS 11.3之后需要配置Info.plist權(quán)限才可以通過Face ID驗(yàn)證哦!不然只能輸密碼啦...
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"驗(yàn)證成功");
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"當(dāng)前軟件被掛起并取消了授權(quán) (如App進(jìn)入了后臺(tái)等)");
NSLog(@"error-->%@",error);
});
}
}];
}
}
========
判斷設(shè)備是否支持TouchID 和 FaceID
-(void)justTouchIDFaceID{
// 檢測(cè)設(shè)備是否支持TouchID或者FaceID
if (@available(iOS 8.0, *)) {
LAContext *LAContent = [[LAContext alloc] init];
NSError *authError = nil;
BOOL isCanEvaluatePolicy = [LAContent canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&authError];
if (authError) {
NSLog(@"檢測(cè)設(shè)備是否支持TouchID或者FaceID失?。n error : == %@",authError.localizedDescription);
} else {
if (isCanEvaluatePolicy) {
// 判斷設(shè)備支持TouchID還是FaceID
if (@available(iOS 11.0, *)) {
switch (LAContent.biometryType) {
case LABiometryTypeNone:
{
NSLog(@"The device does not support biometry.");
}
break;
case LABiometryTypeTouchID:
{
NSLog(@"The device supports Touch ID.");
}
break;
case LABiometryTypeFaceID:
{
NSLog(@"The device supports Face ID.");
}
break;
default:
break;
}
} else {
// Fallback on earlier versions
NSLog(@"iOS 11之前不需要判斷 biometryType");
// 因?yàn)閕PhoneX起始系統(tǒng)版本都已經(jīng)是iOS11.0,所以iOS11.0系統(tǒng)版本下不需要再去判斷是否支持faceID,直接走支持TouchID邏輯即可。
NSLog(@"The device supports Face ID.");
}
} else {
NSLog(@"The device does not support biometry.");
}
}
} else {
// Fallback on earlier versions
NSLog(@"The device does not support biometry.");
}
}
