├── BATouchID.podspec ├── BATouchID.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── boai.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── boai.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── BATouchID.xcscheme │ └── xcschememanagement.plist ├── BATouchID ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── tabbar_mainframeHL.imageset │ │ ├── Contents.json │ │ ├── tabbar_mainframeHL@2x.png │ │ └── tabbar_mainframeHL@3x.png │ └── touchID.imageset │ │ ├── Contents.json │ │ ├── touchID@2x.png │ │ └── touchID@3x.png ├── BATouchID │ ├── BAKit_DeviceModel.h │ ├── BAKit_DeviceModel.m │ ├── BAKit_TouchID.h │ ├── BAKit_TouchID.m │ └── BATouchID.h ├── BATouchIDDemo.pch ├── BATouchIDLoginVC.h ├── BATouchIDLoginVC.m ├── BAUnlockedGestureVC.h ├── BAUnlockedGestureVC.m ├── BAUnlockedGestureVC.xib ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── Lib │ ├── BAButton │ │ ├── BAButton.h │ │ ├── UIButton+BAKit.h │ │ ├── UIButton+BAKit.m │ │ ├── UIView+BARectCorner.h │ │ └── UIView+BARectCorner.m │ ├── BAKit │ │ ├── NSObject+BARunTime.h │ │ ├── NSObject+BARunTime.m │ │ ├── NSString+BAKit.h │ │ ├── NSString+BAKit.m │ │ ├── UIAlertController+Blocks.h │ │ └── UIAlertController+Blocks.m │ └── 手势解锁 │ │ └── CoreLock │ │ ├── CLLockVC.h │ │ ├── CLLockVC.m │ │ ├── CLLockVC.xib │ │ ├── FrameWork │ │ ├── CoreArchive │ │ │ ├── Category │ │ │ │ ├── NSString+File.h │ │ │ │ └── NSString+File.m │ │ │ ├── CoreArchive.h │ │ │ └── CoreArchive.m │ │ └── CoreExtend │ │ │ └── CoreConst.h │ │ └── Lib │ │ ├── Category │ │ ├── CALayer+Anim.h │ │ └── CALayer+Anim.m │ │ ├── Const │ │ ├── CoreLockConst.h │ │ └── CoreLockConst.m │ │ ├── Controller │ │ ├── CLLockNavVC.h │ │ └── CLLockNavVC.m │ │ └── View │ │ ├── CLLockInfoView.h │ │ ├── CLLockInfoView.m │ │ ├── CLLockItemView.h │ │ ├── CLLockItemView.m │ │ ├── CLLockLabel.h │ │ ├── CLLockLabel.m │ │ ├── CLLockMainView.h │ │ ├── CLLockMainView.m │ │ ├── CLLockView.h │ │ └── CLLockView.m ├── LoginViewController.h ├── LoginViewController.m ├── LoginViewController.xib ├── SettingVC.h ├── SettingVC.m ├── SettingVC.xib ├── ViewController.h ├── ViewController.m ├── icon1.jpg ├── main.m └── 美女.jpg ├── Images ├── BATouchID.png └── 支付宝指纹登录流程图.png ├── LICENSE └── README.md /BATouchID.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'BATouchID' 3 | s.version = '1.0.1' 4 | s.summary = 'git 最全面的指纹解锁封装和支付宝指纹登录逻辑处理!' 5 | s.homepage = 'https://github.com/BAHome/BATouchID' 6 | s.license = 'MIT' 7 | s.authors = { 'boai' => 'sunboyan@outlook.com' } 8 | s.platform = :ios, '7.0' 9 | s.source = { :git => 'https://github.com/BAHome/BATouchID.git', :tag => s.version.to_s } 10 | s.source_files = 'BATouchID/BATouchID/*.{h,m}' 11 | s.requires_arc = true 12 | end 13 | -------------------------------------------------------------------------------- /BATouchID.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /BATouchID.xcodeproj/project.xcworkspace/xcuserdata/boai.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BAHome/BATouchID/a3280aa457c48c152b635996de24d594b9ecce46/BATouchID.xcodeproj/project.xcworkspace/xcuserdata/boai.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /BATouchID.xcodeproj/xcuserdata/boai.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /BATouchID.xcodeproj/xcuserdata/boai.xcuserdatad/xcschemes/BATouchID.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /BATouchID.xcodeproj/xcuserdata/boai.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | BATouchID.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | C492318A1ED52A7000B61C37 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /BATouchID/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/24. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /BATouchID/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/24. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "BATouchID.h" 11 | #import "BATouchIDLoginVC.h" 12 | 13 | #import "NSString+BAKit.h" 14 | 15 | #import "ViewController.h" 16 | 17 | @interface AppDelegate () 18 | 19 | @end 20 | 21 | @implementation AppDelegate 22 | 23 | 24 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 25 | // Override point for customization after application launch. 26 | 27 | [self checkIsAlreadyOpenTouchIDIsStart:YES]; 28 | 29 | return YES; 30 | } 31 | 32 | - (void)applicationWillResignActive:(UIApplication *)application { 33 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 34 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 35 | } 36 | 37 | - (void)applicationDidEnterBackground:(UIApplication *)application 38 | { 39 | [kUserDefaults setObject:[NSDate date] forKey:kLastEnterBackgroundDate]; 40 | } 41 | 42 | - (void)applicationWillEnterForeground:(UIApplication *)application { 43 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 44 | 45 | [self test]; 46 | } 47 | 48 | - (void)test 49 | { 50 | NSDate *date = [kUserDefaults objectForKey:kLastEnterBackgroundDate]; 51 | 52 | // 进入后台 10 秒后需要重新验证指纹 53 | if (!date || [[NSString ba_intervalSinceNow:date] floatValue] > 1*3) 54 | { 55 | [self checkIsAlreadyOpenTouchIDIsStart:NO]; 56 | } 57 | } 58 | 59 | - (void)checkIsAlreadyOpenTouchIDIsStart:(BOOL)isStart 60 | { 61 | id isLogin = [kUserDefaults objectForKey:kIsLogin]; 62 | id isOpenTouchID = [kUserDefaults objectForKey:kIsOpenTouchID]; 63 | 64 | if ([isLogin intValue] == 1) 65 | { 66 | if ([isOpenTouchID intValue] == 1) 67 | { 68 | 69 | BATouchIDLoginVC *vc = [BATouchIDLoginVC new]; 70 | UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:vc]; 71 | if (isStart) 72 | { 73 | vc.isStart = YES; 74 | [[UIApplication sharedApplication].windows lastObject].rootViewController = navi; 75 | } 76 | else 77 | { 78 | [self.window.rootViewController presentViewController:navi animated:NO completion:nil]; 79 | } 80 | } 81 | } 82 | } 83 | 84 | - (void)applicationDidBecomeActive:(UIApplication *)application { 85 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 86 | } 87 | 88 | 89 | - (void)applicationWillTerminate:(UIApplication *)application { 90 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 91 | } 92 | 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /BATouchID/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | } 43 | ], 44 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /BATouchID/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /BATouchID/Assets.xcassets/tabbar_mainframeHL.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "tabbar_mainframeHL@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "tabbar_mainframeHL@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /BATouchID/Assets.xcassets/tabbar_mainframeHL.imageset/tabbar_mainframeHL@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BAHome/BATouchID/a3280aa457c48c152b635996de24d594b9ecce46/BATouchID/Assets.xcassets/tabbar_mainframeHL.imageset/tabbar_mainframeHL@2x.png -------------------------------------------------------------------------------- /BATouchID/Assets.xcassets/tabbar_mainframeHL.imageset/tabbar_mainframeHL@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BAHome/BATouchID/a3280aa457c48c152b635996de24d594b9ecce46/BATouchID/Assets.xcassets/tabbar_mainframeHL.imageset/tabbar_mainframeHL@3x.png -------------------------------------------------------------------------------- /BATouchID/Assets.xcassets/touchID.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "touchID@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "touchID@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /BATouchID/Assets.xcassets/touchID.imageset/touchID@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BAHome/BATouchID/a3280aa457c48c152b635996de24d594b9ecce46/BATouchID/Assets.xcassets/touchID.imageset/touchID@2x.png -------------------------------------------------------------------------------- /BATouchID/Assets.xcassets/touchID.imageset/touchID@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BAHome/BATouchID/a3280aa457c48c152b635996de24d594b9ecce46/BATouchID/Assets.xcassets/touchID.imageset/touchID@3x.png -------------------------------------------------------------------------------- /BATouchID/BATouchID/BAKit_DeviceModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // BAKit_DeviceModel.h 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/24. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BAKit_DeviceModel : NSObject 12 | 13 | /* 14 | 获取设备描述 15 | */ 16 | + (NSString *)ba_deviceGetCurrentDeviceModelDescription; 17 | 18 | /* 19 | 由获取到的设备描述,来匹配设备型号 20 | */ 21 | + (NSString *)ba_deviceGetCurrentDeviceModel; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /BATouchID/BATouchID/BAKit_DeviceModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // BAKit_DeviceModel.m 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/24. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import "BAKit_DeviceModel.h" 10 | #import 11 | 12 | @implementation BAKit_DeviceModel 13 | 14 | + (NSString *)ba_deviceGetCurrentDeviceModelDescription 15 | { 16 | int mib[2]; 17 | size_t len; 18 | char *machine; 19 | 20 | mib[0] = CTL_HW; 21 | mib[1] = HW_MACHINE; 22 | sysctl(mib, 2, NULL, &len, NULL, 0); 23 | machine = malloc(len); 24 | sysctl(mib, 2, machine, &len, NULL, 0); 25 | 26 | NSString *platform = [NSString stringWithCString:machine encoding:NSASCIIStringEncoding]; 27 | free(machine); 28 | return platform; 29 | } 30 | 31 | + (NSString *)ba_deviceGetCurrentDeviceModel 32 | { 33 | NSString *platform = [BAKit_DeviceModel ba_deviceGetCurrentDeviceModelDescription]; 34 | 35 | if ([platform isEqualToString:@"iPhone1,1"]) return @"iPhone 2G"; 36 | if ([platform isEqualToString:@"iPhone1,2"]) return @"iPhone 3G"; 37 | if ([platform isEqualToString:@"iPhone2,1"]) return @"iPhone 3GS"; 38 | 39 | if ([platform isEqualToString:@"iPhone3,1"]) return @"iPhone 4"; 40 | if ([platform isEqualToString:@"iPhone3,2"]) return @"iPhone 4"; 41 | if ([platform isEqualToString:@"iPhone3,3"]) return @"iPhone 4"; 42 | if ([platform isEqualToString:@"iPhone4,1"]) return @"iPhone 4S"; 43 | 44 | if ([platform isEqualToString:@"iPhone5,1"]) return @"iPhone 5"; 45 | if ([platform isEqualToString:@"iPhone5,2"]) return @"iPhone 5"; 46 | 47 | if ([platform isEqualToString:@"iPhone5,3"]) return @"iPhone 5c"; 48 | if ([platform isEqualToString:@"iPhone5,4"]) return @"iPhone 5c"; 49 | 50 | if ([platform isEqualToString:@"iPhone6,1"]) return @"iPhone 5s"; 51 | if ([platform isEqualToString:@"iPhone6,2"]) return @"iPhone 5s"; 52 | 53 | if ([platform isEqualToString:@"iPhone7,1"]) return @"iPhone 6 Plus"; 54 | if ([platform isEqualToString:@"iPhone7,2"]) return @"iPhone 6"; 55 | 56 | if ([platform isEqualToString:@"iPhone8,1"]) return @"iPhone 6S"; 57 | if ([platform isEqualToString:@"iPhone8,2"]) return @"iPhone 6S Plus"; 58 | 59 | if ([platform isEqualToString:@"iPhone9,1"]) return @"iPhone 7 A1660"; 60 | if ([platform isEqualToString:@"iPhone9,2"]) return @"iPhone 7 Plus A1661"; 61 | if ([platform isEqualToString:@"iPhone9,3"]) return @"iPhone 7 A1778"; 62 | if ([platform isEqualToString:@"iPhone9,4"]) return @"iPhone 7 Plus A1784"; 63 | 64 | if ([platform isEqualToString:@"iPod1,1"]) return @"iPod Touch 1G"; 65 | if ([platform isEqualToString:@"iPod2,1"]) return @"iPod Touch 2G"; 66 | if ([platform isEqualToString:@"iPod3,1"]) return @"iPod Touch 3G"; 67 | if ([platform isEqualToString:@"iPod4,1"]) return @"iPod Touch 4G"; 68 | if ([platform isEqualToString:@"iPod5,1"]) return @"iPod Touch 5G"; 69 | 70 | if ([platform isEqualToString:@"iPad1,1"]) return @"iPad 1G"; 71 | 72 | if ([platform isEqualToString:@"iPad2,1"]) return @"iPad 2"; 73 | if ([platform isEqualToString:@"iPad2,2"]) return @"iPad 2"; 74 | if ([platform isEqualToString:@"iPad2,3"]) return @"iPad 2"; 75 | if ([platform isEqualToString:@"iPad2,4"]) return @"iPad 2"; 76 | 77 | if ([platform isEqualToString:@"iPad2,5"]) return @"iPad Mini 1G"; 78 | if ([platform isEqualToString:@"iPad2,6"]) return @"iPad Mini 1G"; 79 | if ([platform isEqualToString:@"iPad2,7"]) return @"iPad Mini 1G"; 80 | 81 | if ([platform isEqualToString:@"iPad3,1"]) return @"iPad 3"; 82 | if ([platform isEqualToString:@"iPad3,2"]) return @"iPad 3"; 83 | if ([platform isEqualToString:@"iPad3,3"]) return @"iPad 3"; 84 | if ([platform isEqualToString:@"iPad3,4"]) return @"iPad 4"; 85 | if ([platform isEqualToString:@"iPad3,5"]) return @"iPad 4"; 86 | if ([platform isEqualToString:@"iPad3,6"]) return @"iPad 4"; 87 | 88 | if ([platform isEqualToString:@"iPad4,1"]) return @"iPad Air"; 89 | if ([platform isEqualToString:@"iPad4,2"]) return @"iPad Air"; 90 | if ([platform isEqualToString:@"iPad4,3"]) return @"iPad Air"; 91 | 92 | if ([platform isEqualToString:@"iPad4,4"]) return @"iPad Mini 2G "; 93 | if ([platform isEqualToString:@"iPad4,5"]) return @"iPad Mini 2G "; 94 | if ([platform isEqualToString:@"iPad4,6"]) return @"iPad Mini 2G "; 95 | 96 | if ([platform isEqualToString:@"iPad4,7"]) return @"iPad Mini 3 "; 97 | if ([platform isEqualToString:@"iPad4,8"]) return @"iPad Mini 3 "; 98 | if ([platform isEqualToString:@"iPad4,9"]) return @"iPad Mini 3 "; 99 | 100 | if ([platform isEqualToString:@"iPad5,1"]) return @"iPad Mini 4 WiFi "; 101 | if ([platform isEqualToString:@"iPad5,2"]) return @"iPad Mini 4 WiFi+Cellular "; 102 | 103 | if ([platform isEqualToString:@"iPad5,3"]) return @"iPad Air2 "; 104 | if ([platform isEqualToString:@"iPad5,4"]) return @"iPad Air2 "; 105 | 106 | if ([platform isEqualToString:@"iPad6,7"]) return @"iPad Pro WiFi 12.7-inch"; 107 | if ([platform isEqualToString:@"iPad6,8"]) return @"iPad Pro WiFi+Cellular 12.7-inch"; 108 | 109 | if ([platform isEqualToString:@"iPad6,3"]) return @"iPad Pro WiFi 9.7-inch"; 110 | if ([platform isEqualToString:@"iPad6,4"]) return @"iPad Pro WiFi+Cellular 9.7-inch"; 111 | 112 | if ([platform isEqualToString:@"i386"]) return @"iPhone Simulator"; 113 | if ([platform isEqualToString:@"x86_64"]) return @"iPhone Simulator"; 114 | return platform; 115 | } 116 | 117 | @end 118 | -------------------------------------------------------------------------------- /BATouchID/BATouchID/BAKit_TouchID.h: -------------------------------------------------------------------------------- 1 | // 2 | // BAKit_TouchID.h 3 | // BAKit_TouchID 4 | // 5 | // Created by boai on 2017/5/22. 6 | // Copyright © 2017年 boaihome.com. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | 14 | // 操作系统版本号 15 | #define IOS_VERSION ([[[UIDevice currentDevice] systemVersion] floatValue]) 16 | 17 | /** 18 | * TouchID 状态 19 | */ 20 | typedef NS_ENUM(NSUInteger, BAKit_TouchIDType){ 21 | 22 | /** 23 | * 当前设备不支持TouchID 24 | */ 25 | BAKit_TouchIDTypeNotSupport = 0, 26 | /** 27 | * TouchID 验证成功 28 | */ 29 | BAKit_TouchIDTypeSuccess, 30 | /** 31 | * TouchID 验证失败 32 | */ 33 | BAKit_TouchIDTypeFail, 34 | /** 35 | * TouchID 被用户手动取消 36 | */ 37 | BAKit_TouchIDTypeUserCancel, 38 | /** 39 | * 用户不使用TouchID,选择手动输入密码 40 | */ 41 | BAKit_TouchIDTypeInputPassword, 42 | /** 43 | * TouchID 被系统取消 (如遇到来电,锁屏,按了Home键等) 44 | */ 45 | BAKit_TouchIDTypeSystemCancel, 46 | /** 47 | * TouchID 无法启动,因为用户没有设置密码 48 | */ 49 | BAKit_TouchIDTypePasswordNotSet, 50 | /** 51 | * TouchID 无法启动,因为用户没有设置TouchID 52 | */ 53 | BAKit_TouchIDTypeTouchIDNotSet, 54 | /** 55 | * TouchID 无效 56 | */ 57 | BAKit_TouchIDTypeTouchIDNotAvailable, 58 | /** 59 | * TouchID 被锁定(连续多次验证TouchID失败,系统需要用户手动输入密码) 60 | */ 61 | BAKit_TouchIDTypeTouchIDLockout, 62 | /** 63 | * 当前软件被挂起并取消了授权 (如App进入了后台等) 64 | */ 65 | BAKit_TouchIDTypeAppCancel, 66 | /** 67 | * 当前软件被挂起并取消了授权 (LAContext对象无效) 68 | */ 69 | BAKit_TouchIDTypeInvalidContext, 70 | /** 71 | * 系统版本不支持TouchID (必须高于iOS 8.0才能使用) 72 | */ 73 | BAKit_TouchIDTypeVersionNotSupport 74 | }; 75 | 76 | /** 77 | 指纹解锁 回调 78 | 79 | @param touchIDType 返回的类型,BAKit_TouchIDType 80 | @param error error 81 | @param errorMessage errorMessage 82 | */ 83 | typedef void (^BAKit_TouchID_Block)(BAKit_TouchIDType touchIDType, NSError *error, NSString *errorMessage); 84 | 85 | /** 86 | 判断是否支持指纹解锁 回调 87 | 88 | @param isSupport 是否支持 89 | @param context context 90 | @param policy policy 91 | @param error error 92 | */ 93 | typedef void (^BAKit_TouchIDVerifyIsSupport_Block)(BOOL isSupport, LAContext *context, NSInteger policy, NSError *error); 94 | 95 | @interface BAKit_TouchID : NSObject 96 | 97 | /** 98 | 指纹解锁 99 | 100 | @param content 提示文本 101 | @param cancelButtonTitle 取消按钮显示内容(此参数只有iOS10以上才能生效),默认(nil):取消 102 | @param otherButtonTitle 密码登录按钮显示内容,默认(nil):输入密码(nil) 103 | @param enabled 默认:NO,输入密码按钮,使用系统解锁;YES:自己操作点击密码登录 104 | @param BAKit_TouchIDTypeBlock 返回状态码和错误,可以自行单独处理 105 | */ 106 | + (void)ba_touchIDWithContent:(NSString *)content 107 | cancelButtonTitle:(NSString *)cancelButtonTitle 108 | otherButtonTitle:(NSString *)otherButtonTitle 109 | enabled:(BOOL)enabled 110 | BAKit_TouchIDTypeBlock:(BAKit_TouchID_Block)BAKit_TouchIDTypeBlock; 111 | 112 | /** 113 | 判断是否支持指纹解锁 114 | 115 | @param block block 116 | */ 117 | + (void)ba_touchIDVerifyIsSupportWithBlock:(BAKit_TouchIDVerifyIsSupport_Block)block; 118 | 119 | @end 120 | -------------------------------------------------------------------------------- /BATouchID/BATouchID/BAKit_TouchID.m: -------------------------------------------------------------------------------- 1 | // 2 | // BAKit_TouchID.m 3 | // BAKit_TouchID 4 | // 5 | // Created by boai on 2017/5/22. 6 | // Copyright © 2017年 boaihome.com. All rights reserved. 7 | // 8 | 9 | #import "BAKit_TouchID.h" 10 | #import "BAKit_DeviceModel.h" 11 | 12 | @implementation BAKit_TouchID 13 | 14 | /** 15 | 指纹解锁 16 | 17 | @param content 提示文本 18 | @param cancelButtonTitle 取消按钮显示内容(此参数只有iOS10以上才能生效),默认(nil):取消 19 | @param otherButtonTitle 密码登录按钮显示内容,默认(nil):输入密码(nil) 20 | @param enabled 默认:NO,输入密码按钮,使用系统解锁;YES:自己操作点击密码登录 21 | @param BAKit_TouchIDTypeBlock 返回状态码和错误,可以自行单独处理 22 | */ 23 | + (void)ba_touchIDWithContent:(NSString *)content 24 | cancelButtonTitle:(NSString *)cancelButtonTitle 25 | otherButtonTitle:(NSString *)otherButtonTitle 26 | enabled:(BOOL)enabled 27 | BAKit_TouchIDTypeBlock:(BAKit_TouchID_Block)BAKit_TouchIDTypeBlock 28 | { 29 | [BAKit_TouchID ba_touchIDVerifyIsSupportWithBlock:^(BOOL isSupport, LAContext *context, NSInteger policy, NSError *error) { 30 | 31 | context.localizedFallbackTitle = otherButtonTitle; 32 | NSInteger policy2; 33 | if (enabled) 34 | { 35 | policy2 = LAPolicyDeviceOwnerAuthenticationWithBiometrics; 36 | } 37 | else 38 | { 39 | policy2 = LAPolicyDeviceOwnerAuthentication; 40 | } 41 | 42 | if (isSupport) 43 | { 44 | // 支持指纹验证 45 | [context evaluatePolicy:policy2 localizedReason:content reply:^(BOOL success, NSError * _Nullable error) { 46 | if (success) 47 | { 48 | dispatch_sync(dispatch_get_main_queue(), ^{ 49 | BAKit_TouchIDTypeBlock(BAKit_TouchIDTypeSuccess, error, nil); 50 | }); 51 | 52 | return ; 53 | } 54 | else if (error) 55 | { 56 | NSString *msg = @""; 57 | switch (error.code) { 58 | case LAErrorAuthenticationFailed: 59 | { 60 | msg = @"TouchID 验证失败"; 61 | BAKit_TouchIDTypeBlock(BAKit_TouchIDTypeFail, error, msg); 62 | } 63 | break; 64 | case LAErrorUserCancel: 65 | { 66 | msg = @"TouchID 被用户手动取消"; 67 | BAKit_TouchIDTypeBlock(BAKit_TouchIDTypeUserCancel, error, msg); 68 | } 69 | break; 70 | case LAErrorUserFallback: 71 | { 72 | msg = @"用户不使用TouchID,选择手动输入密码"; 73 | BAKit_TouchIDTypeBlock(BAKit_TouchIDTypeInputPassword, error, msg); 74 | } 75 | break; 76 | case LAErrorSystemCancel: 77 | { 78 | msg = @"TouchID 被系统取消 (如遇到来电,锁屏,按了Home键等)"; 79 | BAKit_TouchIDTypeBlock(BAKit_TouchIDTypeSystemCancel, error, msg); 80 | } 81 | break; 82 | case LAErrorPasscodeNotSet: 83 | { 84 | msg = @"TouchID 无法启动,因为用户没有设置密码"; 85 | BAKit_TouchIDTypeBlock(BAKit_TouchIDTypePasswordNotSet, error, msg); 86 | } 87 | break; 88 | case LAErrorTouchIDNotEnrolled: 89 | { 90 | msg = @"TouchID 无法启动,因为用户没有设置 TouchID"; 91 | BAKit_TouchIDTypeBlock(BAKit_TouchIDTypeTouchIDNotSet, error, msg); 92 | } 93 | break; 94 | case LAErrorTouchIDNotAvailable: 95 | { 96 | msg = @"TouchID 无效"; 97 | BAKit_TouchIDTypeBlock(BAKit_TouchIDTypeTouchIDNotAvailable, error, msg); 98 | } 99 | break; 100 | 101 | if (IOS_VERSION >= 9.0) 102 | { 103 | case LAErrorTouchIDLockout: 104 | { 105 | msg = @"TouchID 被锁定(连续多次验证 TouchID 失败,系统需要用户手动输入密码)"; 106 | BAKit_TouchIDTypeBlock(BAKit_TouchIDTypeTouchIDLockout, error, msg); 107 | if (enabled) 108 | { 109 | [context evaluatePolicy:policy localizedReason:content reply:^(BOOL success, NSError * _Nullable error) {}]; 110 | } 111 | } 112 | break; 113 | case LAErrorAppCancel: 114 | { 115 | msg = @"当前软件被挂起并取消了授权 (如App进入了后台等)"; 116 | BAKit_TouchIDTypeBlock(BAKit_TouchIDTypeAppCancel, error, msg); 117 | if (enabled) 118 | { 119 | [context evaluatePolicy:policy localizedReason:content reply:^(BOOL success, NSError * _Nullable error) {}]; 120 | } 121 | } 122 | break; 123 | case LAErrorInvalidContext: 124 | { 125 | msg = @"当前软件被挂起并取消了授权 (LAContext对象无效)"; 126 | BAKit_TouchIDTypeBlock(BAKit_TouchIDTypeInvalidContext, error, msg); 127 | if (enabled) 128 | { 129 | [context evaluatePolicy:policy localizedReason:content reply:^(BOOL success, NSError * _Nullable error) {}]; 130 | } 131 | } 132 | break; 133 | } 134 | 135 | default: 136 | { 137 | msg = @"TouchID 验证失败"; 138 | if (enabled) 139 | { 140 | [context evaluatePolicy:policy localizedReason:content reply:^(BOOL success, NSError * _Nullable error) {}]; 141 | } 142 | } 143 | break; 144 | } 145 | NSLog(@"%@", msg); 146 | } 147 | }]; 148 | } 149 | else 150 | { 151 | NSString *msg = @""; 152 | msg = [NSString stringWithFormat:@"此设备不支持Touch ID\n设备操作系统:%@\n设备系统版本号:%@\n设备型号:%@", [[UIDevice currentDevice] systemVersion], [[UIDevice currentDevice] systemName], [BAKit_DeviceModel ba_deviceGetCurrentDeviceModel]]; 153 | 154 | BAKit_TouchIDTypeBlock(BAKit_TouchIDTypeNotSupport, nil, msg); 155 | } 156 | }]; 157 | } 158 | 159 | /** 160 | 判断是否支持指纹解锁 161 | 162 | @param block block 163 | */ 164 | + (void)ba_touchIDVerifyIsSupportWithBlock:(BAKit_TouchIDVerifyIsSupport_Block)block 165 | { 166 | LAContext *context = [LAContext new]; 167 | context.maxBiometryFailures = @(3); // 接收的最大的错误次数 168 | 169 | NSInteger policy; 170 | if (IOS_VERSION < 9.0 && IOS_VERSION >= 8.0) 171 | { 172 | policy = LAPolicyDeviceOwnerAuthenticationWithBiometrics; 173 | } 174 | else 175 | { 176 | policy = LAPolicyDeviceOwnerAuthentication; 177 | } 178 | 179 | // 错误对象 180 | NSError *error = nil; 181 | 182 | // 首先使用 canEvaluatePolicy 判断设备支持状态 183 | BOOL isSupport = [context canEvaluatePolicy:policy error:&error]; 184 | block(isSupport, context, policy, error); 185 | } 186 | 187 | @end 188 | -------------------------------------------------------------------------------- /BATouchID/BATouchID/BATouchID.h: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | * @header BAKit.h 4 | * BABaseProject 5 | * 6 | * @brief BAKit 7 | * 8 | * @author 博爱 9 | * @copyright Copyright © 2016年 博爱. All rights reserved. 10 | * @version V1.0 11 | */ 12 | 13 | // _ooOoo_ 14 | // o8888888o 15 | // 88" . "88 16 | // (| -_- |) 17 | // O\ = /O 18 | // ____/`---'\____ 19 | // . ' \\| |// `. 20 | // / \\||| : |||// \ 21 | // / _||||| -:- |||||- \ 22 | // | | \\\ - /// | | 23 | // | \_| ''\---/'' | | 24 | // \ .-\__ `-` ___/-. / 25 | // ___`. .' /--.--\ `. . __ 26 | // ."" '< `.___\_<|>_/___.' >'"". 27 | // | | : `- \`.;`\ _ /`;.`/ - ` : | | 28 | // \ \ `-. \_ __\ /__ _/ .-` / / 29 | // ======`-.____`-.___\_____/___.-`____.-'====== 30 | // `=---=' 31 | // 32 | // ............................................. 33 | // 佛祖镇楼 BUG辟易 34 | // 佛曰: 35 | // 写字楼里写字间,写字间里程序员; 36 | // 程序人员写程序,又拿程序换酒钱。 37 | // 酒醒只在网上坐,酒醉还来网下眠; 38 | // 酒醉酒醒日复日,网上网下年复年。 39 | // 但愿老死电脑间,不愿鞠躬老板前; 40 | // 奔驰宝马贵者趣,公交自行程序员。 41 | // 别人笑我忒疯癫,我笑自己命太贱; 42 | // 不见满街漂亮妹,哪个归得程序员? 43 | 44 | /* 45 | 46 | ********************************************************************************* 47 | * 48 | * 在使用BAKit的过程中如果出现bug请及时以以下任意一种方式联系我,我会及时修复bug 49 | * 50 | * QQ : 可以添加ios开发技术群 479663605 在这里找到我(博爱1616【137361770】) 51 | * 微博 : 博爱1616 52 | * Email : 137361770@qq.com 53 | * GitHub : https://github.com/boai 54 | * 博客 : http://boaihome.com 55 | 56 | ********************************************************************************* 57 | 58 | */ 59 | 60 | 61 | #ifndef BATouchID_h 62 | #define BATouchID_h 63 | 64 | #import "BAKit_TouchID.h" 65 | 66 | 67 | /*! view 用 BAKit_ShowAlertWithMsg */ 68 | #define BAKit_ShowAlertWithMsg(msg) [[[UIAlertView alloc] initWithTitle:@"温馨提示" message:(msg) delegate:nil cancelButtonTitle:@"确 定" otherButtonTitles:nil] show]; 69 | 70 | /*! VC 用 BAKit_ShowAlertWithMsg */ 71 | #define BAKit_ShowAlertWithMsg_ios8(msg) UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"温馨提示" message:msg preferredStyle:UIAlertControllerStyleAlert];\ 72 | UIAlertAction *sureAction = [UIAlertAction actionWithTitle:@"确 定" style:UIAlertActionStyleDefault handler:nil];\ 73 | [alert addAction:sureAction];\ 74 | [self presentViewController:alert animated:YES completion:nil]; 75 | 76 | /*! 77 | ********************************************************************************* 78 | ************************************ 更新说明 ************************************ 79 | ********************************************************************************* 80 | 81 | 项目源码地址: 82 | OC 版 :https://github.com/BAHome/BATouchID 83 | 84 | 最新更新时间:2017-05-27 【倒叙】
85 | 最新Version:【Version:1.0.1】
86 | 更新内容:
87 | 1.0.1.1、新增 单独判断是否支持指纹识别的方法
88 | 1.0.1.2、demo 新增手势密码设置、验证、修改、重置等方法
89 | 1.0.1.3、demo 新增手势密码和指纹识别的逻辑处理,具体使用中可参照demo 中的逻辑处理方式
90 | 91 | 最新更新时间:2017-05-24 【倒叙】
92 | 最新Version:【Version:1.0.0】
93 | 更新内容:
94 | 1.0.0.1、新增 Touch ID 的 详细封装
95 | 1.0.0.2、可以自定义 描述文字、取消按钮、第二个按钮等、详细的错误状态返回
96 | 1.0.0.3、demo 中增加了支付宝指纹登录逻辑,详见 demo 97 | 1.0.0.4、进入后台 10秒 后再次打开APP 会自动判断指纹登录,详见 demo 98 | 1.0.0.5、本地存储开启指纹登录开关,会自动判断指纹登录,详见 demo 99 | 1.0.0.6、本地密码登录后自动判断是否支持指纹登录,会自动判断指纹登录,详见 demo 100 | 101 | */ 102 | 103 | #endif /* BATouchID_h */ 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /BATouchID/BATouchIDDemo.pch: -------------------------------------------------------------------------------- 1 | // 2 | // BATouchIDDemo.pch 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/26. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #ifndef BATouchIDDemo_pch 10 | #define BATouchIDDemo_pch 11 | 12 | #define kIsLogin @"kIsLogin" 13 | #define kIsOpenTouchID @"kIsOpenTouchID" 14 | #define kIsOpenUnlockedGesture @"kIsOpenUnlockedGesture" 15 | 16 | #define kLastEnterBackgroundDate @"kLastEnterBackgroundDate" 17 | 18 | #define kUserDefaults [NSUserDefaults standardUserDefaults] 19 | 20 | #import "UIAlertController+Blocks.h" 21 | 22 | 23 | #endif /* BATouchIDDemo_pch */ 24 | -------------------------------------------------------------------------------- /BATouchID/BATouchIDLoginVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // BATouchIDLoginVC.h 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/24. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BATouchIDLoginVC : UIViewController 12 | 13 | @property(nonatomic, assign) BOOL isStart; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /BATouchID/BATouchIDLoginVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // BATouchIDLoginVC.m 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/24. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import "BATouchIDLoginVC.h" 10 | #import "BATouchID.h" 11 | #import "BAButton.h" 12 | 13 | #import "ViewController.h" 14 | #import "CLLockVC.h" 15 | 16 | @interface BATouchIDLoginVC () 17 | 18 | @property(nonatomic, strong) UIButton *touchIDButton; 19 | 20 | @end 21 | 22 | @implementation BATouchIDLoginVC 23 | 24 | - (void)viewWillAppear:(BOOL)animated { 25 | [super viewWillAppear:animated]; 26 | 27 | self.navigationController.navigationBar.hidden = YES; 28 | } 29 | 30 | - (void)viewWillDisappear:(BOOL)animated { 31 | [super viewWillDisappear:animated]; 32 | 33 | self.navigationController.navigationBar.hidden = NO; 34 | } 35 | 36 | - (void)viewDidLoad { 37 | [super viewDidLoad]; 38 | // Do any additional setup after loading the view. 39 | 40 | [self setupUI]; 41 | } 42 | 43 | - (void)setupUI 44 | { 45 | self.touchIDButton.hidden = NO; 46 | self.view.backgroundColor = [UIColor whiteColor]; 47 | [self test]; 48 | } 49 | 50 | - (void)handleButtonAction:(UIButton *)sender 51 | { 52 | [self test]; 53 | } 54 | 55 | - (void)test 56 | { 57 | /** 58 | 指纹解锁 59 | 60 | @param content 提示文本 61 | @param cancelButtonTitle 取消按钮显示内容(此参数只有iOS10以上才能生效),默认(nil):取消 62 | @param otherButtonTitle 密码登录按钮显示内容,默认(nil):输入密码(nil) 63 | @param enabled 默认:NO,输入密码按钮,使用系统解锁;YES:自己操作点击密码登录 64 | @param BAKit_TouchIDTypeBlock 返回状态码和错误,可以自行单独处理 65 | */ 66 | [BAKit_TouchID ba_touchIDWithContent:@"此操作需要认证您的身份" cancelButtonTitle:nil otherButtonTitle:nil enabled:YES BAKit_TouchIDTypeBlock:^(BAKit_TouchIDType touchIDType, NSError *error, NSString *errorMessage) { 67 | 68 | if (errorMessage && touchIDType != BAKit_TouchIDTypeTouchIDLockout && touchIDType != BAKit_TouchIDTypeInputPassword) 69 | { 70 | NSString *msg = errorMessage; 71 | BAKit_ShowAlertWithMsg_ios8(msg); 72 | } 73 | 74 | if (touchIDType == BAKit_TouchIDTypeSuccess) 75 | { 76 | BAKit_ShowAlertWithMsg(@"指纹验证成功!"); 77 | [self ba_backToPreVC:nil]; 78 | } 79 | if (touchIDType == BAKit_TouchIDTypeInputPassword) 80 | { 81 | NSLog(@"请跳转到自己的密码登录界面,如:手势解锁等!"); 82 | 83 | dispatch_async(dispatch_get_main_queue(), ^{ 84 | [self ba_verifyPwd]; 85 | }); 86 | } 87 | }]; 88 | } 89 | 90 | #pragma mark 设置手势密码 91 | - (void)ba_setupPwd 92 | { 93 | BOOL hasPwd = [CLLockVC hasPwd]; 94 | hasPwd = NO; 95 | if(hasPwd) 96 | { 97 | NSLog(@"已经设置过密码了,你可以验证或者修改密码"); 98 | } 99 | else 100 | { 101 | [CLLockVC showSettingLockVCInVC:self successBlock:^(CLLockVC *lockVC, NSString *pwd) { 102 | NSLog(@"密码设置成功"); 103 | 104 | [kUserDefaults setObject:[NSNumber numberWithBool:YES] forKey:kIsOpenUnlockedGesture]; 105 | [self ba_backToPreVC:lockVC]; 106 | }]; 107 | } 108 | } 109 | 110 | - (void)ba_verifyPwd 111 | { 112 | BOOL hasPwd = [CLLockVC hasPwd]; 113 | if(!hasPwd){ 114 | NSLog(@"你还没有设置密码,请先设置密码"); 115 | [self ba_setupPwd]; 116 | } 117 | else 118 | { 119 | [CLLockVC showVerifyLockVCInVC:self forgetPwdBlock:^(CLLockVC *lockVC) { 120 | NSLog(@"忘记密码"); 121 | [lockVC dismiss:1.0f]; 122 | 123 | // 此处逻辑需要自行定义!我这里是进入首页 124 | [self ba_backToPreVC:lockVC]; 125 | 126 | } successBlock:^(CLLockVC *lockVC, NSString *pwd) { 127 | NSLog(@"密码正确"); 128 | [lockVC dismiss:1.0f]; 129 | 130 | [self ba_backToPreVC:lockVC]; 131 | }]; 132 | } 133 | } 134 | 135 | - (void)ba_backToPreVC:(CLLockVC *)lockVC 136 | { 137 | dispatch_async(dispatch_get_main_queue(), ^{ 138 | 139 | if (self.isStart) 140 | { 141 | UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:[ViewController new]]; 142 | 143 | [self presentViewController:navi animated:NO completion:nil]; 144 | // [[UIApplication sharedApplication].windows lastObject].rootViewController = navi; 145 | } 146 | else 147 | { 148 | 149 | [self dismissViewControllerAnimated:NO completion:nil]; 150 | } 151 | }); 152 | } 153 | 154 | - (void)viewDidLayoutSubviews 155 | { 156 | [super viewDidLayoutSubviews]; 157 | 158 | _touchIDButton.frame = CGRectMake(0, 0, 150, 300); 159 | _touchIDButton.center = self.view.center; 160 | } 161 | 162 | - (UIButton *)touchIDButton 163 | { 164 | if (!_touchIDButton) 165 | { 166 | _touchIDButton = [UIButton buttonWithType:UIButtonTypeCustom]; 167 | [_touchIDButton setImage:[UIImage imageNamed:@"touchID"] forState:UIControlStateNormal]; 168 | [_touchIDButton setTitle:@"点击进行指纹解锁" forState:UIControlStateNormal]; 169 | [_touchIDButton setTitleColor:[UIColor colorWithRed:0 green:152/255.0 blue:229/255.0 alpha:1.0f] forState:UIControlStateNormal]; 170 | [_touchIDButton addTarget:self action:@selector(handleButtonAction:) forControlEvents:UIControlEventTouchDown]; 171 | [self.view addSubview:_touchIDButton]; 172 | [_touchIDButton ba_button_setBAButtonLayoutType:BAButtonLayoutTypeCenterImageTop padding:5]; 173 | 174 | } 175 | return _touchIDButton; 176 | } 177 | 178 | @end 179 | -------------------------------------------------------------------------------- /BATouchID/BAUnlockedGestureVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // BAUnlockedGestureVC.h 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/26. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BAUnlockedGestureVC : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /BATouchID/BAUnlockedGestureVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // BAUnlockedGestureVC.m 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/26. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import "BAUnlockedGestureVC.h" 10 | #import "CLLockVC.h" 11 | 12 | static NSString * const kCellID = @"BAUnlockedGestureVCCell"; 13 | 14 | @interface BAUnlockedGestureVC () 15 | 16 | @property (weak, nonatomic) IBOutlet UITableView *tableView; 17 | @property(nonatomic, strong) NSMutableArray *dataArray; 18 | 19 | @end 20 | 21 | @implementation BAUnlockedGestureVC 22 | 23 | - (void)viewWillAppear:(BOOL)animated 24 | { 25 | [super viewWillAppear:animated]; 26 | 27 | [self test]; 28 | } 29 | 30 | - (void)viewDidLoad 31 | { 32 | [super viewDidLoad]; 33 | 34 | [self setupUI]; 35 | } 36 | 37 | - (void)setupUI 38 | { 39 | self.title = @"手势设置"; 40 | self.tableView.tableFooterView = [UIView new]; 41 | 42 | } 43 | 44 | - (void)test 45 | { 46 | id isOpenUnlockedGesture = [kUserDefaults objectForKey:kIsOpenUnlockedGesture]; 47 | 48 | [self.dataArray removeAllObjects]; 49 | if ([isOpenUnlockedGesture intValue] == 1) 50 | { 51 | [_dataArray addObjectsFromArray:@[@"手势密码", @"验证手势密码", @"修改手势密码"]]; 52 | } 53 | else if ([isOpenUnlockedGesture intValue] == 0 && _dataArray.count == 0) 54 | { 55 | [_dataArray addObject:@"手势密码"]; 56 | } 57 | [self.tableView reloadData]; 58 | } 59 | 60 | #pragma mark - UITableViewDelegate, UITableViewDataSource 61 | 62 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 63 | { 64 | return self.dataArray.count; 65 | } 66 | 67 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 68 | { 69 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellID]; 70 | 71 | if (!cell) 72 | { 73 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kCellID]; 74 | } 75 | if (indexPath.row == 0) 76 | { 77 | UISwitch *switcher; 78 | 79 | id isOpenUnlockedGesture = [kUserDefaults objectForKey:kIsOpenUnlockedGesture]; 80 | 81 | if ([cell.accessoryView isKindOfClass:[UISwitch class]]) 82 | { 83 | switcher = (UISwitch *)cell.accessoryView; 84 | } 85 | else 86 | { 87 | switcher = [[UISwitch alloc] init]; 88 | } 89 | switcher.tag = indexPath.row; 90 | switcher.on = ([isOpenUnlockedGesture intValue] == 1) ? YES : NO; 91 | 92 | [switcher removeTarget:nil action:NULL forControlEvents:UIControlEventAllEvents]; 93 | [switcher addTarget:self action:@selector(handleSwichAction:) forControlEvents:UIControlEventValueChanged]; 94 | cell.accessoryView = switcher; 95 | } 96 | cell.textLabel.text = self.dataArray[indexPath.row]; 97 | 98 | return cell; 99 | } 100 | 101 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 102 | { 103 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 104 | 105 | if (indexPath.row == 1) 106 | { 107 | [self ba_verifyPwd]; 108 | } 109 | if (indexPath.row == 2) 110 | { 111 | [self ba_modifyPwd]; 112 | } 113 | } 114 | 115 | #pragma mark - custom method 116 | - (void)handleSwichAction:(UISwitch *)sender 117 | { 118 | [[NSUserDefaults standardUserDefaults] removeObjectForKey:kIsOpenUnlockedGesture]; 119 | if (sender.on) 120 | { 121 | [self openUnlockedGesture]; 122 | } 123 | else 124 | { 125 | [kUserDefaults setObject:[NSNumber numberWithBool:NO] forKey:kIsOpenUnlockedGesture]; 126 | sender.on = NO; 127 | [CLLockVC ba_setPwdRemove]; 128 | } 129 | [self test]; 130 | } 131 | 132 | - (void)openUnlockedGesture 133 | { 134 | [UIAlertController ba_alertControllerShowAlertInViewController:self withTitle:nil mutableAttributedTitle:nil message:@"继续开启手势解锁\n将关闭指纹解锁" mutableAttributedMessage:nil buttonTitlesArray:@[@"取 消", @"继 续"] buttonTitleColorArray:@[[UIColor greenColor], [UIColor redColor]] tapBlock:^(UIAlertController * _Nonnull controller, UIAlertAction * _Nonnull action, NSInteger buttonIndex) { 135 | 136 | if (buttonIndex == 1) 137 | { 138 | [kUserDefaults removeObjectForKey:kIsOpenTouchID]; 139 | [kUserDefaults setObject:[NSNumber numberWithBool:NO] forKey:kIsOpenTouchID]; 140 | [self ba_setupPwd]; 141 | } 142 | 143 | return; 144 | }]; 145 | } 146 | 147 | #pragma mark 设置手势密码 148 | - (void)ba_setupPwd 149 | { 150 | BOOL hasPwd = [CLLockVC hasPwd]; 151 | hasPwd = NO; 152 | if(hasPwd) 153 | { 154 | NSLog(@"已经设置过密码了,你可以验证或者修改密码"); 155 | } 156 | else 157 | { 158 | [CLLockVC showSettingLockVCInVC:self successBlock:^(CLLockVC *lockVC, NSString *pwd) { 159 | NSLog(@"密码设置成功"); 160 | [lockVC dismiss:0.5f]; 161 | 162 | [kUserDefaults setObject:[NSNumber numberWithBool:YES] forKey:kIsOpenUnlockedGesture]; 163 | }]; 164 | } 165 | } 166 | 167 | - (void)ba_modifyPwd 168 | { 169 | BOOL hasPwd = [CLLockVC hasPwd]; 170 | if(!hasPwd) 171 | { 172 | NSLog(@"你还没有设置密码,请先设置密码"); 173 | } 174 | else 175 | { 176 | [CLLockVC showModifyLockVCInVC:self successBlock:^(CLLockVC *lockVC, NSString *pwd) { 177 | [lockVC dismiss:0.5f]; 178 | }]; 179 | } 180 | } 181 | 182 | - (void)ba_verifyPwd 183 | { 184 | BOOL hasPwd = [CLLockVC hasPwd]; 185 | if(!hasPwd){ 186 | NSLog(@"你还没有设置密码,请先设置密码"); 187 | } 188 | else 189 | { 190 | [CLLockVC showVerifyLockVCInVC:self forgetPwdBlock:^{ 191 | NSLog(@"忘记密码"); 192 | } successBlock:^(CLLockVC *lockVC, NSString *pwd) { 193 | NSLog(@"密码正确"); 194 | [lockVC dismiss:0.5f]; 195 | }]; 196 | } 197 | } 198 | 199 | #pragma mark - setter / getter 200 | 201 | - (NSMutableArray *)dataArray 202 | { 203 | if (!_dataArray) 204 | { 205 | _dataArray = @[].mutableCopy; 206 | 207 | } 208 | return _dataArray; 209 | } 210 | 211 | 212 | @end 213 | -------------------------------------------------------------------------------- /BATouchID/BAUnlockedGestureVC.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /BATouchID/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /BATouchID/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /BATouchID/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /BATouchID/Lib/BAButton/BAButton.h: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | * @header BAKit.h 4 | * BABaseProject 5 | * 6 | * @brief BAKit 7 | * 8 | * @author 博爱 9 | * @copyright Copyright © 2016年 博爱. All rights reserved. 10 | * @version V1.0 11 | */ 12 | 13 | // _ooOoo_ 14 | // o8888888o 15 | // 88" . "88 16 | // (| -_- |) 17 | // O\ = /O 18 | // ____/`---'\____ 19 | // . ' \\| |// `. 20 | // / \\||| : |||// \ 21 | // / _||||| -:- |||||- \ 22 | // | | \\\ - /// | | 23 | // | \_| ''\---/'' | | 24 | // \ .-\__ `-` ___/-. / 25 | // ___`. .' /--.--\ `. . __ 26 | // ."" '< `.___\_<|>_/___.' >'"". 27 | // | | : `- \`.;`\ _ /`;.`/ - ` : | | 28 | // \ \ `-. \_ __\ /__ _/ .-` / / 29 | // ======`-.____`-.___\_____/___.-`____.-'====== 30 | // `=---=' 31 | // 32 | // ............................................. 33 | // 佛祖镇楼 BUG辟易 34 | // 佛曰: 35 | // 写字楼里写字间,写字间里程序员; 36 | // 程序人员写程序,又拿程序换酒钱。 37 | // 酒醒只在网上坐,酒醉还来网下眠; 38 | // 酒醉酒醒日复日,网上网下年复年。 39 | // 但愿老死电脑间,不愿鞠躬老板前; 40 | // 奔驰宝马贵者趣,公交自行程序员。 41 | // 别人笑我忒疯癫,我笑自己命太贱; 42 | // 不见满街漂亮妹,哪个归得程序员? 43 | 44 | /* 45 | 46 | ********************************************************************************* 47 | * 48 | * 在使用BAKit的过程中如果出现bug请及时以以下任意一种方式联系我,我会及时修复bug 49 | * 50 | * QQ : 可以添加ios开发技术群 479663605 在这里找到我(博爱1616【137361770】) 51 | * 微博 : 博爱1616 52 | * Email : 137361770@qq.com 53 | * GitHub : https://github.com/boai 54 | * 博客 : http://boaihome.com 55 | 56 | ********************************************************************************* 57 | 58 | */ 59 | 60 | 61 | #ifndef BAButton_h 62 | #define BAButton_h 63 | 64 | #import "UIButton+BAKit.h" 65 | 66 | /*! 67 | ********************************************************************************* 68 | ************************************ 更新说明 ************************************ 69 | ********************************************************************************* 70 | 71 | 欢迎使用 BAHome 系列开源代码 ! 72 | 如有更多需求,请前往:https://github.com/BAHome 73 | 74 | 最新更新时间:2017-05-20 【倒叙】 75 | 最新Version:【Version:2.3.0】 76 | 更新内容: 77 | 2.3.0.1、用分类全新重构 BAButton,代码配置更灵活 78 | 2.3.0.2、可以自由设置 button 的文字和图片的布局、间距、每个角的切圆角 79 | 2.3.0.3、全面适配 纯代码、xib、storyboard 80 | 2.3.0.4、版本改动较大,希望大家谅解,如果用老版本的 BAButton,可以参考demo 更换新版本,后期改动不大 81 | 82 | */ 83 | 84 | 85 | #endif /* BAButton_h */ 86 | -------------------------------------------------------------------------------- /BATouchID/Lib/BAButton/UIButton+BAKit.h: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | * @header BAKit.h 4 | * BABaseProject 5 | * 6 | * @brief BAKit 7 | * 8 | * @author 博爱 9 | * @copyright Copyright © 2016年 博爱. All rights reserved. 10 | * @version V1.0 11 | */ 12 | 13 | // _ooOoo_ 14 | // o8888888o 15 | // 88" . "88 16 | // (| -_- |) 17 | // O\ = /O 18 | // ____/`---'\____ 19 | // . ' \\| |// `. 20 | // / \\||| : |||// \ 21 | // / _||||| -:- |||||- \ 22 | // | | \\\ - /// | | 23 | // | \_| ''\---/'' | | 24 | // \ .-\__ `-` ___/-. / 25 | // ___`. .' /--.--\ `. . __ 26 | // ."" '< `.___\_<|>_/___.' >'"". 27 | // | | : `- \`.;`\ _ /`;.`/ - ` : | | 28 | // \ \ `-. \_ __\ /__ _/ .-` / / 29 | // ======`-.____`-.___\_____/___.-`____.-'====== 30 | // `=---=' 31 | // 32 | // ............................................. 33 | // 佛祖镇楼 BUG辟易 34 | // 佛曰: 35 | // 写字楼里写字间,写字间里程序员; 36 | // 程序人员写程序,又拿程序换酒钱。 37 | // 酒醒只在网上坐,酒醉还来网下眠; 38 | // 酒醉酒醒日复日,网上网下年复年。 39 | // 但愿老死电脑间,不愿鞠躬老板前; 40 | // 奔驰宝马贵者趣,公交自行程序员。 41 | // 别人笑我忒疯癫,我笑自己命太贱; 42 | // 不见满街漂亮妹,哪个归得程序员? 43 | 44 | /* 45 | 46 | ********************************************************************************* 47 | * 48 | * 在使用BAKit的过程中如果出现bug请及时以以下任意一种方式联系我,我会及时修复bug 49 | * 50 | * QQ : 可以添加ios开发技术群 479663605 在这里找到我(博爱1616【137361770】) 51 | * 微博 : 博爱1616 52 | * Email : 137361770@qq.com 53 | * GitHub : https://github.com/boai 54 | * 博客 : http://boaihome.com 55 | 56 | ********************************************************************************* 57 | 58 | */ 59 | 60 | 61 | #import 62 | #import "UIView+BARectCorner.h" 63 | 64 | NS_ASSUME_NONNULL_BEGIN 65 | /** 66 | button 的样式,以图片为基准 67 | 68 | - BAButtonLayoutTypeNormal: button 默认样式:内容居中-图左文右 69 | - BAButtonLayoutTypeCenterImageRight: 内容居中-图右文左 70 | - BAButtonLayoutTypeCenterImageTop: 内容居中-图上文下 71 | - BAButtonLayoutTypeCenterImageBottom: 内容居中-图下文上 72 | - BAButtonLayoutTypeLeftImageLeft: 内容居左-图左文右 73 | - BAButtonLayoutTypeLeftImageRight: 内容居左-图右文左 74 | - BAButtonLayoutTypeRightImageLeft: 内容居右-图左文右 75 | - BAButtonLayoutTypeRightImageRight: 内容居右-图右文左 76 | */ 77 | typedef NS_ENUM(NSInteger, BAButtonLayoutType) { 78 | BAButtonLayoutTypeNormal = 0, 79 | BAButtonLayoutTypeCenterImageRight, 80 | BAButtonLayoutTypeCenterImageTop, 81 | BAButtonLayoutTypeCenterImageBottom, 82 | BAButtonLayoutTypeLeftImageLeft, 83 | BAButtonLayoutTypeLeftImageRight, 84 | BAButtonLayoutTypeRightImageLeft, 85 | BAButtonLayoutTypeRightImageRight, 86 | }; 87 | 88 | @interface UIButton (BAKit) 89 | 90 | /** 91 | button 的布局样式,默认为:BAButtonLayoutTypeNormal,注意:此设置只能在 [self.view addSubview:button] 之后添加样式 92 | */ 93 | @property(nonatomic, assign) BAButtonLayoutType buttonLayoutType; 94 | 95 | /*! 96 | * 文字与图片之间的间距,默认为:0 97 | */ 98 | @property (nonatomic, assign) CGFloat padding; 99 | 100 | 101 | /** 102 | 快速设置 button 的布局样式 和 间距 103 | 104 | @param type button 的布局样式 105 | @param padding 文字与图片之间的间距 106 | */ 107 | - (void)ba_button_setBAButtonLayoutType:(BAButtonLayoutType)type padding:(CGFloat)padding; 108 | 109 | /** 110 | 快速切圆角 111 | 112 | @param type 圆角样式 113 | @param viewCornerRadius 圆角角度 114 | */ 115 | - (void)ba_button_setBAViewRectCornerType:(BAViewRectCornerType)type viewCornerRadius:(CGFloat)viewCornerRadius; 116 | 117 | /** 118 | * 给定框架创建一个UIButton对象 119 | */ 120 | + (id)initWithFrame:(CGRect)frame; 121 | 122 | /** 123 | * 给定框架和字符串(字符串字体颜色默认是白色)创建一个UIButton对象 124 | */ 125 | + (id)initWithFrame:(CGRect)frame 126 | title:(NSString *)title; 127 | 128 | /** 129 | * 给定框架、字符串和背景图片创建一个UIButton对象 130 | */ 131 | + (id)initWithFrame:(CGRect)frame 132 | title:(NSString *)title 133 | backgroundImage:(UIImage *)backgroundImage; 134 | 135 | /** 136 | * 给定框架、字符串、背景图片和高亮背景图片创建一个UIButton对象 137 | */ 138 | + (id)initWithFrame:(CGRect)frame 139 | title:(NSString *)title 140 | backgroundImage:(UIImage *)backgroundImage 141 | highlightedBackgroundImage:(UIImage *)highlightedBackgroundImage; 142 | 143 | /** 144 | * 给定框架、字符串、颜色创建一个UIButton对象 145 | */ 146 | + (id)initWithFrame:(CGRect)frame 147 | title:(NSString *)title 148 | color:(UIColor *)color; 149 | 150 | /** 151 | * 给定框架、字符串、背景颜色和高亮背景颜色创建一个UIButton对象 152 | */ 153 | + (id)initWithFrame:(CGRect)frame 154 | title:(NSString *)title 155 | color:(UIColor *)color 156 | highlightedColor:(UIColor *)highlightedColor; 157 | 158 | /** 159 | * 给定框架、颜色创建一个UIButton对象 160 | */ 161 | + (id)initWithFrame:(CGRect)frame 162 | color:(UIColor *)color; 163 | 164 | /** 165 | * 给定框架、背景颜色和高亮背景颜色创建一个UIButton对象 166 | */ 167 | + (id)initWithFrame:(CGRect)frame 168 | color:(UIColor *)color 169 | highlightedColor:(UIColor *)highlightedColor; 170 | 171 | /** 172 | * 给定框架和图片创建一个UIButton对象 173 | */ 174 | + (id)initWithFrame:(CGRect)frame 175 | image:(UIImage *)image; 176 | 177 | /** 178 | * 给定框架、背景图片和高亮背景图片创建一个UIButton对象 */ 179 | + (id)initWithFrame:(CGRect)frame 180 | image:(UIImage *)image 181 | highlightedImage:(UIImage *)highlightedImage; 182 | 183 | /** 184 | * 设置字符字体和大小 185 | */ 186 | - (void)setTitleFont:(NSString *)fontName 187 | size:(CGFloat)size; 188 | 189 | /** 190 | * 设置字符颜色和高亮颜色 191 | */ 192 | - (void)setTitleColor:(UIColor *)color 193 | highlightedColor:(UIColor *)highlightedColor; 194 | 195 | #pragma mark - 快速创建 button 196 | /** 197 | 创建 button 198 | 199 | @param frame frame 200 | @param title title 201 | @param selTitle selTitle 202 | @param titleColor titleColor,默认:黑色 203 | @param titleFont titleFont默认:15 204 | @param image image description 205 | @param selImage selImage 206 | @param padding padding 文字图片间距 207 | @param buttonLayoutType buttonLayoutType 文字图片布局样式 208 | @param viewRectCornerType viewRectCornerType 圆角样式 209 | @param viewCornerRadius viewCornerRadius 圆角角度 210 | @param target target 211 | @param sel sel 212 | @return button 213 | */ 214 | - (instancetype __nonnull)creatButtonWithFrame:(CGRect)frame 215 | title:(NSString * __nullable)title 216 | selTitle:(NSString * __nullable)selTitle 217 | titleColor:(UIColor * __nullable)titleColor 218 | titleFont:(UIFont * __nullable)titleFont 219 | image:(UIImage * __nullable)image 220 | selImage:(UIImage * __nullable)selImage 221 | padding:(CGFloat)padding 222 | buttonPositionStyle:(BAButtonLayoutType)buttonLayoutType 223 | viewRectCornerType:(BAViewRectCornerType)viewRectCornerType 224 | viewCornerRadius:(CGFloat)viewCornerRadius 225 | target:(id __nullable)target 226 | selector:(SEL __nullable)sel; 227 | 228 | @end 229 | NS_ASSUME_NONNULL_END 230 | 231 | 232 | -------------------------------------------------------------------------------- /BATouchID/Lib/BAButton/UIButton+BAKit.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIButton+BAKit.m 3 | // BAButtonDemo 4 | // 5 | // Created by boai on 2017/5/17. 6 | // Copyright © 2017年 博爱之家. All rights reserved. 7 | // 8 | 9 | 10 | 11 | 12 | #import "UIButton+BAKit.h" 13 | #import 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | @interface UIImage (BAKit) 18 | 19 | + (UIImage *)imageWithColor:(UIColor *)color; 20 | 21 | @end 22 | 23 | @implementation UIImage (BAKit) 24 | 25 | + (UIImage *)imageWithColor:(UIColor *)color 26 | { 27 | CGRect rect = CGRectMake(0, 0, 1, 1); 28 | UIGraphicsBeginImageContext(rect.size); 29 | CGContextRef context = UIGraphicsGetCurrentContext(); 30 | CGContextSetFillColorWithColor(context, [color CGColor]); 31 | 32 | CGContextFillRect(context, rect); 33 | UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); 34 | UIGraphicsEndImageContext(); 35 | 36 | return image; 37 | } 38 | 39 | @end 40 | 41 | static void *buttonLayoutTypeKey = @"buttonLayoutTypeKey"; 42 | static void *paddingKey = @"paddingKey"; 43 | 44 | @implementation UIButton (BAKit) 45 | 46 | - (void)setupButtonLayout 47 | { 48 | CGFloat image_w = self.imageView.frame.size.width; 49 | CGFloat image_h = self.imageView.frame.size.height; 50 | 51 | CGFloat title_w = self.titleLabel.frame.size.width; 52 | CGFloat title_h = self.titleLabel.frame.size.height; 53 | 54 | if ([UIDevice currentDevice].systemVersion.floatValue >= 8.0) 55 | { 56 | // 由于iOS8中titleLabel的size为0,用下面的这种设置 57 | title_w = self.titleLabel.intrinsicContentSize.width; 58 | title_h = self.titleLabel.intrinsicContentSize.height; 59 | } 60 | 61 | UIEdgeInsets imageEdge = UIEdgeInsetsZero; 62 | UIEdgeInsets titleEdge = UIEdgeInsetsZero; 63 | 64 | switch (self.buttonLayoutType) { 65 | case BAButtonLayoutTypeNormal: 66 | { 67 | titleEdge = UIEdgeInsetsMake(0, self.padding, 0, 0); 68 | imageEdge = UIEdgeInsetsMake(0, 0, 0, self.padding); 69 | } 70 | break; 71 | case BAButtonLayoutTypeCenterImageRight: 72 | { 73 | titleEdge = UIEdgeInsetsMake(0, -image_w - self.padding, 0, image_w); 74 | imageEdge = UIEdgeInsetsMake(0, title_w + self.padding, 0, -title_w); 75 | } 76 | break; 77 | case BAButtonLayoutTypeCenterImageTop: 78 | { 79 | titleEdge = UIEdgeInsetsMake(0, -image_w, -image_h - self.padding, 0); 80 | imageEdge = UIEdgeInsetsMake(-title_h - self.padding, 0, 0, -title_w); 81 | } 82 | break; 83 | case BAButtonLayoutTypeCenterImageBottom: 84 | { 85 | titleEdge = UIEdgeInsetsMake(-image_h - self.padding, -image_w, 0, 0); 86 | imageEdge = UIEdgeInsetsMake(0, 0, -title_h - self.padding, -title_w); 87 | } 88 | break; 89 | case BAButtonLayoutTypeLeftImageLeft: 90 | { 91 | titleEdge = UIEdgeInsetsMake(0, self.padding, 0, 0); 92 | self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; 93 | } 94 | break; 95 | case BAButtonLayoutTypeLeftImageRight: 96 | { 97 | titleEdge = UIEdgeInsetsMake(0, -image_w, 0, 0); 98 | imageEdge = UIEdgeInsetsMake(0, title_w + self.padding, 0, 0); 99 | self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft; 100 | } 101 | break; 102 | case BAButtonLayoutTypeRightImageLeft: 103 | { 104 | imageEdge = UIEdgeInsetsMake(0, 0, 0, self.padding); 105 | self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight; 106 | } 107 | break; 108 | case BAButtonLayoutTypeRightImageRight: 109 | { 110 | titleEdge = UIEdgeInsetsMake(0, 0, 0, image_w + self.padding); 111 | imageEdge = UIEdgeInsetsMake(0, 0, 0, -title_w); 112 | self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight; 113 | } 114 | break; 115 | 116 | default: 117 | break; 118 | } 119 | self.imageEdgeInsets = imageEdge; 120 | self.titleEdgeInsets = titleEdge; 121 | } 122 | 123 | /** 124 | 快速设置 button 的布局样式 和 间距 125 | 126 | @param type button 的布局样式 127 | @param padding 文字与图片之间的间距 128 | */ 129 | - (void)ba_button_setBAButtonLayoutType:(BAButtonLayoutType)type padding:(CGFloat)padding 130 | { 131 | self.buttonLayoutType = type; 132 | self.padding = padding; 133 | } 134 | 135 | /** 136 | 快速切圆角 137 | 138 | @param type 圆角样式 139 | @param viewCornerRadius 圆角角度 140 | */ 141 | - (void)ba_button_setBAViewRectCornerType:(BAViewRectCornerType)type viewCornerRadius:(CGFloat)viewCornerRadius 142 | { 143 | [self ba_view_setBAViewRectCornerType:type viewCornerRadius:viewCornerRadius]; 144 | } 145 | 146 | /* 给定框架创建一个UIButton对象 */ 147 | + (id)initWithFrame:(CGRect)frame 148 | { 149 | return [UIButton initWithFrame:frame 150 | title:nil]; 151 | } 152 | 153 | /* 给定框架和字符串(字符串字体颜色默认是白色)创建一个UIButton对象 */ 154 | + (id)initWithFrame:(CGRect)frame 155 | title:(NSString *)title 156 | { 157 | return [UIButton initWithFrame:frame 158 | title:title 159 | backgroundImage:nil]; 160 | } 161 | 162 | /* 给定框架、字符串和背景图片创建一个UIButton对象 */ 163 | + (id)initWithFrame:(CGRect)frame 164 | title:(NSString *)title 165 | backgroundImage:(UIImage *)backgroundImage 166 | { 167 | return [UIButton initWithFrame:frame 168 | title:title 169 | backgroundImage:backgroundImage 170 | highlightedBackgroundImage:nil]; 171 | } 172 | 173 | /* 给定框架、字符串、背景图片和高亮背景图片创建一个UIButton对象 */ 174 | + (id)initWithFrame:(CGRect)frame 175 | title:(NSString *)title 176 | backgroundImage:(UIImage *)backgroundImage 177 | highlightedBackgroundImage:(UIImage *)highlightedBackgroundImage 178 | { 179 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 180 | [button setFrame:frame]; 181 | [button setTitle:title 182 | forState:UIControlStateNormal]; 183 | [button setBackgroundImage:backgroundImage 184 | forState:UIControlStateNormal]; 185 | [button setBackgroundImage:highlightedBackgroundImage 186 | forState:UIControlStateHighlighted]; 187 | return button; 188 | } 189 | 190 | /* 给定框架、字符串、颜色创建一个UIButton对象 */ 191 | + (id)initWithFrame:(CGRect)frame 192 | title:(NSString *)title 193 | color:(UIColor *)color 194 | { 195 | // 返回与'色'关联的颜色组件(包括透明度) 196 | const CGFloat *components = CGColorGetComponents(color.CGColor); 197 | return [UIButton initWithFrame:frame 198 | title:title 199 | backgroundImage:[UIImage imageWithColor:color] 200 | highlightedBackgroundImage:[UIImage imageWithColor:[UIColor colorWithRed:components[0]-0.1 201 | green:components[1]-0.1 202 | blue:components[2]-0.1 203 | alpha:1]]]; 204 | } 205 | 206 | /* 给定框架、字符串、背景颜色和高亮背景颜色创建一个UIButton对象 */ 207 | + (id)initWithFrame:(CGRect)frame 208 | title:(NSString *)title 209 | color:(UIColor *)color 210 | highlightedColor:(UIColor *)highlightedColor 211 | { 212 | return [UIButton initWithFrame:frame 213 | title:title 214 | backgroundImage:[UIImage imageWithColor:color] 215 | highlightedBackgroundImage:[UIImage imageWithColor:highlightedColor]]; 216 | } 217 | 218 | /* 给定框架、颜色创建一个UIButton对象 */ 219 | + (id)initWithFrame:(CGRect)frame 220 | color:(UIColor *)color 221 | { 222 | // 返回与'色'关联的颜色组件(包括透明度) 223 | const CGFloat *components = CGColorGetComponents(color.CGColor); 224 | return [UIButton initWithFrame:frame 225 | title:nil 226 | backgroundImage:[UIImage imageWithColor:color] 227 | highlightedBackgroundImage:[UIImage imageWithColor:[UIColor colorWithRed:components[0]-0.1 228 | green:components[1]-0.1 229 | blue:components[2]-0.1 230 | alpha:1]]]; 231 | } 232 | 233 | /* 给定框架、背景颜色和高亮背景颜色创建一个UIButton对象 */ 234 | + (id)initWithFrame:(CGRect)frame 235 | color:(UIColor *)color 236 | highlightedColor:(UIColor *)highlightedColor 237 | { 238 | return [UIButton initWithFrame:frame 239 | title:nil 240 | backgroundImage:[UIImage imageWithColor:color] 241 | highlightedBackgroundImage:[UIImage imageWithColor:highlightedColor]]; 242 | } 243 | 244 | /* 给定框架和图片创建一个UIButton对象 */ 245 | + (id)initWithFrame:(CGRect)frame 246 | image:(UIImage *)image 247 | { 248 | return [UIButton initWithFrame:frame 249 | image:image 250 | highlightedImage:nil]; 251 | } 252 | 253 | /* 给定框架、背景图片和高亮背景图片创建一个UIButton对象 */ 254 | + (id)initWithFrame:(CGRect)frame 255 | image:(UIImage *)image 256 | highlightedImage:(UIImage *)highlightedImage 257 | { 258 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 259 | [button setFrame:frame]; 260 | [button setImage:image 261 | forState:UIControlStateNormal]; 262 | [button setImage:highlightedImage 263 | forState:UIControlStateHighlighted]; 264 | return button; 265 | } 266 | 267 | /* 设置字符字体和大小 */ 268 | - (void)setTitleFont:(NSString *)fontName 269 | size:(CGFloat)size 270 | { 271 | [self.titleLabel setFont:[UIFont fontWithName:fontName size:size]]; 272 | } 273 | 274 | /* 设置字符颜色和高亮颜色 */ 275 | - (void)setTitleColor:(UIColor *)color 276 | highlightedColor:(UIColor *)highlightedColor 277 | { 278 | [self setTitleColor:color 279 | forState:UIControlStateNormal]; 280 | [self setTitleColor:highlightedColor 281 | forState:UIControlStateHighlighted]; 282 | } 283 | 284 | #pragma mark - 快速创建 button 285 | /** 286 | 创建 button 287 | 288 | @param frame frame 289 | @param title title 290 | @param selTitle selTitle 291 | @param titleColor titleColor,默认:黑色 292 | @param titleFont titleFont默认:15 293 | @param image image description 294 | @param selImage selImage 295 | @param padding padding 文字图片间距 296 | @param buttonLayoutType buttonLayoutType 文字图片布局样式 297 | @param viewRectCornerType viewRectCornerType 圆角样式 298 | @param viewCornerRadius viewCornerRadius 圆角角度 299 | @param target target 300 | @param sel sel 301 | @return button 302 | */ 303 | - (instancetype __nonnull)creatButtonWithFrame:(CGRect)frame 304 | title:(NSString * __nullable)title 305 | selTitle:(NSString * __nullable)selTitle 306 | titleColor:(UIColor * __nullable)titleColor 307 | titleFont:(UIFont * __nullable)titleFont 308 | image:(UIImage * __nullable)image 309 | selImage:(UIImage * __nullable)selImage 310 | padding:(CGFloat)padding 311 | buttonPositionStyle:(BAButtonLayoutType)buttonLayoutType 312 | viewRectCornerType:(BAViewRectCornerType)viewRectCornerType 313 | viewCornerRadius:(CGFloat)viewCornerRadius 314 | target:(id __nullable)target 315 | selector:(SEL __nullable)sel 316 | { 317 | UIButton *button = [[UIButton alloc] init]; 318 | button.frame = frame; 319 | if (title) 320 | { 321 | [button setTitle:title forState:UIControlStateNormal]; 322 | } 323 | if (selTitle) 324 | { 325 | [button setTitle:selTitle forState:UIControlStateSelected]; 326 | } 327 | [button setTitleColor:titleColor ? titleColor : [UIColor blackColor] forState:UIControlStateNormal]; 328 | 329 | button.titleLabel.font = titleFont ? titleFont : [UIFont systemFontOfSize:15.0f]; 330 | 331 | if (selImage) 332 | { 333 | [button setImage:selImage forState:UIControlStateSelected]; 334 | } 335 | if (image) 336 | { 337 | [button setImage:image forState:UIControlStateNormal]; 338 | } 339 | [button ba_button_setBAButtonLayoutType:buttonLayoutType padding:padding]; 340 | [button ba_button_setBAViewRectCornerType:viewRectCornerType viewCornerRadius:viewCornerRadius]; 341 | [button addTarget:target action:sel forControlEvents:UIControlEventTouchUpInside]; 342 | 343 | return button; 344 | } 345 | 346 | #pragma mark - setter / getter 347 | - (void)setButtonLayoutType:(BAButtonLayoutType)buttonLayoutType 348 | { 349 | objc_setAssociatedObject(self, buttonLayoutTypeKey, @(buttonLayoutType), OBJC_ASSOCIATION_ASSIGN); 350 | [self setupButtonLayout]; 351 | } 352 | 353 | - (BAButtonLayoutType)buttonLayoutType 354 | { 355 | return [objc_getAssociatedObject(self, buttonLayoutTypeKey) integerValue]; 356 | } 357 | 358 | - (void)setPadding:(CGFloat)padding 359 | { 360 | objc_setAssociatedObject(self, paddingKey, @(padding), OBJC_ASSOCIATION_ASSIGN); 361 | [self setupButtonLayout]; 362 | } 363 | 364 | - (CGFloat)padding 365 | { 366 | return [objc_getAssociatedObject(self, paddingKey) floatValue]; 367 | } 368 | 369 | - (void)setFrame:(CGRect)frame 370 | { 371 | [super setFrame:frame]; 372 | [self setupButtonLayout]; 373 | } 374 | 375 | @end 376 | NS_ASSUME_NONNULL_END 377 | 378 | -------------------------------------------------------------------------------- /BATouchID/Lib/BAButton/UIView+BARectCorner.h: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | * @header BAKit.h 4 | * BABaseProject 5 | * 6 | * @brief BAKit 7 | * 8 | * @author 博爱 9 | * @copyright Copyright © 2016年 博爱. All rights reserved. 10 | * @version V1.0 11 | */ 12 | 13 | // _ooOoo_ 14 | // o8888888o 15 | // 88" . "88 16 | // (| -_- |) 17 | // O\ = /O 18 | // ____/`---'\____ 19 | // . ' \\| |// `. 20 | // / \\||| : |||// \ 21 | // / _||||| -:- |||||- \ 22 | // | | \\\ - /// | | 23 | // | \_| ''\---/'' | | 24 | // \ .-\__ `-` ___/-. / 25 | // ___`. .' /--.--\ `. . __ 26 | // ."" '< `.___\_<|>_/___.' >'"". 27 | // | | : `- \`.;`\ _ /`;.`/ - ` : | | 28 | // \ \ `-. \_ __\ /__ _/ .-` / / 29 | // ======`-.____`-.___\_____/___.-`____.-'====== 30 | // `=---=' 31 | // 32 | // ............................................. 33 | // 佛祖镇楼 BUG辟易 34 | // 佛曰: 35 | // 写字楼里写字间,写字间里程序员; 36 | // 程序人员写程序,又拿程序换酒钱。 37 | // 酒醒只在网上坐,酒醉还来网下眠; 38 | // 酒醉酒醒日复日,网上网下年复年。 39 | // 但愿老死电脑间,不愿鞠躬老板前; 40 | // 奔驰宝马贵者趣,公交自行程序员。 41 | // 别人笑我忒疯癫,我笑自己命太贱; 42 | // 不见满街漂亮妹,哪个归得程序员? 43 | 44 | /* 45 | 46 | ********************************************************************************* 47 | * 48 | * 在使用BAKit的过程中如果出现bug请及时以以下任意一种方式联系我,我会及时修复bug 49 | * 50 | * QQ : 可以添加ios开发技术群 479663605 在这里找到我(博爱1616【137361770】) 51 | * 微博 : 博爱1616 52 | * Email : 137361770@qq.com 53 | * GitHub : https://github.com/boai 54 | * 博客 : http://boaihome.com 55 | 56 | ********************************************************************************* 57 | 58 | */ 59 | 60 | 61 | #import 62 | 63 | /*! 随机色 */ 64 | CG_INLINE UIColor * 65 | BAKit_ColorRandom(){ 66 | return [UIColor colorWithRed:arc4random_uniform(255)/255.0 green:arc4random_uniform(255)/255.0 blue:arc4random_uniform(255)/255.0 alpha:1]; 67 | } 68 | 69 | /*! 70 | * 设置 viewRectCornerType 样式, 71 | * 注意:BAViewRectCornerType 必须要先设置 viewCornerRadius,才能有效,否则设置无效, 72 | */ 73 | typedef NS_ENUM(NSInteger, BAViewRectCornerType) { 74 | /*! 75 | * 设置下左角 圆角半径 76 | */ 77 | BAViewRectCornerTypeBottomLeft = 0, 78 | /*! 79 | * 设置下右角 圆角半径 80 | */ 81 | BAViewRectCornerTypeBottomRight, 82 | /*! 83 | * 设置上左角 圆角半径 84 | */ 85 | BAViewRectCornerTypeTopLeft, 86 | /*! 87 | * 设置下右角 圆角半径 88 | */ 89 | BAViewRectCornerTypeTopRight, 90 | /*! 91 | * 设置下左、下右角 圆角半径 92 | */ 93 | BAViewRectCornerTypeBottomLeftAndBottomRight, 94 | /*! 95 | * 设置上左、上右角 圆角半径 96 | */ 97 | BAViewRectCornerTypeTopLeftAndTopRight, 98 | /*! 99 | * 设置下左、上左角 圆角半径 100 | */ 101 | BAViewRectCornerTypeBottomLeftAndTopLeft, 102 | /*! 103 | * 设置下右、上右角 圆角半径 104 | */ 105 | BAViewRectCornerTypeBottomRightAndTopRight, 106 | /*! 107 | * 设置上左、上右、下右角 圆角半径 108 | */ 109 | BAViewRectCornerTypeBottomRightAndTopRightAndTopLeft, 110 | /*! 111 | * 设置下右、上右、下左角 圆角半径 112 | */ 113 | BAViewRectCornerTypeBottomRightAndTopRightAndBottomLeft, 114 | /*! 115 | * 设置全部四个角 圆角半径 116 | */ 117 | BAViewRectCornerTypeAllCorners 118 | }; 119 | 120 | @interface UIView (BARectCorner) 121 | 122 | /*! 123 | * 设置 viewRectCornerType 样式, 124 | * 注意:BAViewRectCornerType 必须要先设置 viewCornerRadius,才能有效,否则设置无效, 125 | */ 126 | @property (nonatomic, assign) BAViewRectCornerType viewRectCornerType; 127 | 128 | /*! 129 | * 设置 button 圆角,如果要全部设置四个角的圆角,可以直接用这个方法,必须要在设置 frame 之后 130 | */ 131 | @property (nonatomic, assign) CGFloat viewCornerRadius; 132 | 133 | /** 134 | 快速切圆角 135 | 136 | @param type 圆角样式 137 | @param viewCornerRadius 圆角角度 138 | */ 139 | - (void)ba_view_setBAViewRectCornerType:(BAViewRectCornerType)type viewCornerRadius:(CGFloat)viewCornerRadius; 140 | 141 | @end 142 | -------------------------------------------------------------------------------- /BATouchID/Lib/BAButton/UIView+BARectCorner.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+BARectCorner.m 3 | // BAButton 4 | // 5 | // Created by boai on 2017/5/19. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import "UIView+BARectCorner.h" 10 | #import 11 | 12 | static void *viewRectCornerTypeKey = @"viewRectCornerTypeKey"; 13 | static void *viewCornerRadiusKey = @"viewCornerRadiusKey"; 14 | 15 | @implementation UIView (BARectCorner) 16 | 17 | - (void)ba_view_setBAViewRectCornerType:(BAViewRectCornerType)type viewCornerRadius:(CGFloat)viewCornerRadius 18 | { 19 | self.viewCornerRadius = viewCornerRadius; 20 | self.viewRectCornerType = type; 21 | } 22 | 23 | #pragma mark - view 的 角半径,默认 CGSizeMake(0, 0) 24 | - (void)setupButtonCornerType 25 | { 26 | UIRectCorner corners; 27 | CGSize cornerRadii; 28 | 29 | cornerRadii = CGSizeMake(self.viewCornerRadius, self.viewCornerRadius); 30 | if (self.viewCornerRadius == 0) 31 | { 32 | cornerRadii = CGSizeMake(0, 0); 33 | } 34 | 35 | switch (self.viewRectCornerType) 36 | { 37 | case BAViewRectCornerTypeBottomLeft: 38 | { 39 | corners = UIRectCornerBottomLeft; 40 | } 41 | break; 42 | case BAViewRectCornerTypeBottomRight: 43 | { 44 | corners = UIRectCornerBottomRight; 45 | } 46 | break; 47 | case BAViewRectCornerTypeTopLeft: 48 | { 49 | corners = UIRectCornerTopLeft; 50 | } 51 | break; 52 | case BAViewRectCornerTypeTopRight: 53 | { 54 | corners = UIRectCornerTopRight; 55 | } 56 | break; 57 | case BAViewRectCornerTypeBottomLeftAndBottomRight: 58 | { 59 | corners = UIRectCornerBottomLeft | UIRectCornerBottomRight; 60 | } 61 | break; 62 | case BAViewRectCornerTypeTopLeftAndTopRight: 63 | { 64 | corners = UIRectCornerTopLeft | UIRectCornerTopRight; 65 | } 66 | break; 67 | case BAViewRectCornerTypeBottomLeftAndTopLeft: 68 | { 69 | corners = UIRectCornerBottomLeft | UIRectCornerTopLeft; 70 | } 71 | break; 72 | case BAViewRectCornerTypeBottomRightAndTopRight: 73 | { 74 | corners = UIRectCornerBottomRight | UIRectCornerTopRight; 75 | } 76 | break; 77 | case BAViewRectCornerTypeBottomRightAndTopRightAndTopLeft: 78 | { 79 | corners = UIRectCornerBottomRight | UIRectCornerTopRight | UIRectCornerTopLeft; 80 | } 81 | break; 82 | case BAViewRectCornerTypeBottomRightAndTopRightAndBottomLeft: 83 | { 84 | corners = UIRectCornerBottomRight | UIRectCornerTopRight | UIRectCornerBottomLeft; 85 | } 86 | break; 87 | case BAViewRectCornerTypeAllCorners: 88 | { 89 | corners = UIRectCornerAllCorners; 90 | } 91 | break; 92 | 93 | default: 94 | break; 95 | } 96 | 97 | UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds 98 | byRoundingCorners:corners 99 | cornerRadii:cornerRadii]; 100 | CAShapeLayer *maskLayer = [CAShapeLayer layer]; 101 | maskLayer.frame = self.bounds; 102 | maskLayer.path = maskPath.CGPath; 103 | self.layer.mask = maskLayer; 104 | } 105 | 106 | #pragma mark - setter / getter 107 | 108 | - (void)setViewRectCornerType:(BAViewRectCornerType)viewRectCornerType 109 | { 110 | objc_setAssociatedObject(self, viewRectCornerTypeKey, @(viewRectCornerType), OBJC_ASSOCIATION_ASSIGN); 111 | [self setupButtonCornerType]; 112 | } 113 | 114 | - (BAViewRectCornerType)viewRectCornerType 115 | { 116 | return [objc_getAssociatedObject(self, viewRectCornerTypeKey) integerValue]; 117 | } 118 | 119 | - (void)setViewCornerRadius:(CGFloat)viewCornerRadius 120 | { 121 | objc_setAssociatedObject(self, viewCornerRadiusKey, @(viewCornerRadius), OBJC_ASSOCIATION_ASSIGN); 122 | } 123 | 124 | - (CGFloat)viewCornerRadius 125 | { 126 | return [objc_getAssociatedObject(self, viewCornerRadiusKey) floatValue]; 127 | } 128 | 129 | @end 130 | -------------------------------------------------------------------------------- /BATouchID/Lib/BAKit/NSObject+BARunTime.h: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | * @header BAKit.h 4 | * BABaseProject 5 | * 6 | * @brief BAKit 7 | * 8 | * @author 博爱 9 | * @copyright Copyright © 2016年 博爱. All rights reserved. 10 | * @version V1.0 11 | */ 12 | 13 | // _ooOoo_ 14 | // o8888888o 15 | // 88" . "88 16 | // (| -_- |) 17 | // O\ = /O 18 | // ____/`---'\____ 19 | // . ' \\| |// `. 20 | // / \\||| : |||// \ 21 | // / _||||| -:- |||||- \ 22 | // | | \\\ - /// | | 23 | // | \_| ''\---/'' | | 24 | // \ .-\__ `-` ___/-. / 25 | // ___`. .' /--.--\ `. . __ 26 | // ."" '< `.___\_<|>_/___.' >'"". 27 | // | | : `- \`.;`\ _ /`;.`/ - ` : | | 28 | // \ \ `-. \_ __\ /__ _/ .-` / / 29 | // ======`-.____`-.___\_____/___.-`____.-'====== 30 | // `=---=' 31 | // 32 | // ............................................. 33 | // 佛祖镇楼 BUG辟易 34 | // 佛曰: 35 | // 写字楼里写字间,写字间里程序员; 36 | // 程序人员写程序,又拿程序换酒钱。 37 | // 酒醒只在网上坐,酒醉还来网下眠; 38 | // 酒醉酒醒日复日,网上网下年复年。 39 | // 但愿老死电脑间,不愿鞠躬老板前; 40 | // 奔驰宝马贵者趣,公交自行程序员。 41 | // 别人笑我忒疯癫,我笑自己命太贱; 42 | // 不见满街漂亮妹,哪个归得程序员? 43 | 44 | /* 45 | 46 | ********************************************************************************* 47 | * 48 | * 在使用BAKit的过程中如果出现bug请及时以以下任意一种方式联系我,我会及时修复bug 49 | * 50 | * QQ : 可以添加ios开发技术群 479663605 在这里找到我(博爱1616【137361770】) 51 | * 微博 : 博爱1616 52 | * Email : 137361770@qq.com 53 | * GitHub : https://github.com/boai 54 | * 博客 : http://boaihome.com 55 | 56 | ********************************************************************************* 57 | 58 | */ 59 | 60 | /** 61 | * - 添加运行时分类方法 62 | * - 用于运行时动态获取当前类的属性列表、方法列表、成员变量列表、协议列表 63 | * - 性能优化 64 | */ 65 | #import 66 | 67 | @interface NSObject (BARunTime) 68 | 69 | /** 70 | * 将 ‘字典数组‘ 转换成当前模型的对象数组 71 | * 72 | * @param array 字典数组 73 | * 74 | * @return 返回模型对象的数组 75 | */ 76 | + (NSArray *)ba_objectsWithArray:(NSArray *)array; 77 | 78 | /** 79 | * 返回当前类的所有属性列表 80 | * 81 | * @return 属性名称 82 | */ 83 | + (NSArray *)ba_propertysList; 84 | 85 | /** 86 | * 返回当前类的所有成员变量数组 87 | * 88 | * @return 当前类的所有成员变量! 89 | * 90 | * Tips:用于调试, 可以尝试查看所有不开源的类的ivar 91 | */ 92 | + (NSArray *)ba_ivarList; 93 | 94 | /** 95 | * 返回当前类的所有方法 96 | * 97 | * @return 当前类的所有成员变量! 98 | */ 99 | + (NSArray *)ba_methodList; 100 | 101 | /** 102 | * 返回当前类的所有协议 103 | * 104 | * @return 当前类的所有协议! 105 | */ 106 | + (NSArray *)ba_protocolList; 107 | 108 | @end 109 | -------------------------------------------------------------------------------- /BATouchID/Lib/BAKit/NSObject+BARunTime.m: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | * @header BAKit.h 4 | * BABaseProject 5 | * 6 | * @brief BAKit 7 | * 8 | * @author 博爱 9 | * @copyright Copyright © 2016年 博爱. All rights reserved. 10 | * @version V1.0 11 | */ 12 | 13 | // _ooOoo_ 14 | // o8888888o 15 | // 88" . "88 16 | // (| -_- |) 17 | // O\ = /O 18 | // ____/`---'\____ 19 | // . ' \\| |// `. 20 | // / \\||| : |||// \ 21 | // / _||||| -:- |||||- \ 22 | // | | \\\ - /// | | 23 | // | \_| ''\---/'' | | 24 | // \ .-\__ `-` ___/-. / 25 | // ___`. .' /--.--\ `. . __ 26 | // ."" '< `.___\_<|>_/___.' >'"". 27 | // | | : `- \`.;`\ _ /`;.`/ - ` : | | 28 | // \ \ `-. \_ __\ /__ _/ .-` / / 29 | // ======`-.____`-.___\_____/___.-`____.-'====== 30 | // `=---=' 31 | // 32 | // ............................................. 33 | // 佛祖镇楼 BUG辟易 34 | // 佛曰: 35 | // 写字楼里写字间,写字间里程序员; 36 | // 程序人员写程序,又拿程序换酒钱。 37 | // 酒醒只在网上坐,酒醉还来网下眠; 38 | // 酒醉酒醒日复日,网上网下年复年。 39 | // 但愿老死电脑间,不愿鞠躬老板前; 40 | // 奔驰宝马贵者趣,公交自行程序员。 41 | // 别人笑我忒疯癫,我笑自己命太贱; 42 | // 不见满街漂亮妹,哪个归得程序员? 43 | 44 | /* 45 | 46 | ********************************************************************************* 47 | * 48 | * 在使用BAKit的过程中如果出现bug请及时以以下任意一种方式联系我,我会及时修复bug 49 | * 50 | * QQ : 可以添加ios开发技术群 479663605 在这里找到我(博爱1616【137361770】) 51 | * 微博 : 博爱1616 52 | * Email : 137361770@qq.com 53 | * GitHub : https://github.com/boai 54 | * 博客园 : http://www.cnblogs.com/boai/ 55 | * 博客 : http://boai.github.io 56 | * 简书 : http://www.jianshu.com/users/95c9800fdf47/latest_articles 57 | * 简书专题 : http://www.jianshu.com/collection/072d578bf782 58 | 59 | ********************************************************************************* 60 | 61 | */ 62 | 63 | 64 | #import "NSObject+BARunTime.h" 65 | #import 66 | 67 | @implementation NSObject (BARunTime) 68 | 69 | #pragma mark - 根据传递进来的所有字典数组 字典转模型 70 | + (NSArray *)ba_objectsWithArray:(NSArray *)array 71 | { 72 | if (array.count == 0) 73 | { 74 | return nil; 75 | } 76 | 77 | // 判断是否是字典数组 78 | NSAssert([array[0] isKindOfClass:[NSDictionary class]], @"必须传入字典数组"); 79 | 80 | // 获取属性列表数组 81 | NSArray *propertyList = [self ba_propertysList]; 82 | 83 | NSMutableArray *arrayM = [NSMutableArray array]; 84 | 85 | for (NSDictionary *dict in array) 86 | { 87 | // 创建模型 88 | id model = [self new]; 89 | 90 | // 遍历数组 91 | for (NSString *key in dict) 92 | { 93 | // 判断属性列表数组中是否包含当前key 如果有, 意味着属性存在 94 | if ([propertyList containsObject:key]) { 95 | // 字典转模型 96 | [model setValue:dict[key] forKey:key]; 97 | } 98 | } 99 | // 添加到可变数组中 100 | [arrayM addObject:model]; 101 | } 102 | return arrayM.copy; 103 | } 104 | 105 | #pragma mark - 获取本类所有 ‘属性‘ 的数组 106 | /** 程序运行的时候动态的获取当前类的属性列表 107 | * 程序运行的时候,类的属性不会变化 108 | */ 109 | const void *ba_propertyListKey = @"ba_propertyListKey"; 110 | + (NSArray *)ba_propertysList 111 | { 112 | NSArray *result = objc_getAssociatedObject(self, ba_propertyListKey); 113 | 114 | if (result != nil) 115 | { 116 | return result; 117 | } 118 | 119 | NSMutableArray *arrayM = [NSMutableArray array]; 120 | // 获取当前类的属性数组 121 | // count -> 属性的数量 122 | unsigned int count = 0; 123 | objc_property_t *list = class_copyPropertyList([self class], &count); 124 | 125 | for (unsigned int i = 0; i < count; i++) { 126 | // 根据下标获取属性 127 | objc_property_t property = list[i]; 128 | 129 | // 获取属性的名字 130 | const char *cName = property_getName(property); 131 | 132 | // 转换成OC字符串 133 | NSString *name = [NSString stringWithUTF8String:cName]; 134 | [arrayM addObject:name]; 135 | } 136 | 137 | /*! ⚠️注意: 一定要释放数组 class_copyPropertyList底层为C语言,所以我们一定要记得释放properties */ 138 | free(list); 139 | 140 | // ---保存属性数组对象--- 141 | objc_setAssociatedObject(self, ba_propertyListKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC); 142 | 143 | return objc_getAssociatedObject(self, ba_propertyListKey); 144 | } 145 | 146 | #pragma mark - 获取本类所有 ‘方法‘ 的数组 147 | const void *ba_methodListKey = "ba_methodListKey"; 148 | + (NSArray *)ba_methodList 149 | { 150 | // 1. 使用运行时动态添加属性 151 | NSArray *methodsList = objc_getAssociatedObject(self, ba_methodListKey); 152 | 153 | // 2. 如果数组中直接返回方法数组 154 | if (methodsList != nil) 155 | { 156 | return methodsList; 157 | } 158 | 159 | // 3. 获取当前类的方法数组 160 | unsigned int count = 0; 161 | Method *list = class_copyMethodList([self class], &count); 162 | 163 | NSMutableArray *arrayM = [NSMutableArray array]; 164 | for (unsigned int i = 0; i < count; i++) 165 | { 166 | // 根据下标获取方法 167 | Method method = list[i]; 168 | 169 | SEL methodName = method_getName(method); 170 | 171 | NSString *methodName_OC = NSStringFromSelector(methodName); 172 | 173 | IMP imp = method_getImplementation(method); 174 | const char *name_s =sel_getName(method_getName(method)); 175 | int arguments = method_getNumberOfArguments(method); 176 | const char* encoding =method_getTypeEncoding(method); 177 | NSLog(@"方法名:%@,参数个数:%d,编码方式:%@",[NSString stringWithUTF8String:name_s], 178 | arguments, 179 | [NSString stringWithUTF8String:encoding]); 180 | 181 | [arrayM addObject:methodName_OC]; 182 | } 183 | 184 | // 4. 释放数组 185 | free(list); 186 | 187 | // 5. 保存方法的数组对象 188 | objc_setAssociatedObject(self, ba_methodListKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC); 189 | 190 | return objc_getAssociatedObject(self, ba_methodListKey); 191 | } 192 | 193 | 194 | #pragma mark - 获取本类所有 ‘成员变量‘ 的数组 <用来调试> 195 | /** 获取当前类的所有成员变量 */ 196 | const char *ba_ivarListKey = "ba_ivarListKey"; 197 | + (NSArray *)ba_ivarList 198 | { 199 | 200 | // 1. 查询根据key 保存的成员变量数组 201 | NSArray *ivarList = objc_getAssociatedObject(self, ba_ivarListKey); 202 | 203 | // 2. 判断数组中是否有值, 如果有直接返回 204 | if (ivarList != nil) 205 | { 206 | return ivarList; 207 | } 208 | 209 | // 3. 如果数组中没有, 则根据当前类,获取当前类的所有 ‘成员变量‘ 210 | unsigned int count = 0; 211 | Ivar *ivars = class_copyIvarList([self class], &count); 212 | 213 | // 4. 遍历 成员变量 数组, 获取成员变量的名 214 | NSMutableArray *arrayM = [NSMutableArray array]; 215 | for (unsigned int i = 0; i < count; i++) { 216 | Ivar ivar = ivars[i]; 217 | // - C语言的字符串都是 ‘char *‘ 类型的 218 | const char *ivarName_C = ivar_getName(ivar); 219 | 220 | // - 将 C语言的字符串 转换成 OC字符串 221 | NSString *ivarName_OC = [NSString stringWithUTF8String:ivarName_C]; 222 | // - 将本类 ‘成员变量名‘ 添加到数组 223 | [arrayM addObject:ivarName_OC]; 224 | } 225 | 226 | // 5. 释放ivars 227 | free(ivars); 228 | 229 | // 6. 根据key 动态获取保存在关联对象中的数组 230 | objc_setAssociatedObject(self, ba_ivarListKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC); 231 | 232 | return objc_getAssociatedObject(self, ba_ivarListKey); 233 | } 234 | 235 | #pragma mark - 获取本类所有 ‘协议‘ 的数组 236 | /** 用来获取动态保存在关联对象中的协议数组 |运行时的关联对象根据key动态取值| */ 237 | const char *ba_protocolListKey = "ba_protocolListKey"; 238 | 239 | + (NSArray *)ba_protocolList { 240 | NSArray *protocolList = objc_getAssociatedObject(self, ba_protocolListKey); 241 | if (protocolList != nil) 242 | { 243 | return protocolList; 244 | } 245 | 246 | unsigned int count = 0; 247 | Protocol * __unsafe_unretained *protocolLists = class_copyProtocolList([self class], &count); 248 | 249 | NSMutableArray *arrayM = [NSMutableArray array]; 250 | for (unsigned int i = 0; i < count; i++) { 251 | // 获取 协议名 252 | Protocol *protocol = protocolLists[i]; 253 | const char *protocolName_C = protocol_getName(protocol); 254 | NSString *protocolName_OC = [NSString stringWithUTF8String:protocolName_C]; 255 | 256 | // 将 协议名 添加到数组 257 | [arrayM addObject:protocolName_OC]; 258 | } 259 | 260 | // 释放数组 261 | free(protocolLists); 262 | // 将保存 协议的数组动态添加到 关联对象 263 | objc_setAssociatedObject(self, ba_protocolListKey, arrayM, OBJC_ASSOCIATION_COPY_NONATOMIC); 264 | 265 | return objc_getAssociatedObject(self, ba_protocolListKey); 266 | } 267 | 268 | @end 269 | -------------------------------------------------------------------------------- /BATouchID/Lib/BAKit/NSString+BAKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+BAKit.h 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/25. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSString (BAKit) 12 | 13 | #pragma mark 判断两个时间差 14 | + (NSString *)ba_intervalSinceNow:(NSDate *)theDate; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /BATouchID/Lib/BAKit/NSString+BAKit.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+BAKit.m 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/25. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import "NSString+BAKit.h" 10 | 11 | @implementation NSString (BAKit) 12 | 13 | #pragma mark 判断两个时间差 14 | + (NSString *)ba_intervalSinceNow:(NSDate *)theDate 15 | { 16 | NSTimeInterval late = [theDate timeIntervalSince1970]*1; 17 | 18 | NSDate *dat = [NSDate date]; 19 | NSTimeInterval now=[dat timeIntervalSince1970]*1; 20 | 21 | 22 | NSTimeInterval cha = now -late; 23 | NSString *timeString=[NSString stringWithFormat:@"%f",cha]; 24 | 25 | return timeString; 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /BATouchID/Lib/BAKit/UIAlertController+Blocks.h: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | * @header BAKit.h 4 | * BABaseProject 5 | * 6 | * @brief BAKit 7 | * 8 | * @author 博爱 9 | * @copyright Copyright © 2016年 博爱. All rights reserved. 10 | * @version V1.0 11 | */ 12 | 13 | // _ooOoo_ 14 | // o8888888o 15 | // 88" . "88 16 | // (| -_- |) 17 | // O\ = /O 18 | // ____/`---'\____ 19 | // . ' \\| |// `. 20 | // / \\||| : |||// \ 21 | // / _||||| -:- |||||- \ 22 | // | | \\\ - /// | | 23 | // | \_| ''\---/'' | | 24 | // \ .-\__ `-` ___/-. / 25 | // ___`. .' /--.--\ `. . __ 26 | // ."" '< `.___\_<|>_/___.' >'"". 27 | // | | : `- \`.;`\ _ /`;.`/ - ` : | | 28 | // \ \ `-. \_ __\ /__ _/ .-` / / 29 | // ======`-.____`-.___\_____/___.-`____.-'====== 30 | // `=---=' 31 | // 32 | // ............................................. 33 | // 佛祖镇楼 BUG辟易 34 | // 佛曰: 35 | // 写字楼里写字间,写字间里程序员; 36 | // 程序人员写程序,又拿程序换酒钱。 37 | // 酒醒只在网上坐,酒醉还来网下眠; 38 | // 酒醉酒醒日复日,网上网下年复年。 39 | // 但愿老死电脑间,不愿鞠躬老板前; 40 | // 奔驰宝马贵者趣,公交自行程序员。 41 | // 别人笑我忒疯癫,我笑自己命太贱; 42 | // 不见满街漂亮妹,哪个归得程序员? 43 | 44 | /* 45 | 46 | ********************************************************************************* 47 | * 48 | * 在使用BAKit的过程中如果出现bug请及时以以下任意一种方式联系我,我会及时修复bug 49 | * 50 | * QQ : 可以添加ios开发技术群 479663605 在这里找到我(博爱1616【137361770】) 51 | * 微博 : 博爱1616 52 | * Email : 137361770@qq.com 53 | * GitHub : https://github.com/boai 54 | * 博客 : http://boaihome.com 55 | 56 | ********************************************************************************* 57 | 58 | */ 59 | 60 | #import 61 | 62 | #if TARGET_OS_IOS 63 | typedef void (^UIAlertControllerPopoverPresentationControllerBlock) (UIPopoverPresentationController * __nonnull popover); 64 | #endif 65 | typedef void (^UIAlertControllerCompletionBlock) (UIAlertController * __nonnull controller, UIAlertAction * __nonnull action, NSInteger buttonIndex); 66 | 67 | @interface UIAlertController (Blocks) 68 | 69 | @property (readonly, nonatomic) BOOL visible; 70 | 71 | /** 72 | 快速创建一个系统 Alert 或者 ActionSheet 73 | 74 | @param viewController 显示的VC 75 | @param title title 76 | @param mutableAttributedTitle mutableAttributedTitle 77 | @param message message 78 | @param mutableAttributedMessage mutableAttributedMessage 79 | @param preferredStyle 选择 alert 样式 或者 ActionSheet 样式 80 | @param buttonTitlesArray 按钮数组 81 | @param buttonTitleColorArray 按钮颜色数组,默认:系统蓝色,如果颜色数组个数小于title数组个数,则全部为默认蓝色 82 | @param popoverPresentationControllerBlock popoverPresentationControllerBlock 83 | @param tapBlock tapBlock 84 | @return 一个系统 Alert 或者 ActionSheet 85 | */ 86 | + (nonnull instancetype)ba_alertControllerShowInViewController:(nonnull UIViewController *)viewController 87 | withTitle:(nullable NSString *)title 88 | mutableAttributedTitle:(nullable NSMutableAttributedString *)mutableAttributedTitle 89 | message:(nullable NSString *)message 90 | mutableAttributedMessage:(nullable NSMutableAttributedString *)mutableAttributedMessage 91 | preferredStyle:(UIAlertControllerStyle)preferredStyle 92 | buttonTitlesArray:(nullable NSArray *)buttonTitlesArray 93 | buttonTitleColorArray:(nullable NSArray *)buttonTitleColorArray 94 | #if TARGET_OS_IOS 95 | popoverPresentationControllerBlock:(nullable UIAlertControllerPopoverPresentationControllerBlock)popoverPresentationControllerBlock 96 | #endif 97 | tapBlock:(nullable UIAlertControllerCompletionBlock)tapBlock; 98 | 99 | /** 100 | 快速创建一个系统 Alert 101 | 102 | @param viewController 显示的VC 103 | @param title title 104 | @param mutableAttributedTitle mutableAttributedTitle 105 | @param message message 106 | @param mutableAttributedMessage mutableAttributedMessage 107 | @param buttonTitlesArray 按钮数组 108 | @param buttonTitleColorArray 按钮颜色数组,默认:系统蓝色,如果颜色数组个数小于title数组个数,则全部为默认蓝色 109 | @param tapBlock tapBlock 110 | @return Alert 111 | */ 112 | + (nonnull instancetype)ba_alertControllerShowAlertInViewController:(nonnull UIViewController *)viewController 113 | withTitle:(nullable NSString *)title 114 | mutableAttributedTitle:(nullable NSMutableAttributedString *)mutableAttributedTitle 115 | message:(nullable NSString *)message 116 | mutableAttributedMessage:(nullable NSMutableAttributedString *)mutableAttributedMessage 117 | buttonTitlesArray:(nullable NSArray *)buttonTitlesArray 118 | buttonTitleColorArray:(nullable NSArray *)buttonTitleColorArray 119 | tapBlock:(nullable UIAlertControllerCompletionBlock)tapBlock; 120 | 121 | /** 122 | 快速创建一个系统 ActionSheet 123 | 124 | @param viewController 显示的VC 125 | @param title title 126 | @param mutableAttributedTitle mutableAttributedTitle 127 | @param message message 128 | @param mutableAttributedMessage mutableAttributedMessage 129 | @param buttonTitlesArray 按钮数组 130 | @param buttonTitleColorArray 按钮颜色数组,默认:系统蓝色,如果颜色数组个数小于title数组个数,则全部为默认蓝色 131 | @param popoverPresentationControllerBlock popoverPresentationControllerBlock description 132 | @param tapBlock tapBlock description 133 | @return ActionSheet 134 | */ 135 | + (nonnull instancetype)ba_alertControllerShowActionSheetInViewController:(nonnull UIViewController *)viewController 136 | withTitle:(nullable NSString *)title 137 | mutableAttributedTitle:(nullable NSMutableAttributedString *)mutableAttributedTitle 138 | message:(nullable NSString *)message 139 | mutableAttributedMessage:(nullable NSMutableAttributedString *)mutableAttributedMessage 140 | buttonTitlesArray:(nullable NSArray *)buttonTitlesArray 141 | buttonTitleColorArray:(nullable NSArray *)buttonTitleColorArray 142 | #if TARGET_OS_IOS 143 | popoverPresentationControllerBlock:(nullable UIAlertControllerPopoverPresentationControllerBlock)popoverPresentationControllerBlock 144 | #endif 145 | tapBlock:(nullable UIAlertControllerCompletionBlock)tapBlock; 146 | 147 | @end 148 | -------------------------------------------------------------------------------- /BATouchID/Lib/BAKit/UIAlertController+Blocks.m: -------------------------------------------------------------------------------- 1 | 2 | #import "UIAlertController+Blocks.h" 3 | #import 4 | #import 5 | #import "NSObject+BARunTime.h" 6 | 7 | //static NSInteger const UIAlertControllerBlocksFirstOtherButtonIndex = 2; 8 | 9 | @interface UIViewController (UACB_Topmost) 10 | 11 | - (UIViewController *)uacb_topmost; 12 | 13 | @end 14 | 15 | @implementation UIAlertController (Blocks) 16 | 17 | + (instancetype)ba_alertControllerShowInViewController:(UIViewController *)viewController 18 | withTitle:(NSString *)title 19 | mutableAttributedTitle:(nullable NSMutableAttributedString *)mutableAttributedTitle 20 | message:(NSString *)message 21 | mutableAttributedMessage:(nullable NSMutableAttributedString *)mutableAttributedMessage 22 | preferredStyle:(UIAlertControllerStyle)preferredStyle 23 | buttonTitlesArray:(nullable NSArray *)buttonTitlesArray 24 | buttonTitleColorArray:(nullable NSArray *)buttonTitleColorArray 25 | #if TARGET_OS_IOS 26 | popoverPresentationControllerBlock:(void(^)(UIPopoverPresentationController *popover))popoverPresentationControllerBlock 27 | #endif 28 | tapBlock:(UIAlertControllerCompletionBlock)tapBlock 29 | { 30 | UIAlertController *strongController = [self alertControllerWithTitle:title 31 | message:message 32 | preferredStyle:preferredStyle]; 33 | 34 | __weak UIAlertController *controller = strongController; 35 | 36 | if (buttonTitlesArray) 37 | { 38 | for (NSUInteger i = 0; i < buttonTitlesArray.count; i++) 39 | { 40 | NSString *buttonTitle = buttonTitlesArray[i]; 41 | 42 | UIAlertAction *action = [UIAlertAction actionWithTitle:buttonTitle 43 | style:UIAlertActionStyleDefault 44 | handler:^(UIAlertAction *action){ 45 | if (tapBlock) { 46 | tapBlock(controller, action, i); 47 | } 48 | }]; 49 | [controller addAction:action]; 50 | 51 | if (!buttonTitleColorArray || buttonTitleColorArray.count == 0 || 52 | buttonTitleColorArray.count < buttonTitlesArray.count) 53 | { 54 | NSMutableArray *mutArr = [NSMutableArray array]; 55 | for (NSInteger i = 0; i < buttonTitlesArray.count; i ++) 56 | { 57 | [mutArr addObject:[UIColor blueColor]]; 58 | } 59 | buttonTitleColorArray = [mutArr mutableCopy]; 60 | } 61 | if (buttonTitleColorArray) 62 | { 63 | [strongController setAlertWithAlert:strongController 64 | mutableAttributedTitle:mutableAttributedTitle 65 | mutableAttributedMessage:mutableAttributedMessage 66 | Action:action 67 | buttonTitleColor:buttonTitleColorArray[i]]; 68 | } 69 | } 70 | } 71 | 72 | if (preferredStyle == UIAlertControllerStyleActionSheet) 73 | { 74 | UIAlertAction *action = [UIAlertAction actionWithTitle:@"取 消" 75 | style:UIAlertActionStyleCancel 76 | handler:nil]; 77 | [controller addAction:action]; 78 | } 79 | 80 | #if TARGET_OS_IOS 81 | if (popoverPresentationControllerBlock) 82 | { 83 | popoverPresentationControllerBlock(controller.popoverPresentationController); 84 | } 85 | #endif 86 | 87 | [viewController.uacb_topmost presentViewController:controller animated:YES completion:nil]; 88 | 89 | return controller; 90 | } 91 | 92 | + (instancetype)ba_alertControllerShowAlertInViewController:(UIViewController *)viewController 93 | withTitle:(NSString *)title 94 | mutableAttributedTitle:(nullable NSMutableAttributedString *)mutableAttributedTitle 95 | message:(NSString *)message 96 | mutableAttributedMessage:(nullable NSMutableAttributedString *)mutableAttributedMessage 97 | buttonTitlesArray:(nullable NSArray *)buttonTitlesArray 98 | buttonTitleColorArray:(nullable NSArray *)buttonTitleColorArray 99 | tapBlock:(UIAlertControllerCompletionBlock)tapBlock 100 | { 101 | return [self ba_alertControllerShowInViewController:viewController 102 | withTitle:title 103 | mutableAttributedTitle:mutableAttributedTitle 104 | message:message 105 | mutableAttributedMessage:mutableAttributedMessage 106 | preferredStyle:UIAlertControllerStyleAlert 107 | buttonTitlesArray:buttonTitlesArray 108 | buttonTitleColorArray:buttonTitleColorArray 109 | #if TARGET_OS_IOS 110 | popoverPresentationControllerBlock:nil 111 | #endif 112 | tapBlock:tapBlock]; 113 | } 114 | 115 | + (instancetype)ba_alertControllerShowActionSheetInViewController:(UIViewController *)viewController 116 | withTitle:(NSString *)title 117 | mutableAttributedTitle:(nullable NSMutableAttributedString *)mutableAttributedTitle 118 | message:(NSString *)message 119 | mutableAttributedMessage:(nullable NSMutableAttributedString *)mutableAttributedMessage 120 | buttonTitlesArray:(nullable NSArray *)buttonTitlesArray 121 | buttonTitleColorArray:(nullable NSArray *)buttonTitleColorArray 122 | #if TARGET_OS_IOS 123 | popoverPresentationControllerBlock:(void(^)(UIPopoverPresentationController *popover))popoverPresentationControllerBlock 124 | #endif 125 | tapBlock:(UIAlertControllerCompletionBlock)tapBlock 126 | { 127 | return [self ba_alertControllerShowInViewController:viewController 128 | withTitle:title 129 | mutableAttributedTitle:mutableAttributedTitle 130 | message:message 131 | mutableAttributedMessage:mutableAttributedMessage 132 | preferredStyle:UIAlertControllerStyleActionSheet 133 | buttonTitlesArray:buttonTitlesArray 134 | buttonTitleColorArray:buttonTitleColorArray 135 | #if TARGET_OS_IOS 136 | popoverPresentationControllerBlock:popoverPresentationControllerBlock 137 | #endif 138 | tapBlock:tapBlock]; 139 | } 140 | 141 | #pragma mark - 142 | 143 | - (BOOL)visible 144 | { 145 | return self.view.superview != nil; 146 | } 147 | 148 | - (void)setAlertWithAlert:(UIAlertController * __nonnull )alert 149 | mutableAttributedTitle:(NSMutableAttributedString *)mutableAttributedTitle 150 | mutableAttributedMessage:(nullable NSMutableAttributedString *)mutableAttributedMessage 151 | Action:(UIAlertAction * __nonnull )action 152 | buttonTitleColor:(UIColor *)buttonTitleColor 153 | { 154 | /*! 1、首先获得对应的属性 */ 155 | // NSArray *propertysListArray = [[UIAlertController class] ba_propertysList]; 156 | // NSLog(@"1、获取【UIAlertController】所有的属性名:%@", propertysListArray); 157 | 158 | /*! 2、获得成员变量 */ 159 | NSArray *ivarListArray = [[UIAlertAction class] ba_ivarList]; 160 | // NSLog(@"2、获取【UIAlertController】所有的成员变量:%@", ivarListArray); 161 | 162 | for (NSInteger i = 0; i < ivarListArray.count; i++) 163 | { 164 | NSString *ivarName = ivarListArray[i]; 165 | if ([ivarName isEqualToString:@"_titleTextColor"]) 166 | { 167 | [action setValue:buttonTitleColor forKey:@"titleTextColor"]; 168 | } 169 | } 170 | 171 | /*! 3、改变显示提示字体颜色 */ 172 | NSArray *propertysListArray2 = [[UIAlertController class] ba_ivarList]; 173 | // NSLog(@"3、获取【UIAlertController】所有的成员变量:%@", propertysListArray2); 174 | for (NSInteger i = 0; i < propertysListArray2.count; i++) 175 | { 176 | NSString *ivarName = propertysListArray2[i]; 177 | if ([ivarName isEqualToString:@"_attributedTitle"]) 178 | { 179 | [alert setValue:mutableAttributedTitle forKey:@"attributedTitle"]; 180 | } 181 | if ([ivarName isEqualToString:@"_attributedMessage"]) 182 | { 183 | [alert setValue:mutableAttributedMessage forKey:@"attributedMessage"]; 184 | } 185 | } 186 | } 187 | 188 | @end 189 | 190 | @implementation UIViewController (UACB_Topmost) 191 | 192 | - (UIViewController *)uacb_topmost 193 | { 194 | UIViewController *topmost = self; 195 | 196 | UIViewController *above; 197 | while ((above = topmost.presentedViewController)) { 198 | topmost = above; 199 | } 200 | 201 | return topmost; 202 | } 203 | 204 | @end 205 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/CLLockVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // CLLockVC.h 3 | // CoreLock 4 | // 5 | // Created by 成林 on 15/4/21. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSInteger, CoreLockType) { 12 | //设置密码 13 | CoreLockTypeSetPwd=0, 14 | //输入并验证密码 15 | CoreLockTypeVeryfiPwd, 16 | //修改密码 17 | CoreLockTypeModifyPwd, 18 | }; 19 | 20 | @interface CLLockVC : UIViewController 21 | 22 | @property (nonatomic,assign) CoreLockType type; 23 | 24 | /* 25 | * 是否有本地密码缓存?即用户是否设置过初始密码? 26 | */ 27 | + (BOOL)hasPwd; 28 | 29 | /* 30 | * 展示设置密码控制器 31 | */ 32 | + (instancetype)showSettingLockVCInVC:(UIViewController *)vc 33 | successBlock:(void(^)(CLLockVC *lockVC, NSString *pwd))successBlock; 34 | 35 | /* 36 | * 展示验证密码输入框 37 | */ 38 | + (instancetype)showVerifyLockVCInVC:(UIViewController *)vc 39 | forgetPwdBlock:(void(^)())forgetPwdBlock 40 | successBlock:(void(^)(CLLockVC *lockVC, NSString *pwd))successBlock; 41 | 42 | /* 43 | * 展示修改密码输入框 44 | */ 45 | + (instancetype)showModifyLockVCInVC:(UIViewController *)vc 46 | successBlock:(void(^)(CLLockVC *lockVC, NSString *pwd))successBlock; 47 | 48 | /* 49 | * 消失 50 | */ 51 | - (void)dismiss:(NSTimeInterval)interval; 52 | 53 | #pragma mark - 密码移除 54 | + (void)ba_setPwdRemove; 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/CLLockVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // CLLockVC.m 3 | // CoreLock 4 | // 5 | // Created by 成林 on 15/4/21. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import "CLLockVC.h" 10 | #import "CoreLockConst.h" 11 | #import "CoreArchive.h" 12 | #import "CLLockLabel.h" 13 | #import "CLLockNavVC.h" 14 | #import "CLLockView.h" 15 | 16 | @interface CLLockVC () 17 | 18 | /** 操作成功:密码设置成功、密码验证成功 */ 19 | @property (nonatomic,copy) void (^successBlock)(CLLockVC *lockVC,NSString *pwd); 20 | 21 | @property (nonatomic,copy) void (^forgetPwdBlock)(CLLockVC *lockVC); 22 | 23 | @property (weak, nonatomic) IBOutlet CLLockLabel *label; 24 | 25 | @property (nonatomic,copy) NSString *msg; 26 | 27 | @property (weak, nonatomic) IBOutlet CLLockView *lockView; 28 | 29 | @property (nonatomic,weak) UIViewController *vc; 30 | 31 | @property (nonatomic,strong) UIBarButtonItem *resetItem; 32 | 33 | @property (nonatomic,copy) NSString *modifyCurrentTitle; 34 | 35 | @property (weak, nonatomic) IBOutlet UIView *actionView; 36 | 37 | @property (weak, nonatomic) IBOutlet UIButton *modifyBtn; 38 | 39 | /** 直接进入修改页面的 */ 40 | @property (nonatomic,assign) BOOL isDirectModify; 41 | 42 | @end 43 | 44 | @implementation CLLockVC 45 | 46 | - (void)viewDidLoad 47 | { 48 | [super viewDidLoad]; 49 | 50 | //控制器准备 51 | [self vcPrepare]; 52 | 53 | //数据传输 54 | [self dataTransfer]; 55 | 56 | //事件 57 | [self event]; 58 | } 59 | 60 | 61 | /* 62 | * 事件 63 | */ 64 | - (void)event 65 | { 66 | /* 67 | * 设置密码 68 | */ 69 | 70 | /** 开始输入:第一次 */ 71 | self.lockView.setPWBeginBlock = ^(){ 72 | 73 | [self.label showNormalMsg:CoreLockPWDTitleFirst]; 74 | }; 75 | 76 | /** 开始输入:确认 */ 77 | self.lockView.setPWConfirmlock = ^(){ 78 | 79 | [self.label showNormalMsg:CoreLockPWDTitleConfirm]; 80 | }; 81 | 82 | /** 密码长度不够 */ 83 | self.lockView.setPWSErrorLengthTooShortBlock = ^(NSUInteger currentCount){ 84 | 85 | [self.label showWarnMsg:[NSString stringWithFormat:@"请连接至少%@个点",@(CoreLockMinItemCount)]]; 86 | }; 87 | 88 | /** 两次密码不一致 */ 89 | self.lockView.setPWSErrorTwiceDiffBlock = ^(NSString *pwd1,NSString *pwdNow){ 90 | 91 | [self.label showWarnMsg:CoreLockPWDDiffTitle]; 92 | 93 | self.navigationItem.rightBarButtonItem = self.resetItem; 94 | }; 95 | 96 | /** 第一次输入密码:正确 */ 97 | self.lockView.setPWFirstRightBlock = ^(){ 98 | 99 | [self.label showNormalMsg:CoreLockPWDTitleConfirm]; 100 | }; 101 | 102 | /** 再次输入密码一致 */ 103 | self.lockView.setPWTwiceSameBlock = ^(NSString *pwd){ 104 | 105 | [self.label showNormalMsg:CoreLockPWSuccessTitle]; 106 | 107 | //存储密码 108 | [CoreArchive setStr:pwd key:CoreLockPWDKey]; 109 | 110 | //禁用交互 111 | self.view.userInteractionEnabled = NO; 112 | 113 | if(_successBlock != nil) _successBlock(self,pwd); 114 | 115 | // if(CoreLockTypeModifyPwd == _type){ 116 | // [self dismiss:0.5f]; 117 | // } 118 | }; 119 | 120 | /* 121 | * 验证密码 122 | */ 123 | 124 | /** 开始 */ 125 | self.lockView.verifyPWBeginBlock = ^(){ 126 | 127 | [self.label showNormalMsg:CoreLockVerifyNormalTitle]; 128 | }; 129 | 130 | /** 验证 */ 131 | self.lockView.verifyPwdBlock = ^(NSString *pwd){ 132 | 133 | //取出本地密码 134 | NSString *pwdLocal = [CoreArchive strForKey:CoreLockPWDKey]; 135 | 136 | BOOL res = [pwdLocal isEqualToString:pwd]; 137 | 138 | if(res){//密码一致 139 | 140 | [self.label showNormalMsg:CoreLockVerifySuccesslTitle]; 141 | 142 | if(CoreLockTypeVeryfiPwd == _type){ 143 | 144 | //禁用交互 145 | self.view.userInteractionEnabled = NO; 146 | 147 | }else if (CoreLockTypeModifyPwd == _type){//修改密码 148 | 149 | [self.label showNormalMsg:CoreLockPWDTitleFirst]; 150 | 151 | self.modifyCurrentTitle = CoreLockPWDTitleFirst; 152 | } 153 | 154 | if(CoreLockTypeVeryfiPwd == _type) { 155 | if(_successBlock != nil) _successBlock(self,pwd); 156 | } 157 | 158 | } 159 | else 160 | { 161 | // 密码不一致 162 | [self.label showWarnMsg:CoreLockVerifyErrorPwdTitle]; 163 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"忘记密码" style:UIBarButtonItemStylePlain target:self action:@selector(forgetPwd)];; 164 | } 165 | return res; 166 | }; 167 | 168 | /* 169 | * 修改 170 | */ 171 | 172 | /** 开始 */ 173 | self.lockView.modifyPwdBlock =^(){ 174 | 175 | [self.label showNormalMsg:self.modifyCurrentTitle]; 176 | }; 177 | } 178 | 179 | /* 180 | * 数据传输 181 | */ 182 | -(void)dataTransfer{ 183 | 184 | [self.label showNormalMsg:self.msg]; 185 | 186 | //传递类型 187 | self.lockView.type = self.type; 188 | } 189 | 190 | /* 191 | * 控制器准备 192 | */ 193 | -(void)vcPrepare{ 194 | 195 | //设置背景色 196 | self.view.backgroundColor = CoreLockViewBgColor; 197 | 198 | //初始情况隐藏 199 | self.navigationItem.rightBarButtonItem = nil; 200 | 201 | self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil]; 202 | 203 | //默认标题 204 | self.modifyCurrentTitle = CoreLockModifyNormalTitle; 205 | 206 | if(CoreLockTypeModifyPwd == _type) { 207 | 208 | _actionView.hidden = YES; 209 | 210 | [_actionView removeFromSuperview]; 211 | 212 | if(_isDirectModify) return; 213 | 214 | // self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"关闭" style:UIBarButtonItemStylePlain target:self action:@selector(dismiss)]; 215 | } 216 | 217 | if(![self.class hasPwd]){ 218 | [_modifyBtn removeFromSuperview]; 219 | } 220 | } 221 | 222 | - (void)dismiss 223 | { 224 | [self dismiss:0]; 225 | } 226 | 227 | #pragma mark - 密码重设 228 | - (void)setPwdReset 229 | { 230 | [self.label showNormalMsg:CoreLockPWDTitleFirst]; 231 | // 隐藏 232 | self.navigationItem.rightBarButtonItem = nil; 233 | // 通知视图重设 234 | [self.lockView resetPwd]; 235 | } 236 | 237 | #pragma mark - 密码移除 238 | + (void)ba_setPwdRemove 239 | { 240 | // 通知视图重设 241 | [CoreArchive removeStrForKey:CoreLockPWDKey]; 242 | } 243 | 244 | #pragma mark - 忘记密码 245 | - (void)forgetPwd 246 | { 247 | [self dismiss:0]; 248 | 249 | // 此处需要单独处理 250 | // [self setPwdReset]; 251 | if(_forgetPwdBlock != nil) _forgetPwdBlock(self); 252 | 253 | } 254 | 255 | #pragma mark - 修改密码 256 | - (void)modiftyPwd 257 | { 258 | 259 | } 260 | 261 | /* 262 | * 是否有本地密码缓存?即用户是否设置过初始密码? 263 | */ 264 | + (BOOL)hasPwd 265 | { 266 | NSString *pwd = [CoreArchive strForKey:CoreLockPWDKey]; 267 | return pwd !=nil; 268 | } 269 | 270 | #pragma mark - 设置密码控制器 271 | + (instancetype)showSettingLockVCInVC:(UIViewController *)vc 272 | successBlock:(void(^)(CLLockVC *lockVC,NSString *pwd))successBlock 273 | { 274 | CLLockVC *lockVC = [self lockVC:vc type:CoreLockTypeSetPwd]; 275 | lockVC.title = @"设置手势密码"; 276 | 277 | //设置类型 278 | lockVC.type = CoreLockTypeSetPwd; 279 | //保存block 280 | lockVC.successBlock = successBlock; 281 | return lockVC; 282 | } 283 | 284 | #pragma mark - 验证密码输入框 285 | + (instancetype)showVerifyLockVCInVC:(UIViewController *)vc 286 | forgetPwdBlock:(void(^)())forgetPwdBlock 287 | successBlock:(void(^)(CLLockVC *lockVC, NSString *pwd))successBlock 288 | { 289 | CLLockVC *lockVC = [self lockVC:vc type:CoreLockTypeVeryfiPwd]; 290 | lockVC.title = @"手势解锁"; 291 | 292 | //设置类型 293 | lockVC.type = CoreLockTypeVeryfiPwd; 294 | 295 | //保存block 296 | lockVC.successBlock = successBlock; 297 | lockVC.forgetPwdBlock = forgetPwdBlock; 298 | 299 | return lockVC; 300 | } 301 | 302 | /* 303 | * 展示修改密码输入框 304 | */ 305 | + (instancetype)showModifyLockVCInVC:(UIViewController *)vc 306 | successBlock:(void(^)(CLLockVC *lockVC, NSString *pwd))successBlock 307 | { 308 | CLLockVC *lockVC = [self lockVC:vc type:CoreLockTypeModifyPwd]; 309 | lockVC.title = @"修改手势密码"; 310 | //设置类型 311 | lockVC.type = CoreLockTypeModifyPwd; 312 | //记录 313 | lockVC.successBlock = successBlock; 314 | 315 | return lockVC; 316 | } 317 | 318 | + (instancetype)lockVC:(UIViewController *)vc type:(CoreLockType)type 319 | { 320 | CLLockVC *lockVC = [[CLLockVC alloc] init]; 321 | lockVC.vc = vc; 322 | 323 | // if (type == CoreLockTypeVeryfiPwd) 324 | // { 325 | // CLLockNavVC *navVC = [[CLLockNavVC alloc] initWithRootViewController:lockVC]; 326 | // [vc presentViewController:navVC animated:YES completion:nil]; 327 | // } 328 | // else 329 | // { 330 | [vc.navigationController pushViewController:lockVC animated:YES]; 331 | // } 332 | return lockVC; 333 | } 334 | 335 | - (void)setType:(CoreLockType)type 336 | { 337 | _type = type; 338 | 339 | //根据type自动调整label文字 340 | [self labelWithType]; 341 | } 342 | 343 | /* 344 | * 根据type自动调整label文字 345 | */ 346 | - (void)labelWithType 347 | { 348 | if(CoreLockTypeSetPwd == _type){//设置密码 349 | self.msg = CoreLockPWDTitleFirst; 350 | }else if (CoreLockTypeVeryfiPwd == _type){//验证密码 351 | self.msg = CoreLockVerifyNormalTitle; 352 | }else if (CoreLockTypeModifyPwd == _type){//修改密码 353 | self.msg = CoreLockModifyNormalTitle; 354 | } 355 | } 356 | 357 | /* 358 | * 消失 359 | */ 360 | - (void)dismiss:(NSTimeInterval)interval 361 | { 362 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(interval * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 363 | // [self dismissViewControllerAnimated:YES completion:nil]; 364 | [self.navigationController popViewControllerAnimated:YES]; 365 | }); 366 | } 367 | 368 | /* 369 | * 重置 370 | */ 371 | - (UIBarButtonItem *)resetItem 372 | { 373 | if(_resetItem == nil) 374 | { 375 | //添加右按钮 376 | _resetItem= [[UIBarButtonItem alloc] initWithTitle:@"重设" style:UIBarButtonItemStylePlain target:self action:@selector(setPwdReset)]; 377 | } 378 | 379 | return _resetItem; 380 | } 381 | 382 | - (IBAction)forgetPwdAction:(id)sender 383 | { 384 | [self forgetPwd]; 385 | } 386 | 387 | - (IBAction)modifyPwdAction:(id)sender 388 | { 389 | CLLockVC *lockVC = [[CLLockVC alloc] init]; 390 | 391 | lockVC.title = @"修改密码"; 392 | 393 | lockVC.isDirectModify = YES; 394 | 395 | //设置类型 396 | lockVC.type = CoreLockTypeModifyPwd; 397 | 398 | [self.navigationController pushViewController:lockVC animated:YES]; 399 | } 400 | 401 | @end 402 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/CLLockVC.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/FrameWork/CoreArchive/Category/NSString+File.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+File.h 3 | // CoreCategory 4 | // 5 | // Created by 成林 on 15/4/6. 6 | // Copyright (c) 2015年 沐汐. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | 13 | @interface NSString (File) 14 | 15 | 16 | /* 17 | * document根文件夹 18 | */ 19 | +(NSString *)documentFolder; 20 | 21 | 22 | /* 23 | * caches根文件夹 24 | */ 25 | +(NSString *)cachesFolder; 26 | 27 | 28 | 29 | 30 | /** 31 | * 生成子文件夹 32 | * 33 | * 如果子文件夹不存在,则直接创建;如果已经存在,则直接返回 34 | * 35 | * @param subFolder 子文件夹名 36 | * 37 | * @return 文件夹路径 38 | */ 39 | -(NSString *)createSubFolder:(NSString *)subFolder; 40 | 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/FrameWork/CoreArchive/Category/NSString+File.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+File.m 3 | // CoreCategory 4 | // 5 | // Created by 成林 on 15/4/6. 6 | // Copyright (c) 2015年 沐汐. All rights reserved. 7 | // 8 | 9 | #import "NSString+File.h" 10 | 11 | @implementation NSString (File) 12 | 13 | /* 14 | * document根文件夹 15 | */ 16 | +(NSString *)documentFolder{ 17 | 18 | return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]; 19 | } 20 | 21 | 22 | 23 | /* 24 | * caches根文件夹 25 | */ 26 | +(NSString *)cachesFolder{ 27 | 28 | return [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; 29 | } 30 | 31 | 32 | 33 | 34 | 35 | /** 36 | * 生成子文件夹 37 | * 38 | * 如果子文件夹不存在,则直接创建;如果已经存在,则直接返回 39 | * 40 | * @param subFolder 子文件夹名 41 | * 42 | * @return 文件夹路径 43 | */ 44 | -(NSString *)createSubFolder:(NSString *)subFolder{ 45 | 46 | NSString *subFolderPath=[NSString stringWithFormat:@"%@/%@",self,subFolder]; 47 | 48 | BOOL isDir = NO; 49 | 50 | NSFileManager *fileManager = [NSFileManager defaultManager]; 51 | 52 | BOOL existed = [fileManager fileExistsAtPath:subFolderPath isDirectory:&isDir]; 53 | 54 | if ( !(isDir == YES && existed == YES) ) 55 | { 56 | [fileManager createDirectoryAtPath:subFolderPath withIntermediateDirectories:YES attributes:nil error:nil]; 57 | } 58 | 59 | return subFolderPath; 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/FrameWork/CoreArchive/CoreArchive.h: -------------------------------------------------------------------------------- 1 | // 2 | // ToolArc.h 3 | // 私人通讯录 4 | // 5 | // Created by muxi on 14-9-3. 6 | // Copyright (c) 2014年 muxi. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "NSString+File.h" 12 | 13 | 14 | @interface CoreArchive : NSObject 15 | 16 | #pragma mark - 偏好类信息存储 17 | 18 | /** 19 | * 保存普通字符串 20 | */ 21 | +(void)setStr:(NSString *)str key:(NSString *)key; 22 | 23 | /** 24 | * 读取 25 | */ 26 | +(NSString *)strForKey:(NSString *)key; 27 | 28 | /** 29 | * 删除 30 | */ 31 | +(void)removeStrForKey:(NSString *)key; 32 | 33 | 34 | /** 35 | * 保存int 36 | */ 37 | +(void)setInt:(NSInteger)i key:(NSString *)key; 38 | 39 | /** 40 | * 读取int 41 | */ 42 | +(NSInteger)intForKey:(NSString *)key; 43 | 44 | 45 | 46 | /** 47 | * 保存float 48 | */ 49 | +(void)setFloat:(CGFloat)floatValue key:(NSString *)key; 50 | 51 | /** 52 | * 读取float 53 | */ 54 | +(CGFloat)floatForKey:(NSString *)key; 55 | 56 | 57 | 58 | /** 59 | * 保存bool 60 | */ 61 | +(void)setBool:(BOOL)boolValue key:(NSString *)key; 62 | 63 | /** 64 | * 读取bool 65 | */ 66 | +(BOOL)boolForKey:(NSString *)key; 67 | 68 | 69 | #pragma mark - 文件归档 70 | 71 | /** 72 | * 归档 73 | */ 74 | +(BOOL)archiveRootObject:(id)obj toFile:(NSString *)path; 75 | /** 76 | * 删除 77 | */ 78 | +(BOOL)removeRootObjectWithFile:(NSString *)path; 79 | 80 | /** 81 | * 解档 82 | */ 83 | +(id)unarchiveObjectWithFile:(NSString *)path; 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/FrameWork/CoreArchive/CoreArchive.m: -------------------------------------------------------------------------------- 1 | // 2 | // ToolArc.m 3 | // 私人通讯录 4 | // 5 | // Created by muxi on 14-9-3. 6 | // Copyright (c) 2014年 muxi. All rights reserved. 7 | // 8 | 9 | #import "CoreArchive.h" 10 | 11 | @implementation CoreArchive 12 | 13 | #pragma mark - 偏好类信息存储 14 | //保存普通对象 15 | +(void)setStr:(NSString *)str key:(NSString *)key{ 16 | 17 | //获取preference 18 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 19 | 20 | //保存 21 | [defaults setObject:str forKey:key]; 22 | 23 | //立即同步 24 | [defaults synchronize]; 25 | 26 | } 27 | 28 | //读取 29 | +(NSString *)strForKey:(NSString *)key{ 30 | 31 | //获取preference 32 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 33 | 34 | //读取 35 | NSString *str=(NSString *)[defaults objectForKey:key]; 36 | 37 | return str; 38 | 39 | } 40 | 41 | //删除 42 | +(void)removeStrForKey:(NSString *)key{ 43 | 44 | [self setStr:nil key:key]; 45 | 46 | } 47 | 48 | //保存int 49 | +(void)setInt:(NSInteger)i key:(NSString *)key{ 50 | //获取preference 51 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 52 | 53 | //保存 54 | [defaults setInteger:i forKey:key]; 55 | 56 | //立即同步 57 | [defaults synchronize]; 58 | 59 | } 60 | 61 | //读取 62 | +(NSInteger)intForKey:(NSString *)key{ 63 | //获取preference 64 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 65 | 66 | //读取 67 | NSInteger i=[defaults integerForKey:key]; 68 | 69 | return i; 70 | } 71 | 72 | //保存float 73 | +(void)setFloat:(CGFloat)floatValue key:(NSString *)key{ 74 | 75 | //获取preference 76 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 77 | 78 | //保存 79 | [defaults setFloat:floatValue forKey:key]; 80 | 81 | //立即同步 82 | [defaults synchronize]; 83 | 84 | } 85 | //读取 86 | +(CGFloat)floatForKey:(NSString *)key{ 87 | //获取preference 88 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 89 | 90 | //读取 91 | CGFloat floatValue=[defaults floatForKey:key]; 92 | 93 | return floatValue; 94 | } 95 | 96 | 97 | //保存bool 98 | +(void)setBool:(BOOL)boolValue key:(NSString *)key{ 99 | //获取preference 100 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 101 | 102 | //保存 103 | [defaults setBool:boolValue forKey:key]; 104 | 105 | //立即同步 106 | [defaults synchronize]; 107 | 108 | } 109 | //读取 110 | +(BOOL)boolForKey:(NSString *)key{ 111 | //获取preference 112 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 113 | 114 | //读取 115 | BOOL boolValue=[defaults boolForKey:key]; 116 | 117 | return boolValue; 118 | } 119 | 120 | 121 | 122 | 123 | #pragma mark - 文件归档 124 | //归档 125 | +(BOOL)archiveRootObject:(id)obj toFile:(NSString *)path{ 126 | return [NSKeyedArchiver archiveRootObject:obj toFile:path]; 127 | } 128 | //删除 129 | +(BOOL)removeRootObjectWithFile:(NSString *)path{ 130 | return [self archiveRootObject:nil toFile:path]; 131 | } 132 | //解档 133 | +(id)unarchiveObjectWithFile:(NSString *)path{ 134 | return [NSKeyedUnarchiver unarchiveObjectWithFile:path]; 135 | } 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | @end 145 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/FrameWork/CoreExtend/CoreConst.h: -------------------------------------------------------------------------------- 1 | //全局通用常量定义,结尾请不要使用;号 2 | 3 | 4 | //ios系统版本 5 | #define ios8x [[[UIDevice currentDevice] systemVersion] floatValue] >=8.0f 6 | #define ios7x ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f) && ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0f) 7 | #define ios6x [[[UIDevice currentDevice] systemVersion] floatValue] < 7.0f 8 | #define iosNot6x [[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0f 9 | 10 | 11 | #define iphone4x_3_5 ([UIScreen mainScreen].bounds.size.height==480.0f) 12 | 13 | #define iphone5x_4_0 ([UIScreen mainScreen].bounds.size.height==568.0f) 14 | 15 | #define iphone6_4_7 ([UIScreen mainScreen].bounds.size.height==667.0f) 16 | 17 | #define iphone6Plus_5_5 ([UIScreen mainScreen].bounds.size.height==736.0f || [UIScreen mainScreen].bounds.size.height==414.0f) 18 | 19 | //屏幕宽高 20 | #define kScreenW [[UIScreen mainScreen] bounds].size.width 21 | #define kScreenH [[UIScreen mainScreen] bounds].size.height 22 | 23 | //屏幕frame,bounds,size 24 | #define kScreenFrame [UIScreen mainScreen].bounds 25 | #define kScreenBounds [UIScreen mainScreen].bounds 26 | #define kScreenSize [UIScreen mainScreen].bounds.size 27 | 28 | 29 | 30 | #define rgb(r,g,b) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:1.0f] 31 | #define rgba(r,g,b,a) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a] 32 | #define hexColor(colorV) [UIColor colorWithHexColorString:@#colorV] 33 | #define hexColorAlpha(colorV,a) [UIColor colorWithHexColorString:@#colorV alpha:a]; 34 | 35 | 36 | #define StringFromInteger(i) [NSString stringWithFormat:@"%@",@(i)] 37 | 38 | 39 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/Category/CALayer+Anim.h: -------------------------------------------------------------------------------- 1 | // 2 | // CALayer+Anim.h 3 | // CoreLock 4 | // 5 | // Created by 冯成林 on 15/4/28. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CALayer (Anim) 12 | 13 | 14 | 15 | /* 16 | * 摇动 17 | */ 18 | -(void)shake; 19 | 20 | 21 | 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/Category/CALayer+Anim.m: -------------------------------------------------------------------------------- 1 | // 2 | // CALayer+Anim.m 3 | // CoreLock 4 | // 5 | // Created by 冯成林 on 15/4/28. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import "CALayer+Anim.h" 10 | 11 | @implementation CALayer (Anim) 12 | 13 | 14 | /* 15 | * 摇动 16 | */ 17 | -(void)shake{ 18 | 19 | CAKeyframeAnimation *kfa = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"]; 20 | 21 | CGFloat s = 16; 22 | 23 | kfa.values = @[@(-s),@(0),@(s),@(0),@(-s),@(0),@(s),@(0)]; 24 | 25 | //时长 26 | kfa.duration = .1f; 27 | 28 | //重复 29 | kfa.repeatCount =2; 30 | 31 | //移除 32 | kfa.removedOnCompletion = YES; 33 | 34 | [self addAnimation:kfa forKey:@"shake"]; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/Const/CoreLockConst.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreLockConst.h 3 | // CoreLock 4 | // 5 | // Created by 成林 on 15/4/24. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | 13 | #ifndef _CoreLockConst_H_ 14 | #define _CoreLockConst_H_ 15 | 16 | 17 | #define rgba(r,g,b,a) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a] 18 | 19 | 20 | /* 21 | * 背景色 22 | */ 23 | //#define CoreLockViewBgColor rgba(13,52,89,1) 24 | #define CoreLockViewBgColor [UIColor whiteColor] 25 | 26 | /* 27 | * 外环线条颜色:默认 28 | */ 29 | //#define CoreLockCircleLineNormalColor rgba(241,241,241,1) 30 | #define CoreLockCircleLineNormalColor rgba(0, 204, 255, 1) 31 | 32 | 33 | /* 34 | * 外环线条颜色:选中 35 | */ 36 | #define CoreLockCircleLineSelectedColor rgba(34,178,246,1) 37 | 38 | 39 | /* 40 | * 实心圆 41 | */ 42 | #define CoreLockCircleLineSelectedCircleColor rgba(34,178,246,1) 43 | 44 | 45 | /* 46 | * 实心圆 47 | */ 48 | #define CoreLockLockLineColor rgba(34,178,246,1) 49 | 50 | 51 | 52 | /* 53 | * 警示文字颜色 54 | */ 55 | #define CoreLockWarnColor rgba(254,82,92,1) 56 | 57 | 58 | 59 | /** 选中圆大小比例 */ 60 | extern const CGFloat CoreLockArcWHR; 61 | 62 | 63 | 64 | /** 选中圆大小的线宽 */ 65 | extern const CGFloat CoreLockArcLineW; 66 | 67 | 68 | /** 密码存储Key */ 69 | extern NSString *const CoreLockPWDKey; 70 | 71 | 72 | /** 最低设置密码数目 */ 73 | extern const NSUInteger CoreLockMinItemCount; 74 | 75 | 76 | 77 | /* 78 | * 设置密码 79 | */ 80 | 81 | /** 设置密码提示文字:第一次 */ 82 | extern NSString *const CoreLockPWDTitleFirst; 83 | 84 | 85 | /** 设置密码提示文字:确认 */ 86 | extern NSString *const CoreLockPWDTitleConfirm; 87 | 88 | 89 | /** 设置密码提示文字:再次密码不一致 */ 90 | extern NSString *const CoreLockPWDDiffTitle; 91 | 92 | 93 | /** 设置密码提示文字:设置成功 */ 94 | extern NSString *const CoreLockPWSuccessTitle; 95 | 96 | 97 | 98 | /* 99 | * 验证密码 100 | */ 101 | 102 | /** 验证密码:普通提示文字 */ 103 | extern NSString *const CoreLockVerifyNormalTitle; 104 | 105 | 106 | /** 验证密码:密码错误 */ 107 | extern NSString *const CoreLockVerifyErrorPwdTitle; 108 | 109 | 110 | 111 | /** 验证密码:验证成功 */ 112 | extern NSString *const CoreLockVerifySuccesslTitle; 113 | 114 | 115 | 116 | /* 117 | * 修改密码 118 | */ 119 | /** 修改密码:普通提示文字 */ 120 | extern NSString *const CoreLockModifyNormalTitle; 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/Const/CoreLockConst.m: -------------------------------------------------------------------------------- 1 | // 2 | // CoreLockConst.m 3 | // CoreLock 4 | // 5 | // Created by 成林 on 15/4/24. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #ifndef _CoreLockConst_H_ 10 | #define _CoreLockConst_H_ 11 | 12 | #import 13 | 14 | /** 选中圆大小比例 */ 15 | const CGFloat CoreLockArcWHR = .3f; 16 | 17 | 18 | /** 选中圆大小的线宽 */ 19 | const CGFloat CoreLockArcLineW = 1.0f; 20 | 21 | 22 | /** 密码存储Key */ 23 | NSString *const CoreLockPWDKey = @"CoreLockPWDKey"; 24 | 25 | 26 | /* 27 | * 设置密码 28 | */ 29 | 30 | 31 | /** 最低设置密码数目 */ 32 | const NSUInteger CoreLockMinItemCount = 4; 33 | 34 | 35 | /** 设置密码提示文字 */ 36 | NSString *const CoreLockPWDTitleFirst = @"请滑动设置新密码"; 37 | 38 | 39 | 40 | /** 设置密码提示文字:确认 */ 41 | NSString *const CoreLockPWDTitleConfirm = @"请再次输入确认密码"; 42 | 43 | 44 | /** 设置密码提示文字:再次密码不一致 */ 45 | NSString *const CoreLockPWDDiffTitle = @"再次密码输入不一致"; 46 | 47 | /** 设置密码提示文字:设置成功 */ 48 | NSString *const CoreLockPWSuccessTitle = @"密码设置成功!"; 49 | 50 | 51 | /* 52 | * 验证密码 53 | */ 54 | 55 | /** 验证密码:普通提示文字 */ 56 | NSString *const CoreLockVerifyNormalTitle = @"请滑动输入密码"; 57 | 58 | 59 | /** 验证密码:密码错误 */ 60 | NSString *const CoreLockVerifyErrorPwdTitle = @"输入密码错误"; 61 | 62 | 63 | /** 验证密码:验证成功 */ 64 | NSString *const CoreLockVerifySuccesslTitle = @"密码正确"; 65 | 66 | 67 | /* 68 | * 修改密码 69 | */ 70 | /** 修改密码:普通提示文字 */ 71 | NSString *const CoreLockModifyNormalTitle = @"请输入旧密码"; 72 | 73 | 74 | 75 | 76 | #endif -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/Controller/CLLockNavVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // CLLockNavVC.h 3 | // CoreLock 4 | // 5 | // Created by 成林 on 15/4/28. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CLLockNavVC : UINavigationController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/Controller/CLLockNavVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // CLLockNavVC.m 3 | // CoreLock 4 | // 5 | // Created by 成林 on 15/4/28. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import "CLLockNavVC.h" 10 | 11 | @interface CLLockNavVC () 12 | 13 | @end 14 | 15 | @implementation CLLockNavVC 16 | 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | 21 | // [self.navigationBar setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor whiteColor],NSFontAttributeName:[UIFont systemFontOfSize:20]}]; 22 | 23 | // [self.navigationBar setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault]; 24 | 25 | //tintColor 26 | self.navigationBar.tintColor = [UIColor blackColor]; 27 | } 28 | 29 | 30 | //-(UIStatusBarStyle)preferredStatusBarStyle{ 31 | // return UIStatusBarStyleLightContent; 32 | //} 33 | 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/View/CLLockInfoView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CLLockInfoView.h 3 | // CoreLock 4 | // 5 | // Created by 成林 on 15/4/27. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 仅仅是做展示用 8 | 9 | #import 10 | 11 | @interface CLLockInfoView : UIView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/View/CLLockInfoView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CLLockInfoView.m 3 | // CoreLock 4 | // 5 | // Created by 成林 on 15/4/27. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import "CLLockInfoView.h" 10 | #import "CoreLockConst.h" 11 | 12 | 13 | 14 | 15 | 16 | @implementation CLLockInfoView 17 | 18 | 19 | -(void)drawRect:(CGRect)rect{ 20 | 21 | //获取上下文 22 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 23 | 24 | //设置属性 25 | CGContextSetLineWidth(ctx, CoreLockArcLineW); 26 | 27 | //设置线条颜色 28 | [CoreLockCircleLineNormalColor set]; 29 | 30 | //新建路径 31 | CGMutablePathRef pathM =CGPathCreateMutable(); 32 | 33 | CGFloat marginV = 3.f; 34 | CGFloat padding = 1.0f; 35 | CGFloat rectWH = (rect.size.width - marginV * 2 - padding*2) / 3; 36 | 37 | //添加圆形路径 38 | for (NSUInteger i=0; i<9; i++) { 39 | 40 | NSUInteger row = i % 3; 41 | NSUInteger col = i / 3; 42 | 43 | CGFloat rectX = (rectWH + marginV) * row + padding; 44 | 45 | CGFloat rectY = (rectWH + marginV) * col + padding; 46 | 47 | CGRect rect = CGRectMake(rectX, rectY, rectWH, rectWH); 48 | 49 | CGPathAddEllipseInRect(pathM, NULL, rect); 50 | } 51 | 52 | //添加路径 53 | CGContextAddPath(ctx, pathM); 54 | 55 | //绘制路径 56 | CGContextStrokePath(ctx); 57 | 58 | //释放路径 59 | CGPathRelease(pathM); 60 | } 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/View/CLLockItemView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CLLockItemView.h 3 | // CoreLock 4 | // 5 | // Created by 成林 on 15/4/21. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | typedef enum { 13 | 14 | //正上 15 | LockItemViewDirecTop=1, 16 | 17 | //右上 18 | LockItemViewDirecRightTop, 19 | 20 | //右 21 | LockItemViewDirecRight, 22 | 23 | //右下 24 | LockItemViewDiretRightBottom, 25 | 26 | //下 27 | LockItemViewDirecBottom, 28 | 29 | //左下 30 | LockItemViewDirecLeftBottom, 31 | 32 | //左 33 | LockItemViewDirecLeft, 34 | 35 | //左上 36 | LockItemViewDirecLeftTop, 37 | 38 | }LockItemViewDirect; 39 | 40 | 41 | 42 | 43 | @interface CLLockItemView : UIView 44 | 45 | 46 | 47 | 48 | /** 是否选中 */ 49 | @property (nonatomic,assign) BOOL selected; 50 | 51 | 52 | 53 | /** 方向 */ 54 | @property (nonatomic,assign) LockItemViewDirect direct; 55 | 56 | 57 | 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/View/CLLockItemView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CLLockItemView.m 3 | // CoreLock 4 | // 5 | // Created by 成林 on 15/4/21. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import "CLLockItemView.h" 10 | #import "CoreLockConst.h" 11 | 12 | @interface CLLockItemView () 13 | 14 | /** 圆环rect */ 15 | @property (nonatomic,assign) CGRect calRect; 16 | 17 | /** 选中的rect */ 18 | @property (nonatomic,assign) CGRect selectedRect; 19 | 20 | /** 角度 */ 21 | @property (nonatomic,assign) CGFloat angle; 22 | 23 | @end 24 | 25 | 26 | @implementation CLLockItemView 27 | 28 | -(instancetype)initWithFrame:(CGRect)frame{ 29 | 30 | self = [super initWithFrame:frame]; 31 | 32 | if(self){ 33 | 34 | self.backgroundColor = [UIColor clearColor]; 35 | } 36 | 37 | return self; 38 | } 39 | 40 | 41 | 42 | -(void)drawRect:(CGRect)rect{ 43 | 44 | //获取上下文 45 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 46 | 47 | //上下文旋转 48 | [self transFormCtx:ctx rect:rect]; 49 | 50 | //上下文属性设置 51 | [self propertySetting:ctx]; 52 | 53 | //外环:普通 54 | [self circleNormal:ctx rect:rect]; 55 | 56 | //选中情况下,绘制背景色 57 | if(_selected){ 58 | 59 | //外环:选中 60 | [self circleSelected:ctx rect:rect]; 61 | 62 | //三角形:方向标识 63 | [self directFlag:ctx rect:rect]; 64 | } 65 | 66 | 67 | } 68 | 69 | 70 | /* 71 | * 上下文旋转 72 | */ 73 | -(void)transFormCtx:(CGContextRef)ctx rect:(CGRect)rect{ 74 | 75 | if(self.direct == 0) return; 76 | 77 | CGFloat translateXY = rect.size.width * .5f; 78 | 79 | //平移 80 | CGContextTranslateCTM(ctx, translateXY, translateXY); 81 | 82 | CGContextRotateCTM(ctx, self.angle); 83 | 84 | //再平移回来 85 | CGContextTranslateCTM(ctx, -translateXY, -translateXY); 86 | } 87 | 88 | 89 | 90 | /* 91 | * 三角形:方向标识 92 | */ 93 | -(void)directFlag:(CGContextRef)ctx rect:(CGRect)rect{ 94 | 95 | if(self.direct == 0) return; 96 | 97 | //新建路径:三角形 98 | CGMutablePathRef trianglePathM = CGPathCreateMutable(); 99 | 100 | CGFloat marginSelectedCirclev = 4.0f; 101 | CGFloat w =8.0f; 102 | CGFloat h =5.0f; 103 | CGFloat topX = rect.origin.x + rect.size.width * .5f; 104 | CGFloat topY = rect.origin.y +(rect.size.width *.5f - h - marginSelectedCirclev - self.selectedRect.size.height *.5f); 105 | 106 | CGPathMoveToPoint(trianglePathM, NULL, topX, topY); 107 | 108 | //添加左边点 109 | CGFloat leftPointX = topX - w *.5f; 110 | CGFloat leftPointY =topY + h; 111 | CGPathAddLineToPoint(trianglePathM, NULL, leftPointX, leftPointY); 112 | 113 | //右边的点 114 | CGFloat rightPointX = topX + w *.5f; 115 | CGPathAddLineToPoint(trianglePathM, NULL, rightPointX, leftPointY); 116 | 117 | //将路径添加到上下文中 118 | CGContextAddPath(ctx, trianglePathM); 119 | 120 | //绘制圆环 121 | CGContextFillPath(ctx); 122 | 123 | //释放路径 124 | CGPathRelease(trianglePathM); 125 | } 126 | 127 | 128 | 129 | 130 | /* 131 | * 上下文属性设置 132 | */ 133 | -(void)propertySetting:(CGContextRef)ctx{ 134 | 135 | //设置线宽 136 | CGContextSetLineWidth(ctx, CoreLockArcLineW); 137 | 138 | //设置颜色 139 | UIColor *color = nil; 140 | if(_selected){ 141 | 142 | color = CoreLockCircleLineSelectedColor; 143 | }else{ 144 | color = CoreLockCircleLineNormalColor; 145 | } 146 | [color set]; 147 | } 148 | 149 | 150 | 151 | /* 152 | * 外环:普通 153 | */ 154 | -(void)circleNormal:(CGContextRef)ctx rect:(CGRect)rect{ 155 | 156 | //新建路径:外环 157 | CGMutablePathRef loopPath = CGPathCreateMutable(); 158 | 159 | //添加一个圆环路径 160 | CGRect calRect = self.calRect; 161 | CGPathAddEllipseInRect(loopPath, NULL, calRect); 162 | 163 | //将路径添加到上下文中 164 | CGContextAddPath(ctx, loopPath); 165 | 166 | //绘制圆环 167 | CGContextStrokePath(ctx); 168 | 169 | //释放路径 170 | CGPathRelease(loopPath); 171 | } 172 | 173 | 174 | /* 175 | * 外环:选中 176 | */ 177 | -(void)circleSelected:(CGContextRef)ctx rect:(CGRect)rect{ 178 | 179 | //新建路径:外环 180 | CGMutablePathRef circlePath = CGPathCreateMutable(); 181 | 182 | //绘制一个圆形 183 | CGPathAddEllipseInRect(circlePath, NULL, self.selectedRect); 184 | 185 | [CoreLockCircleLineSelectedCircleColor set]; 186 | 187 | //将路径添加到上下文中 188 | CGContextAddPath(ctx, circlePath); 189 | 190 | //绘制圆环 191 | CGContextFillPath(ctx); 192 | 193 | //释放路径 194 | CGPathRelease(circlePath); 195 | } 196 | 197 | 198 | 199 | 200 | 201 | 202 | -(void)setSelected:(BOOL)selected{ 203 | 204 | _selected = selected; 205 | 206 | [self setNeedsDisplay]; 207 | } 208 | 209 | 210 | -(CGRect)calRect{ 211 | 212 | if(CGRectEqualToRect(_calRect, CGRectZero)){ 213 | 214 | CGFloat lineW =CoreLockArcLineW; 215 | 216 | CGFloat sizeWH = self.bounds.size.width - lineW; 217 | CGFloat originXY = lineW *.5f; 218 | 219 | //添加一个圆环路径 220 | _calRect = (CGRect){CGPointMake(originXY, originXY),CGSizeMake(sizeWH, sizeWH)}; 221 | 222 | } 223 | 224 | return _calRect; 225 | } 226 | 227 | 228 | 229 | -(CGRect)selectedRect{ 230 | 231 | if(CGRectEqualToRect(_selectedRect, CGRectZero)){ 232 | 233 | CGRect rect = self.bounds; 234 | 235 | CGFloat selectRectWH = rect.size.width * CoreLockArcWHR; 236 | 237 | CGFloat selectRectXY = rect.size.width * (1 - CoreLockArcWHR) *.5f; 238 | 239 | _selectedRect = CGRectMake(selectRectXY, selectRectXY, selectRectWH, selectRectWH); 240 | } 241 | 242 | return _selectedRect; 243 | } 244 | 245 | -(void)setDirect:(LockItemViewDirect)direct{ 246 | 247 | _direct = direct; 248 | 249 | self.angle = M_PI_4 * (direct -1); 250 | 251 | [self setNeedsDisplay]; 252 | } 253 | 254 | 255 | @end 256 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/View/CLLockLabel.h: -------------------------------------------------------------------------------- 1 | // 2 | // CLLockLabel.h 3 | // CoreLock 4 | // 5 | // Created by 成林 on 15/4/27. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CLLockLabel : UILabel 12 | 13 | 14 | 15 | /* 16 | * 普通提示信息 17 | */ 18 | -(void)showNormalMsg:(NSString *)msg; 19 | 20 | 21 | 22 | /* 23 | * 警示信息 24 | */ 25 | -(void)showWarnMsg:(NSString *)msg; 26 | 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/View/CLLockLabel.m: -------------------------------------------------------------------------------- 1 | // 2 | // CLLockLabel.m 3 | // CoreLock 4 | // 5 | // Created by 成林 on 15/4/27. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import "CLLockLabel.h" 10 | #import "CoreLockConst.h" 11 | #import "CALayer+Anim.h" 12 | 13 | 14 | 15 | @implementation CLLockLabel 16 | 17 | 18 | 19 | 20 | -(instancetype)initWithFrame:(CGRect)frame{ 21 | 22 | self = [super initWithFrame:frame]; 23 | 24 | if(self){ 25 | 26 | //视图初始化 27 | [self viewPrepare]; 28 | } 29 | 30 | return self; 31 | } 32 | 33 | 34 | 35 | -(id)initWithCoder:(NSCoder *)aDecoder{ 36 | 37 | self=[super initWithCoder:aDecoder]; 38 | 39 | if(self){ 40 | 41 | //视图初始化 42 | [self viewPrepare]; 43 | } 44 | 45 | return self; 46 | } 47 | 48 | 49 | /* 50 | * 视图初始化 51 | */ 52 | -(void)viewPrepare{ 53 | 54 | self.font = [UIFont systemFontOfSize:16.0f]; 55 | } 56 | 57 | 58 | 59 | 60 | 61 | /* 62 | * 普通提示信息 63 | */ 64 | -(void)showNormalMsg:(NSString *)msg{ 65 | 66 | self.text = msg; 67 | self.textColor = CoreLockCircleLineNormalColor; 68 | } 69 | 70 | 71 | 72 | /* 73 | * 警示信息 74 | */ 75 | -(void)showWarnMsg:(NSString *)msg{ 76 | 77 | self.text = msg; 78 | self.textColor = CoreLockWarnColor; 79 | 80 | //添加一个shake动画 81 | [self.layer shake]; 82 | } 83 | 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/View/CLLockMainView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CLLockMainView.h 3 | // CoreLock 4 | // 5 | // Created by 冯成林 on 15/4/28. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CLLockMainView : UIView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/View/CLLockMainView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CLLockMainView.m 3 | // CoreLock 4 | // 5 | // Created by 冯成林 on 15/4/28. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import "CLLockMainView.h" 10 | #import "CoreConst.h" 11 | 12 | 13 | @interface CLLockMainView () 14 | 15 | @property (weak, nonatomic) IBOutlet NSLayoutConstraint *topC; 16 | 17 | 18 | @property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomMarginC; 19 | 20 | 21 | @property (weak, nonatomic) IBOutlet NSLayoutConstraint *infoViewTopMoveC; 22 | 23 | @property (weak, nonatomic) IBOutlet NSLayoutConstraint *labelTopMarginC; 24 | 25 | 26 | @property (weak, nonatomic) IBOutlet UIButton *forgetBtn; 27 | 28 | 29 | @property (weak, nonatomic) IBOutlet UIButton *modifyBtn; 30 | 31 | 32 | 33 | @end 34 | 35 | 36 | 37 | @implementation CLLockMainView 38 | 39 | 40 | -(void)awakeFromNib{ 41 | 42 | [super awakeFromNib]; 43 | 44 | if(iphone4x_3_5){ 45 | 46 | _topC.constant =30; 47 | 48 | _bottomMarginC.constant = -30; 49 | 50 | _infoViewTopMoveC.constant = -10; 51 | 52 | _labelTopMarginC.constant = 10; 53 | } 54 | } 55 | 56 | 57 | 58 | -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ 59 | 60 | if(iphone4x_3_5){ 61 | 62 | CGRect forgetFrame = [_forgetBtn convertRect:_forgetBtn.bounds toView:self]; 63 | 64 | CGRect modifyFrame = [_modifyBtn convertRect:_modifyBtn.bounds toView:self]; 65 | 66 | if(CGRectContainsPoint(forgetFrame, point)) return _forgetBtn; 67 | if(CGRectContainsPoint(modifyFrame, point)) return _modifyBtn; 68 | } 69 | 70 | return [super hitTest:point withEvent:event]; 71 | } 72 | 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/View/CLLockView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CLLockView.h 3 | // CoreLock 4 | // 5 | // Created by 成林 on 15/4/21. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CLLockVC.h" 11 | 12 | @interface CLLockView : UIView 13 | 14 | @property (nonatomic,assign) CoreLockType type; 15 | 16 | 17 | 18 | /* 19 | * 设置密码 20 | */ 21 | 22 | /** 开始输入,第一次 */ 23 | @property (nonatomic,copy) void (^setPWBeginBlock)(); 24 | 25 | /** 开始输入,确认密码*/ 26 | @property (nonatomic,copy) void (^setPWConfirmlock)(); 27 | 28 | 29 | /** 设置密码出错:长度不够 */ 30 | @property (nonatomic,copy) void (^setPWSErrorLengthTooShortBlock)(NSUInteger currentCount); 31 | 32 | 33 | /** 设置密码出错:再次密码不一致 */ 34 | @property (nonatomic,copy) void (^setPWSErrorTwiceDiffBlock)(NSString *pwd1,NSString *pwdNow); 35 | 36 | 37 | /** 设置密码:第一次输入正确*/ 38 | @property (nonatomic,copy) void (^setPWFirstRightBlock)(); 39 | 40 | 41 | /** 再次密码输入一致 */ 42 | @property (nonatomic,copy) void (^setPWTwiceSameBlock)(NSString *pwd); 43 | 44 | 45 | /* 46 | * 重设密码 47 | */ 48 | -(void)resetPwd; 49 | 50 | 51 | /* 52 | * 验证密码 53 | */ 54 | 55 | /** 验证密码开始*/ 56 | @property (nonatomic,copy) void (^verifyPWBeginBlock)(); 57 | 58 | /** 验证密码 */ 59 | @property (nonatomic,copy) BOOL (^verifyPwdBlock)(NSString *pwd); 60 | 61 | 62 | /* 63 | * 修改密码 64 | */ 65 | /** 再次密码输入一致 */ 66 | @property (nonatomic,copy) void (^modifyPwdBlock)(); 67 | 68 | 69 | /** 密码修改成功 */ 70 | @property (nonatomic,copy) void (^modifyPwdSuccessBlock)(); 71 | 72 | 73 | 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /BATouchID/Lib/手势解锁/CoreLock/Lib/View/CLLockView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CLLockView.m 3 | // CoreLock 4 | // 5 | // Created by 成林 on 15/4/21. 6 | // Copyright (c) 2015年 冯成林. All rights reserved. 7 | // 8 | 9 | #import "CLLockView.h" 10 | #import "CLLockItemView.h" 11 | #import "CoreLockConst.h" 12 | 13 | 14 | const CGFloat marginValue = 36.0f; 15 | 16 | 17 | @interface CLLockView () 18 | 19 | /** 装itemView的可变数组*/ 20 | @property (nonatomic,strong) NSMutableArray *itemViewsM; 21 | 22 | 23 | /** 临时密码记录器 */ 24 | @property (nonatomic,copy) NSMutableString *pwdM; 25 | 26 | 27 | /** 设置密码:第一次设置的正确的密码 */ 28 | @property (nonatomic,copy) NSString *firstRightPWD; 29 | 30 | 31 | /** 修改密码过程中的验证旧密码正确 */ 32 | @property (nonatomic,assign) BOOL modify_VeriryOldRight; 33 | 34 | 35 | 36 | 37 | @end 38 | 39 | 40 | 41 | @implementation CLLockView 42 | 43 | 44 | -(id)initWithCoder:(NSCoder *)aDecoder{ 45 | 46 | self=[super initWithCoder:aDecoder]; 47 | 48 | if(self){ 49 | 50 | //解锁视图准备 51 | [self lockViewPrepare]; 52 | } 53 | 54 | return self; 55 | } 56 | 57 | 58 | 59 | -(instancetype)initWithFrame:(CGRect)frame{ 60 | 61 | self = [super initWithFrame:frame]; 62 | 63 | if(self){ 64 | 65 | //解锁视图准备 66 | [self lockViewPrepare]; 67 | } 68 | 69 | return self; 70 | } 71 | 72 | 73 | /* 74 | * 绘制线条 75 | */ 76 | -(void)drawRect:(CGRect)rect{ 77 | 78 | //数组为空直接返回 79 | if(_itemViewsM == nil || _itemViewsM.count == 0) return; 80 | 81 | //获取上下文 82 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 83 | 84 | //添加路径 85 | CGContextAddRect(ctx, rect); 86 | 87 | //添加圆形路径 88 | //遍历所有的itemView 89 | [_itemViewsM enumerateObjectsUsingBlock:^(CLLockItemView *itemView, NSUInteger idx, BOOL *stop) { 90 | 91 | CGContextAddEllipseInRect(ctx, itemView.frame); 92 | }]; 93 | 94 | //剪裁 95 | CGContextEOClip(ctx); 96 | 97 | //新建路径:管理线条 98 | CGMutablePathRef pathM = CGPathCreateMutable(); 99 | 100 | //设置上下文属性 101 | //1.设置线条颜色 102 | [CoreLockLockLineColor set]; 103 | 104 | //线条转角样式 105 | CGContextSetLineCap(ctx, kCGLineCapRound); 106 | CGContextSetLineJoin(ctx, kCGLineJoinRound); 107 | 108 | //设置线宽 109 | CGContextSetLineWidth(ctx, 1.0f); 110 | 111 | //遍历所有的itemView 112 | [_itemViewsM enumerateObjectsUsingBlock:^(CLLockItemView *itemView, NSUInteger idx, BOOL *stop) { 113 | 114 | CGPoint directPoint = itemView.center; 115 | 116 | if(idx == 0){//第一个 117 | 118 | //添加起点 119 | CGPathMoveToPoint(pathM, NULL, directPoint.x, directPoint.y); 120 | 121 | }else{//其他 122 | 123 | //添加路径线条 124 | CGPathAddLineToPoint(pathM, NULL, directPoint.x, directPoint.y); 125 | } 126 | }]; 127 | 128 | //将路径添加到上下文 129 | CGContextAddPath(ctx, pathM); 130 | 131 | //渲染路径 132 | CGContextStrokePath(ctx); 133 | 134 | //释放路径 135 | CGPathRelease(pathM); 136 | } 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | /* 147 | * 解锁视图准备 148 | */ 149 | -(void)lockViewPrepare{ 150 | 151 | for (NSUInteger i=0; i<9; i++) { 152 | 153 | CLLockItemView *itemView = [[CLLockItemView alloc] init]; 154 | 155 | [self addSubview:itemView]; 156 | } 157 | } 158 | 159 | 160 | -(void)layoutSubviews{ 161 | 162 | [super layoutSubviews]; 163 | 164 | CGFloat itemViewWH = (self.frame.size.width - 4 * marginValue) /3.0f; 165 | 166 | [self.subviews enumerateObjectsUsingBlock:^(UIView *subview, NSUInteger idx, BOOL *stop) { 167 | 168 | NSUInteger row = idx % 3; 169 | 170 | NSUInteger col = idx / 3; 171 | 172 | CGFloat x = marginValue * (row +1) + row * itemViewWH; 173 | 174 | CGFloat y =marginValue * (col +1) + col * itemViewWH; 175 | 176 | CGRect frame = CGRectMake(x, y, itemViewWH, itemViewWH); 177 | 178 | //设置tag 179 | subview.tag = idx; 180 | 181 | subview.frame = frame; 182 | }]; 183 | 184 | } 185 | 186 | 187 | 188 | 189 | 190 | -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 191 | 192 | //解锁处理 193 | [self lockHandle:touches]; 194 | 195 | 196 | if(CoreLockTypeSetPwd == _type){ // 设置密码 197 | //开始 198 | if(self.firstRightPWD == nil){//第一次输入 199 | 200 | if(_setPWBeginBlock != nil) _setPWBeginBlock(); 201 | 202 | }else{//确认 203 | 204 | if(_setPWConfirmlock != nil) _setPWConfirmlock(); 205 | } 206 | }else if(CoreLockTypeVeryfiPwd == _type){//验证密码 207 | 208 | //开始 209 | if(_verifyPWBeginBlock != nil) _verifyPWBeginBlock(); 210 | 211 | }else if (CoreLockTypeModifyPwd == _type){ 212 | 213 | //开始 214 | if(_modifyPwdBlock != nil) _modifyPwdBlock(); 215 | } 216 | } 217 | 218 | 219 | -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ 220 | 221 | //解锁处理 222 | [self lockHandle:touches]; 223 | } 224 | 225 | 226 | 227 | -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ 228 | 229 | //手势结束 230 | [self gestureEnd]; 231 | } 232 | 233 | 234 | -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{ 235 | 236 | //手势结束 237 | [self gestureEnd]; 238 | } 239 | 240 | 241 | /* 242 | * 手势结束 243 | */ 244 | -(void)gestureEnd{ 245 | 246 | 247 | //设置密码检查 248 | if(self.pwdM.length != 0){ 249 | [self setpwdCheck]; 250 | } 251 | 252 | 253 | for (CLLockItemView *itemView in self.itemViewsM) { 254 | 255 | itemView.selected = NO; 256 | 257 | //清空方向 258 | itemView.direct = 0; 259 | } 260 | 261 | //清空数组所有对象 262 | [self.itemViewsM removeAllObjects]; 263 | 264 | //再绘制 265 | [self setNeedsDisplay]; 266 | 267 | //清空密码 268 | self.pwdM = nil; 269 | 270 | } 271 | 272 | 273 | 274 | /* 275 | * 设置密码检查 276 | */ 277 | -(void)setpwdCheck{ 278 | 279 | NSUInteger count = self.itemViewsM.count; 280 | 281 | if(count < CoreLockMinItemCount){ 282 | if(_setPWSErrorLengthTooShortBlock != nil) _setPWSErrorLengthTooShortBlock(count); 283 | return; 284 | } 285 | 286 | if(CoreLockTypeSetPwd == _type){//设置密码 287 | 288 | //设置密码 289 | [self setpwd]; 290 | 291 | }else if(CoreLockTypeVeryfiPwd == _type){//验证密码 292 | 293 | if(_verifyPwdBlock != nil) _verifyPwdBlock(self.pwdM); 294 | 295 | }else if (CoreLockTypeModifyPwd == _type){//修改密码 296 | 297 | if(!_modify_VeriryOldRight){ 298 | 299 | if(_verifyPwdBlock != nil){ 300 | _modify_VeriryOldRight = _verifyPwdBlock(self.pwdM); 301 | } 302 | 303 | }else{ 304 | 305 | //设置密码 306 | [self setpwd]; 307 | } 308 | } 309 | 310 | } 311 | 312 | 313 | 314 | 315 | /* 316 | * 设置密码 317 | */ 318 | -(void)setpwd{ 319 | 320 | //密码合法 321 | if(self.firstRightPWD == nil){// 第一次设置密码 322 | self.firstRightPWD = self.pwdM; 323 | if(_setPWFirstRightBlock != nil) _setPWFirstRightBlock(); 324 | }else{ 325 | 326 | if(![self.firstRightPWD isEqualToString:self.pwdM]){//两次密码不一致 327 | 328 | if(_setPWSErrorTwiceDiffBlock != nil) _setPWSErrorTwiceDiffBlock(self.firstRightPWD,self.pwdM); 329 | return; 330 | 331 | }else{//再次密码输入一致 332 | 333 | if(_setPWTwiceSameBlock != nil) _setPWTwiceSameBlock(self.firstRightPWD); 334 | } 335 | } 336 | 337 | } 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | /* 350 | * 解锁处理 351 | */ 352 | -(void)lockHandle:(NSSet *)touches{ 353 | 354 | //取出触摸点 355 | UITouch *touch = [touches anyObject]; 356 | 357 | CGPoint loc = [touch locationInView:self]; 358 | 359 | CLLockItemView *itemView = [self itemViewWithTouchLocation:loc]; 360 | 361 | //如果为空,返回 362 | if(itemView ==nil) return; 363 | 364 | //如果已经存在,返回 365 | if([self.itemViewsM containsObject:itemView]) return; 366 | 367 | //添加 368 | [self.itemViewsM addObject:itemView]; 369 | 370 | //记录密码 371 | [self.pwdM appendFormat:@"%@",@(itemView.tag)]; 372 | 373 | 374 | //计算方向:每添加一次itemView就计算一次 375 | [self calDirect]; 376 | 377 | //item处理 378 | [self itemHandel:itemView]; 379 | } 380 | 381 | 382 | 383 | /* 384 | * 计算方向:每添加一次itemView就计算一次 385 | */ 386 | -(void)calDirect{ 387 | 388 | NSUInteger count = _itemViewsM.count; 389 | 390 | if(_itemViewsM==nil || count<=1) return; 391 | 392 | //取出最后一个对象 393 | CLLockItemView *last_1_ItemView = _itemViewsM.lastObject; 394 | 395 | //倒数第二个 396 | CLLockItemView *last_2_ItemView =_itemViewsM[count -2]; 397 | 398 | //计算倒数第二个的位置 399 | CGFloat last_1_x = last_1_ItemView.frame.origin.x; 400 | CGFloat last_1_y = last_1_ItemView.frame.origin.y; 401 | CGFloat last_2_x = last_2_ItemView.frame.origin.x; 402 | CGFloat last_2_y = last_2_ItemView.frame.origin.y; 403 | 404 | //倒数第一个itemView相对倒数第二个itemView来说 405 | //正上 406 | if(last_2_x == last_1_x && last_2_y > last_1_y) { 407 | last_2_ItemView.direct = LockItemViewDirecTop; 408 | } 409 | 410 | //正左 411 | if(last_2_y == last_1_y && last_2_x > last_1_x) { 412 | last_2_ItemView.direct = LockItemViewDirecLeft; 413 | } 414 | 415 | //正下 416 | if(last_2_x == last_1_x && last_2_y < last_1_y) { 417 | last_2_ItemView.direct = LockItemViewDirecBottom; 418 | } 419 | 420 | //正右 421 | if(last_2_y == last_1_y && last_2_x < last_1_x) { 422 | last_2_ItemView.direct = LockItemViewDirecRight; 423 | } 424 | 425 | //左上 426 | if(last_2_x > last_1_x && last_2_y > last_1_y) { 427 | last_2_ItemView.direct = LockItemViewDirecLeftTop; 428 | } 429 | 430 | //右上 431 | if(last_2_x < last_1_x && last_2_y > last_1_y) { 432 | last_2_ItemView.direct = LockItemViewDirecRightTop; 433 | } 434 | 435 | //左下 436 | if(last_2_x > last_1_x && last_2_y < last_1_y) { 437 | last_2_ItemView.direct = LockItemViewDirecLeftBottom; 438 | } 439 | 440 | //右下 441 | if(last_2_x < last_1_x && last_2_y < last_1_y) { 442 | last_2_ItemView.direct = LockItemViewDiretRightBottom; 443 | } 444 | 445 | } 446 | 447 | /* 448 | * item处理 449 | */ 450 | -(void)itemHandel:(CLLockItemView *)itemView{ 451 | 452 | //选中 453 | itemView.selected = YES; 454 | 455 | //绘制 456 | [self setNeedsDisplay]; 457 | } 458 | 459 | - (CLLockItemView *)itemViewWithTouchLocation:(CGPoint)loc{ 460 | 461 | CLLockItemView *itemView = nil; 462 | 463 | for (CLLockItemView *itemViewSub in self.subviews) { 464 | 465 | if(!CGRectContainsPoint(itemViewSub.frame, loc)) continue; 466 | itemView = itemViewSub; 467 | break; 468 | } 469 | return itemView; 470 | } 471 | 472 | /* 473 | * 重设密码 474 | */ 475 | -(void)resetPwd{ 476 | 477 | //清空第一次密码即可 478 | self.firstRightPWD = nil; 479 | } 480 | 481 | - (NSMutableArray *)itemViewsM{ 482 | 483 | if(_itemViewsM == nil){ 484 | 485 | _itemViewsM = [NSMutableArray array]; 486 | } 487 | 488 | return _itemViewsM; 489 | } 490 | 491 | - (NSMutableString *)pwdM{ 492 | 493 | if(_pwdM == nil){ 494 | 495 | _pwdM = [NSMutableString string]; 496 | } 497 | 498 | return _pwdM; 499 | } 500 | 501 | @end 502 | -------------------------------------------------------------------------------- /BATouchID/LoginViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LoginViewController.h 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/25. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LoginViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /BATouchID/LoginViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LoginViewController.m 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/25. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import "LoginViewController.h" 10 | 11 | #import "BATouchIDLoginVC.h" 12 | #import "NSString+BAKit.h" 13 | #import 14 | #import "BATouchID.h" 15 | 16 | #import "SettingVC.h" 17 | 18 | @interface LoginViewController () 19 | @property (weak, nonatomic) IBOutlet UIButton *loginButton; 20 | 21 | - (IBAction)handleButtonAction:(UIButton *)sender; 22 | 23 | @end 24 | 25 | @implementation LoginViewController 26 | 27 | - (void)viewWillAppear:(BOOL)animated 28 | { 29 | [super viewWillAppear:animated]; 30 | 31 | } 32 | 33 | - (void)viewDidLoad { 34 | [super viewDidLoad]; 35 | 36 | [self setupUI]; 37 | } 38 | 39 | - (void)setupUI 40 | { 41 | [self checkIsAlreadyOpenTouchID]; 42 | 43 | self.title = @"登 录"; 44 | 45 | } 46 | 47 | - (void)checkIsAlreadyOpenTouchID 48 | { 49 | id isLogin = [kUserDefaults objectForKey:kIsLogin]; 50 | id isOpenTouchID = [kUserDefaults objectForKey:kIsOpenTouchID]; 51 | 52 | if ([isLogin intValue] == 1) 53 | { 54 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"设置" style:UIBarButtonItemStylePlain target:self action:@selector(handleNaviAction)]; 55 | 56 | [self.loginButton setTitle:@"已登录" forState:UIControlStateNormal]; 57 | 58 | if ([isOpenTouchID intValue] == 1) 59 | { 60 | UINavigationController *navi = [[UINavigationController alloc] initWithRootViewController:[BATouchIDLoginVC new]]; 61 | [self presentViewController:navi animated:YES completion:nil]; 62 | } 63 | } 64 | } 65 | 66 | - (void)handleNaviAction 67 | { 68 | [self.navigationController pushViewController:[SettingVC new] animated:YES]; 69 | } 70 | 71 | - (IBAction)handleButtonAction:(UIButton *)sender 72 | { 73 | NSUserDefaults *defaults = kUserDefaults; 74 | id isLogin = [defaults objectForKey:kIsLogin]; 75 | if ([isLogin intValue] == 0) 76 | { 77 | [kUserDefaults setObject:[NSNumber numberWithBool:YES] forKey:kIsLogin]; 78 | BAKit_ShowAlertWithMsg_ios8(@"登录成功!"); 79 | [self.loginButton setTitle:@"已登录" forState:UIControlStateNormal]; 80 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 81 | [self checkIsSupportTouchID]; 82 | }); 83 | } 84 | else 85 | { 86 | BAKit_ShowAlertWithMsg_ios8(@"您已经登录过!"); 87 | } 88 | } 89 | 90 | - (void)checkIsSupportTouchID 91 | { 92 | [UIAlertController ba_alertControllerShowAlertInViewController:self withTitle:@"登录成功!" mutableAttributedTitle:nil message:@"是否设置指纹登录或者手势登录?" mutableAttributedMessage:nil buttonTitlesArray:@[@"取 消", @"确 定"] buttonTitleColorArray:@[[UIColor greenColor], [UIColor redColor]] tapBlock:^(UIAlertController * _Nonnull controller, UIAlertAction * _Nonnull action, NSInteger buttonIndex) { 93 | 94 | if (buttonIndex == 1) 95 | { 96 | [self.navigationController pushViewController:[SettingVC new] animated:YES]; 97 | } 98 | else 99 | { 100 | return ; 101 | } 102 | 103 | return; 104 | }]; 105 | } 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /BATouchID/LoginViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /BATouchID/SettingVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // SettingVC.h 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/26. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SettingVC : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /BATouchID/SettingVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // SettingVC.m 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/26. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import "SettingVC.h" 10 | #import "BATouchID.h" 11 | 12 | #import "BATouchIDLoginVC.h" 13 | #import "BAUnlockedGestureVC.h" 14 | 15 | static NSString * const kCellID = @"SettingVCCell"; 16 | 17 | @interface SettingVC () 18 | 19 | @property (weak, nonatomic) IBOutlet UITableView *tableView; 20 | @property(nonatomic, strong) NSArray *dataArray; 21 | 22 | @end 23 | 24 | @implementation SettingVC 25 | 26 | - (void)viewWillAppear:(BOOL)animated { 27 | [super viewWillAppear:animated]; 28 | // 手势密码打开之后, 指纹密码失效, 应该在手势设置页面 pop 回当前页的时候刷新一下, 让指纹登录的开关关掉. 29 | [self.tableView reloadData]; 30 | } 31 | 32 | - (void)viewDidLoad { 33 | [super viewDidLoad]; 34 | // Do any additional setup after loading the view from its nib. 35 | 36 | [self setupUI]; 37 | } 38 | 39 | - (void)setupUI 40 | { 41 | self.title = @"安全设置"; 42 | self.tableView.tableFooterView = [UIView new]; 43 | 44 | } 45 | 46 | #pragma mark - UITableViewDelegate, UITableViewDataSource 47 | 48 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 49 | { 50 | return self.dataArray.count; 51 | } 52 | 53 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 54 | { 55 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kCellID]; 56 | 57 | if (!cell) 58 | { 59 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kCellID]; 60 | } 61 | if (indexPath.row == 0) 62 | { 63 | UISwitch *switcher; 64 | 65 | id switcher1On = [kUserDefaults objectForKey:kIsOpenTouchID]; 66 | 67 | if ([cell.accessoryView isKindOfClass:[UISwitch class]]) 68 | { 69 | switcher = (UISwitch *)cell.accessoryView; 70 | } 71 | else 72 | { 73 | switcher = [[UISwitch alloc] init]; 74 | } 75 | switcher.tag = indexPath.row; 76 | switcher.on = ([switcher1On intValue] == 1) ? YES : NO; 77 | 78 | [switcher removeTarget:nil action:NULL forControlEvents:UIControlEventAllEvents]; 79 | [switcher addTarget:self action:@selector(handleSwichAction:) forControlEvents:UIControlEventValueChanged]; 80 | cell.accessoryView = switcher; 81 | } 82 | 83 | cell.textLabel.text = self.dataArray[indexPath.row]; 84 | 85 | return cell; 86 | } 87 | 88 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 89 | { 90 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 91 | 92 | if (indexPath.row == 1) 93 | { 94 | [self.navigationController pushViewController:[BAUnlockedGestureVC new] animated:YES]; 95 | } 96 | } 97 | 98 | #pragma mark - custom method 99 | - (void)handleSwichAction:(UISwitch *)sender 100 | { 101 | id isLogin = [kUserDefaults objectForKey:kIsLogin]; 102 | if ([isLogin intValue] == 0) 103 | { 104 | NSString *msg = @"请您先登录后再开启指纹登录!"; 105 | BAKit_ShowAlertWithMsg_ios8(msg); 106 | sender.on = NO; 107 | } 108 | else 109 | { 110 | if (sender.tag == 0) 111 | { 112 | // 开启和关闭指纹解锁的弹框信息区分开 113 | NSString *msg = sender.isOn ? @"继续开启指纹解锁\n将关闭手势解锁" : @"关闭指纹解锁?"; 114 | [UIAlertController ba_alertControllerShowAlertInViewController:self withTitle:nil mutableAttributedTitle:nil message:msg mutableAttributedMessage:nil buttonTitlesArray:@[@"取 消", @"继 续"] buttonTitleColorArray:@[[UIColor greenColor], [UIColor redColor]] tapBlock:^(UIAlertController * _Nonnull controller, UIAlertAction * _Nonnull action, NSInteger buttonIndex) { 115 | 116 | if (buttonIndex == 1) 117 | { 118 | [kUserDefaults removeObjectForKey:kIsOpenUnlockedGesture]; 119 | [kUserDefaults setObject:[NSNumber numberWithBool:NO] forKey:kIsOpenUnlockedGesture]; 120 | 121 | [kUserDefaults removeObjectForKey:kIsOpenTouchID]; 122 | if (sender.on) 123 | { 124 | [self checkIsSupportTouchID]; 125 | } 126 | else 127 | { 128 | [kUserDefaults setObject:[NSNumber numberWithBool:NO] forKey:kIsOpenTouchID]; 129 | sender.on = NO; 130 | } 131 | } 132 | else // 弹框的取消按钮点击之后, 开关状态不应改变, 把状态切换回去. 133 | { 134 | sender.on = !sender.isOn; 135 | } 136 | return; 137 | }]; 138 | } 139 | } 140 | } 141 | 142 | - (void)checkIsSupportTouchID 143 | { 144 | [BAKit_TouchID ba_touchIDVerifyIsSupportWithBlock:^(BOOL isSupport, LAContext *context, NSInteger policy, NSError *error) { 145 | if (isSupport) 146 | { 147 | id isShow = [kUserDefaults objectForKey:kIsOpenTouchID]; 148 | if ([isShow intValue] == 0) 149 | { 150 | [kUserDefaults setObject:[NSNumber numberWithBool:YES] forKey:kIsOpenTouchID]; 151 | [self presentViewController:[BATouchIDLoginVC new] animated:YES completion:nil]; 152 | } 153 | } 154 | else 155 | { 156 | BAKit_ShowAlertWithMsg_ios8(@"设备不支持 touch ID!"); 157 | } 158 | }]; 159 | } 160 | 161 | #pragma mark - setter / getter 162 | 163 | - (NSArray *)dataArray 164 | { 165 | if (!_dataArray) 166 | { 167 | _dataArray = @[@"指纹登录", @"手势登录"]; 168 | } 169 | return _dataArray; 170 | } 171 | 172 | 173 | @end 174 | -------------------------------------------------------------------------------- /BATouchID/SettingVC.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /BATouchID/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/24. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /BATouchID/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/24. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | 11 | #import "BATouchIDLoginVC.h" 12 | #import "LoginViewController.h" 13 | 14 | #import "BAButton.h" 15 | 16 | @interface ViewController () 17 | 18 | @property(nonatomic, strong) UIButton *loginButton; 19 | 20 | @end 21 | 22 | @implementation ViewController 23 | 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | // Do any additional setup after loading the view, typically from a nib. 27 | 28 | [self setupUI]; 29 | } 30 | 31 | - (void)setupUI 32 | { 33 | self.title = @"首页"; 34 | self.view.backgroundColor = [UIColor whiteColor]; 35 | self.loginButton.hidden = NO; 36 | 37 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"登录界面" style:UIBarButtonItemStylePlain target:self action:@selector(handleNaviAction)]; 38 | } 39 | 40 | - (void)handleNaviAction 41 | { 42 | [self.navigationController pushViewController:[LoginViewController new] animated:YES]; 43 | } 44 | 45 | - (void)handleButtonAction:(UIButton *)sender 46 | { 47 | 48 | } 49 | 50 | - (void)viewDidLayoutSubviews 51 | { 52 | [super viewDidLayoutSubviews]; 53 | 54 | _loginButton.frame = CGRectMake(0, 0, 200, 200); 55 | _loginButton.center = self.view.center; 56 | } 57 | 58 | - (UIButton *)loginButton 59 | { 60 | if (!_loginButton) 61 | { 62 | _loginButton = [UIButton buttonWithType:UIButtonTypeCustom]; 63 | [_loginButton setTitle:@"这里是首页!" forState:UIControlStateNormal]; 64 | [_loginButton setTitleColor:[UIColor colorWithRed:0 green:152/255.0 blue:229/255.0 alpha:1.0f] forState:UIControlStateNormal]; 65 | [_loginButton setImage:[UIImage imageNamed:@"tabbar_mainframeHL"] forState:UIControlStateNormal]; 66 | 67 | [_loginButton addTarget:self action:@selector(handleButtonAction:) forControlEvents:UIControlEventTouchDown]; 68 | [self.view addSubview:_loginButton]; 69 | 70 | [_loginButton ba_button_setBAButtonLayoutType:BAButtonLayoutTypeCenterImageTop padding:10]; 71 | } 72 | return _loginButton; 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /BATouchID/icon1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BAHome/BATouchID/a3280aa457c48c152b635996de24d594b9ecce46/BATouchID/icon1.jpg -------------------------------------------------------------------------------- /BATouchID/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // BATouchID 4 | // 5 | // Created by boai on 2017/5/24. 6 | // Copyright © 2017年 boai. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /BATouchID/美女.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BAHome/BATouchID/a3280aa457c48c152b635996de24d594b9ecce46/BATouchID/美女.jpg -------------------------------------------------------------------------------- /Images/BATouchID.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BAHome/BATouchID/a3280aa457c48c152b635996de24d594b9ecce46/Images/BATouchID.png -------------------------------------------------------------------------------- /Images/支付宝指纹登录流程图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BAHome/BATouchID/a3280aa457c48c152b635996de24d594b9ecce46/Images/支付宝指纹登录流程图.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 BAHome 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BATouchID 2 | [![BAHome Team Name](https://img.shields.io/badge/Team-BAHome-brightgreen.svg?style=flat)](https://github.com/BAHome "BAHome Team") 3 | ![](https://img.shields.io/badge/platform-iOS-red.svg) ![](https://img.shields.io/badge/language-Objective--C-orange.svg) 4 | ![](https://img.shields.io/badge/license-MIT%20License-brightgreen.svg) 5 | ![](https://img.shields.io/cocoapods/v/BATouchID.svg?style=flat) ![](https://img.shields.io/cocoapods/dt/BATouchID.svg 6 | ) [![](https://img.shields.io/badge/微博-博爱1616-red.svg)](http://weibo.com/538298123) 7 | 8 | ## 1、功能及简介 9 | * 1、支付宝 指纹登录 touchID 封装
10 | * 2、可以自定义 描述文字、取消按钮、第二个按钮等、详细的错误状态返回 11 | * 3、demo 中增加了支付宝指纹登录逻辑,详见 demo 12 | * 4、进入后台 10秒 后再次打开APP 会自动判断指纹登录,详见 demo 13 | * 5、本地存储开启指纹登录开关,会自动判断指纹登录,详见 demo 14 | * 6、本地密码登录后自动判断是否支持指纹登录,会自动判断指纹登录,详见 demo 15 | * 7、新增 单独判断是否支持指纹识别的方法
16 | * 8、demo 新增手势密码设置、验证、修改、重置等方法
17 | * 9、demo 新增手势密码和指纹识别的逻辑处理,具体使用中可参照demo 中的逻辑处理方式
18 | 19 | 20 | ## 2、图片示例 21 | ![支付宝指纹登录流程图](https://github.com/BAHome/BATouchID/blob/master/Images/支付宝指纹登录流程图.png) 22 | 23 | ## 3、安装、导入示例和源码地址 24 | * 1、pod 导入【最新版本:version 1.0.1】:
25 | `pod 'BATouchID'`
26 | 如果发现 `pod search BATouchID` 搜索出来的不是最新版本,需要在终端执行 cd 转换文件路径命令退回到 desktop,然后执行 `pod setup` 命令更新本地spec缓存(可能需要几分钟),然后再搜索就可以了。
27 | 具体步骤: 28 | - pod setup : 初始化 29 | - pod repo update : 更新仓库 30 | - pod search BATouchID 31 | * 2、文件夹拖入:下载demo,把 BATouchID 文件夹拖入项目即可,
32 | * 3、导入头文件:
33 | ` #import "BATouchID.h" `
34 | * 4、项目源码地址:
35 | OC 版 :[https://github.com/BAHome/BATouchID](https://github.com/BAHome/BATouchID)
36 | 37 | ## 4、BATouchID 的类结构及 demo 示例 38 | ![BATouchID](https://github.com/BAHome/BATouchID/blob/master/Images/BATouchID.png) 39 | 40 | ### BATouchID.h 41 | ``` 42 | #ifndef BATouchID_h 43 | #define BATouchID_h 44 | 45 | #import "UIButton+BAKit.h" 46 | 47 | /*! 48 | ********************************************************************************* 49 | ************************************ 更新说明 ************************************ 50 | ********************************************************************************* 51 | 52 | 欢迎使用 BAHome 系列开源代码 ! 53 | 如有更多需求,请前往:https://github.com/BAHome 54 | 55 | #ifndef BATouchID_h 56 | #define BATouchID_h 57 | 58 | #import "BAKit_TouchID.h" 59 | #import "BAKit_DeviceModel.h" 60 | 61 | /*! view 用 BAKit_ShowAlertWithMsg */ 62 | #define BAKit_ShowAlertWithMsg(msg) [[[UIAlertView alloc] initWithTitle:@"温馨提示" message:(msg) delegate:nil cancelButtonTitle:@"确 定" otherButtonTitles:nil] show]; 63 | 64 | /*! VC 用 BAKit_ShowAlertWithMsg */ 65 | #define BAKit_ShowAlertWithMsg_ios8(msg) UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"温馨提示" message:msg preferredStyle:UIAlertControllerStyleAlert];\ 66 | UIAlertAction *sureAction = [UIAlertAction actionWithTitle:@"确 定" style:UIAlertActionStyleDefault handler:nil];\ 67 | [alert addAction:sureAction];\ 68 | [self presentViewController:alert animated:YES completion:nil]; 69 | 70 | /*! 71 | ********************************************************************************* 72 | ************************************ 更新说明 ************************************ 73 | ********************************************************************************* 74 | 75 | 项目源码地址: 76 | OC 版 :https://github.com/BAHome/BATouchID 77 | 78 | 最新更新时间:2017-05-27 【倒叙】
79 | 最新Version:【Version:1.0.1】
80 | 更新内容:
81 | 1.0.1.1、新增 单独判断是否支持指纹识别的方法
82 | 1.0.1.2、demo 新增手势密码设置、验证、修改、重置等方法
83 | 1.0.1.3、demo 新增手势密码和指纹识别的逻辑处理,具体使用中可参照demo 中的逻辑处理方式
84 | 85 | 最新更新时间:2017-05-24 【倒叙】
86 | 最新Version:【Version:1.0.0】
87 | 更新内容:
88 | 1.0.0.1、新增 Touch ID de 详细封装
89 | 1.0.0.2、可以自定义 描述文字、取消按钮、第二个按钮等、详细的错误状态返回
90 | 1.0.0.3、demo 中增加了支付宝指纹登录逻辑,详见 demo 91 | 1.0.0.4、新增获取设备详细信息的封装,详见:BAKit_DeviceModel 92 | 93 | */ 94 | 95 | #endif /* BATouchID_h */ 96 | 97 | ``` 98 | 99 | ### BAKit_TouchID.h 100 | ``` 101 | #import 102 | #import 103 | #import 104 | 105 | 106 | // 操作系统版本号 107 | #define IOS_VERSION ([[[UIDevice currentDevice] systemVersion] floatValue]) 108 | 109 | /** 110 | * TouchID 状态 111 | */ 112 | typedef NS_ENUM(NSUInteger, BAKit_TouchIDType){ 113 | 114 | /** 115 | * 当前设备不支持TouchID 116 | */ 117 | BAKit_TouchIDTypeNotSupport = 0, 118 | /** 119 | * TouchID 验证成功 120 | */ 121 | BAKit_TouchIDTypeSuccess, 122 | /** 123 | * TouchID 验证失败 124 | */ 125 | BAKit_TouchIDTypeFail, 126 | /** 127 | * TouchID 被用户手动取消 128 | */ 129 | BAKit_TouchIDTypeUserCancel, 130 | /** 131 | * 用户不使用TouchID,选择手动输入密码 132 | */ 133 | BAKit_TouchIDTypeInputPassword, 134 | /** 135 | * TouchID 被系统取消 (如遇到来电,锁屏,按了Home键等) 136 | */ 137 | BAKit_TouchIDTypeSystemCancel, 138 | /** 139 | * TouchID 无法启动,因为用户没有设置密码 140 | */ 141 | BAKit_TouchIDTypePasswordNotSet, 142 | /** 143 | * TouchID 无法启动,因为用户没有设置TouchID 144 | */ 145 | BAKit_TouchIDTypeTouchIDNotSet, 146 | /** 147 | * TouchID 无效 148 | */ 149 | BAKit_TouchIDTypeTouchIDNotAvailable, 150 | /** 151 | * TouchID 被锁定(连续多次验证TouchID失败,系统需要用户手动输入密码) 152 | */ 153 | BAKit_TouchIDTypeTouchIDLockout, 154 | /** 155 | * 当前软件被挂起并取消了授权 (如App进入了后台等) 156 | */ 157 | BAKit_TouchIDTypeAppCancel, 158 | /** 159 | * 当前软件被挂起并取消了授权 (LAContext对象无效) 160 | */ 161 | BAKit_TouchIDTypeInvalidContext, 162 | /** 163 | * 系统版本不支持TouchID (必须高于iOS 8.0才能使用) 164 | */ 165 | BAKit_TouchIDTypeVersionNotSupport 166 | }; 167 | 168 | /** 169 | 指纹解锁 回调 170 | 171 | @param touchIDType 返回的类型,BAKit_TouchIDType 172 | @param error error 173 | @param errorMessage errorMessage 174 | */ 175 | typedef void (^BAKit_TouchID_Block)(BAKit_TouchIDType touchIDType, NSError *error, NSString *errorMessage); 176 | 177 | /** 178 | 判断是否支持指纹解锁 回调 179 | 180 | @param isSupport 是否支持 181 | @param context context 182 | @param policy policy 183 | @param error error 184 | */ 185 | typedef void (^BAKit_TouchIDVerifyIsSupport_Block)(BOOL isSupport, LAContext *context, NSInteger policy, NSError *error); 186 | 187 | @interface BAKit_TouchID : NSObject 188 | 189 | /** 190 | 指纹解锁 191 | 192 | @param content 提示文本 193 | @param cancelButtonTitle 取消按钮显示内容(此参数只有iOS10以上才能生效),默认(nil):取消 194 | @param otherButtonTitle 密码登录按钮显示内容,默认(nil):输入密码(nil) 195 | @param enabled 默认:NO,输入密码按钮,使用系统解锁;YES:自己操作点击密码登录 196 | @param BAKit_TouchIDTypeBlock 返回状态码和错误,可以自行单独处理 197 | */ 198 | + (void)ba_touchIDWithContent:(NSString *)content 199 | cancelButtonTitle:(NSString *)cancelButtonTitle 200 | otherButtonTitle:(NSString *)otherButtonTitle 201 | enabled:(BOOL)enabled 202 | BAKit_TouchIDTypeBlock:(BAKit_TouchID_Block)BAKit_TouchIDTypeBlock; 203 | 204 | /** 205 | 判断是否支持指纹解锁 206 | 207 | @param block block 208 | */ 209 | + (void)ba_touchIDVerifyIsSupportWithBlock:(BAKit_TouchIDVerifyIsSupport_Block)block; 210 | 211 | @end 212 | ``` 213 | 214 | ### BAKit_DeviceModel.h 215 | ``` 216 | #import 217 | 218 | @interface BAKit_DeviceModel : NSObject 219 | 220 | /* 221 | 获取设备描述 222 | */ 223 | + (NSString *)ba_deviceGetCurrentDeviceModelDescription; 224 | 225 | /* 226 | 由获取到的设备描述,来匹配设备型号 227 | */ 228 | + (NSString *)ba_deviceGetCurrentDeviceModel; 229 | 230 | @end 231 | ``` 232 | ### demo 示例 233 | ``` 234 | // 示例1:登录验证,是否开启指纹登录 235 | - (void)checkIsSupportTouchID 236 | { 237 | [BAKit_TouchID ba_touchIDVerifyIsSupportWithBlock:^(BOOL isSupport, LAContext *context, NSInteger policy, NSError *error) { 238 | if (isSupport) 239 | { 240 | id isShow = [kUserDefaults objectForKey:kIsOpenTouchID]; 241 | if ([isShow intValue] == 0) 242 | { 243 | [kUserDefaults setObject:[NSNumber numberWithBool:YES] forKey:kIsOpenTouchID]; 244 | [self presentViewController:[BATouchIDLoginVC new] animated:YES completion:nil]; 245 | } 246 | } 247 | else 248 | { 249 | BAKit_ShowAlertWithMsg_ios8(@"设备不支持 touch ID!"); 250 | } 251 | }]; 252 | } 253 | 254 | // 示例2:指纹识别 255 | - (void)test 256 | { 257 | /** 258 | 指纹解锁 259 | 260 | @param content 提示文本 261 | @param cancelButtonTitle 取消按钮显示内容(此参数只有iOS10以上才能生效),默认(nil):取消 262 | @param otherButtonTitle 密码登录按钮显示内容,默认(nil):输入密码(nil) 263 | @param enabled 默认:NO,输入密码按钮,使用系统解锁;YES:自己操作点击密码登录 264 | @param BAKit_TouchIDTypeBlock 返回状态码和错误,可以自行单独处理 265 | */ 266 | [BAKit_TouchID ba_touchIDWithContent:@"此操作需要认证您的身份" cancelButtonTitle:nil otherButtonTitle:nil enabled:YES BAKit_TouchIDTypeBlock:^(BAKit_TouchIDType touchIDType, NSError *error, NSString *errorMessage) { 267 | 268 | if (errorMessage && touchIDType != BAKit_TouchIDTypeTouchIDLockout && touchIDType != BAKit_TouchIDTypeInputPassword) 269 | { 270 | NSString *msg = errorMessage; 271 | BAKit_ShowAlertWithMsg_ios8(msg); 272 | } 273 | 274 | if (touchIDType == BAKit_TouchIDTypeSuccess) 275 | { 276 | BAKit_ShowAlertWithMsg(@"指纹验证成功!"); 277 | [self ba_backToPreVC:nil]; 278 | } 279 | if (touchIDType == BAKit_TouchIDTypeInputPassword) 280 | { 281 | NSLog(@"请跳转到自己的密码登录界面,如:手势解锁等!"); 282 | 283 | dispatch_async(dispatch_get_main_queue(), ^{ 284 | [self ba_verifyPwd]; 285 | }); 286 | } 287 | }]; 288 | } 289 | 290 | 其他示例可下载demo查看源码! 291 | ``` 292 | 293 | ## 5、更新记录:【倒叙】 294 | 欢迎使用 [【BAHome】](https://github.com/BAHome) 系列开源代码 ! 295 | 如有更多需求,请前往:[【https://github.com/BAHome】](https://github.com/BAHome) 296 | 297 | 最新更新时间:2017-05-27 【倒叙】
298 | 最新Version:【Version:1.0.1】
299 | 更新内容:
300 | 1.0.1.1、新增 单独判断是否支持指纹识别的方法
301 | 1.0.1.2、demo 新增手势密码设置、验证、修改、重置等方法
302 | 1.0.1.3、demo 新增手势密码和指纹识别的逻辑处理,具体使用中可参照demo 中的逻辑处理方式
303 | 304 | 最新更新时间:2017-05-24 【倒叙】
305 | 最新Version:【Version:1.0.0】
306 | 更新内容:
307 | 1.0.0.1、新增 Touch ID de 详细封装
308 | 1.0.0.2、可以自定义 描述文字、取消按钮、第二个按钮等、详细的错误状态返回
309 | 1.0.0.3、demo 中增加了支付宝指纹登录逻辑,详见 demo 310 | 1.0.0.4、新增获取设备详细信息的封装,详见:BAKit_DeviceModel 311 | 312 | ## 6、bug 反馈 313 | > 1、开发中遇到 bug,希望小伙伴儿们能够及时反馈与我们 BAHome 团队,我们必定会认真对待每一个问题!
314 | 315 | > 2、以后提需求和 bug 的同学,记得把 git 或者博客链接给我们,我直接超链到你们那里!希望大家积极参与测试!
316 | 317 | ## 7、BAHome 团队成员 318 | > 1、QQ 群 319 | 479663605
320 | 【注意:此群为 2 元 付费群,介意的小伙伴儿勿扰!】
321 | 322 | > 孙博岩
323 | QQ:137361770
324 | git:[https://github.com/boai](https://github.com/boai)
325 | 简书:[http://www.jianshu.com/u/95c9800fdf47](http://www.jianshu.com/u/95c9800fdf47)
326 | 微博:[![](https://img.shields.io/badge/微博-博爱1616-red.svg)](http://weibo.com/538298123)
327 | 328 | > 马景丽
329 | QQ:1253540493
330 | git:[https://github.com/MaJingli](https://github.com/MaJingli)
331 | 332 | > 陆晓峰
333 | QQ:442171865
334 | git:[https://github.com/zeR0Lu](https://github.com/zeR0Lu)
335 | 336 | > 陈集
337 | QQ:3161182978
338 | git:[https://github.com/chenjipdc](https://github.com/chenjipdc)
339 | 简书:[http://www.jianshu.com/u/90ae559fc21d](http://www.jianshu.com/u/90ae559fc21d) 340 | 341 | > 任子丰
342 | QQ:459643690
343 | git:[https://github.com/renzifeng](https://github.com/renzifeng)
344 | 345 | > 吴丰收
346 | QQ:498121294
347 | 348 | > 石少庸
349 | QQ:363605775
350 | git:[https://github.com/CrazyCoderShi](https://github.com/CrazyCoderShi)
351 | 简书:[http://www.jianshu.com/u/0726f4d689a3](http://www.jianshu.com/u/0726f4d689a3) 352 | 353 | ## 8、开发环境 和 支持版本 354 | > 开发使用 最新版本 Xcode,理论上支持 iOS 8 及以上版本,如有版本适配问题,请及时反馈!多谢合作! 355 | 356 | ## 9、感谢 357 | > 感谢 BAHome 团队成员倾力合作,后期会推出一系列 常用 UI 控件的封装,大家有需求得也可以在 issue 提出,如果合理,我们会尽快推出新版本!
358 | 359 | > BAHome 的发展离不开小伙伴儿的信任与推广,再次感谢各位小伙伴儿的支持! 360 | 361 | --------------------------------------------------------------------------------