philm-iOS-wiki
  • 介绍
  • 网络层
    • 说明
  • UI
    • 说明
    • 在ios7以前使用ColorSpace的坑
    • UITableView偏移异常问题
    • drawRect时单独设置文字阴影无效
    • Xcode9下相册访问权限问题
    • 避免同时点击多个Button
    • scroll上的button延迟响应问题
    • uibutton触发边界事件
    • ios 11 上tableview 改动
    • YYImage 显示指定区域的图片
  • 数据持久化
    • 说明
  • 其它
    • 取消延迟执行之坑
    • NSString 转换 float 的精度问题
  • 每周阅读
    • 目录
    • 深入思考NSNotification
    • gitBook使用小助手
    • iOS App签名的原理
    • 响应链
    • iOS10跳转系统到设置页
    • SDWebImage下载高清图内存问题
    • iOS圆角避免离屏渲染
    • 常用的延时调用
    • iOS 神经网络
    • SDWebImage缓存策略
    • 3Dtouch
    • 为什么 Objective-C 对象存储在堆上而不是栈上
    • 深入浅出理解视频编码H264结构
    • CATextLayer学习
    • cocoaPods
    • 任意网站支持RSS
    • Metal简介
    • 动态更改icon
    • CAReplicatorLayer
    • 增加点击间隔
    • 勒索病毒当道的时代
    • iOS常用宏定义
    • Metal实现YUV转RGB渲染视频
    • 获取当前下载的app及下载进度
    • OpenGL ES 三种类型修饰 uniform attribute varying
    • 技术部门引入OKR
    • 基于runloop的线程保活、销毁与通信
    • 深入理解哈希表
    • TOLL-FREE BRIDGING 和 UNMANAGED
    • 开发者能拿到的标识符
    • Swift自定义LOG
    • 系统通知整理
    • iOS 中的 imageIO 与 image 解码
    • CGImageRef基本介绍及方法说明
    • Swift 3.0 语法
    • webview加载部分网页
    • 在CAAnimation中暂停动画
    • 把代码迁移到协调器上
    • ios11API更新整理
    • 非越狱iOS设备的远程控制实现原理
    • 关于本地化
    • swift命名空间
    • CoreML与coremltools体验
    • 力学动画
    • Swift 4官方文档中文版: The Basic(上)
    • swift 中的KVO用法
    • GPUImage的图像形变设计(简单形变部分)
    • iOS响应式架构
    • 移动端图片上传旋转、压缩的解决方案
    • AVFoundation使用指南AVAssert使用
    • 过渡动画
    • 谈谈 MVX 中的 Model
    • AVFoundation编程-AVPlayer使用
    • GPUImage的图像形变设计(复杂形变部分)
    • What's New in LLVM 9
    • ios的事件机制
    • GPUImage源码解读(一)
    • GPUImage源码解读(二)
    • iOS 启动优化
    • 模块化 Swift 中的状态
    • swift中的let和var背后的编程模式
    • Swift Runtime动态性分析
    • RAC下的响应式编程
    • GPUImage源码解读(三)
    • 如何准确判断webView是否加载完成
    • NSObject的+load和+initialize详解
    • ios8以后设置启动图
    • GPUImage源码解读(四)
    • Swift自动闭包
    • IOS11新特性
    • GPUImage源码解读(五)
    • 理解 OC 内部的消息调用、消息转发、类和对象
    • 修饰符
    • IOS 切面统计事件解耦
    • GPUImage源码解读(六)
    • CoreImage介绍
    • 影响Core Animation性能的原因
    • Instruments中的动画工具选项介绍
    • GPUImage源码解读(七)
    • Xcode 7新的特性Lightweight Generics 轻量级泛型与__kindof修饰符
    • GPUImage源码解读(八)
    • Core Image之自定 Filter
    • iOS通用链接
    • 谈nonatomic非线程安全问题
    • 深拷贝与浅拷贝
    • CIKernel 介绍
    • iOS11适配
    • GPUImage源码解读(九)
    • CVPixelBufferCreate使用的坑
    • ios一窥并发底层
    • ARKit进阶:物理世界
    • ARKit的工作原理及流程介绍
    • UI线程卡顿监控
    • FBKVOController使用
    • GPUImage源码解读(十)
    • WKWebView在ios11崩溃问题解决方法
    • 微信iOS SQLite源码优化实践
    • HEIF 和 HEVC 研究
    • 谈谈 iOS 中图片的解压缩
    • 提升 iOS 开发效率! Xcode 9 内置模拟器的9个技巧
    • ObjC和JavaScript的交互,在恰当的时机注入对象
    • iOS数据保护
    • iOS11中网络层的一些变化(Session707&709脱水版)
    • GPUImage源码解读(十一)
    • 一种避免 iOS 内存碎片的方法
    • pods的原理
    • GPUImage源码解读(十二)
    • GPUImage源码解读(十三)
    • iOS 11 Layout的新特性
    • iOS应用瘦身方法思路整理
    • GPUImage源码解读(十四)
    • CAEmitterLayer属性介绍
    • 浅析移动蜂窝网络的特点及其省电方案
    • 如何在 table view 中添加 3D Touch Peek & Pop 功能
    • iOS中锁的介绍与使用
    • NSLog效率低下的原因及尝试lldb断点打印Log
    • GPUImage源码解读(十五)
    • GPUImage源码解读(十六)
    • CADisplayLink
    • GPUImage源码解读(十七)
    • CADisplayLink
    • 老生常谈category增加属性的几种操作
    • 30行代码演示dispatch_once死锁
    • GPUImage源码解读(十八)
    • YYImage设计思路
    • GPUImage源码解读(十九)
    • 深入理解Tagged Pointer
    • iOS 11:WKWebView内容过滤规则详解
    • Swift语法对编译速度的影响
    • GPUImage源码解读(二十)
    • GPUImage源码解读(二十一)
    • iOS App间常用的五种通信方式
    • YYCache深入学习
    • 冲顶大会插件
    • iOS高性能图片架构与设计
    • YUV颜色编码解析
    • iOS传感器:App前后台切换后,获取敏感信息使用touch ID进行校验
    • GPUImage源码解读(二十二)
    • GPUImage源码解读(二十三)
    • 从零开始的机器学习 - Machine Learning(一)
    • 从零开始的机器学习 - Machine Learning(二)
    • GPUImage源码解读(二十四)
    • Objective-C消息转发机制
    • iOS 程序 main 函数之前发生了什么
    • MMKV--基于 mmap 的 iOS 高性能通用 key-value 组件
    • Objective-C 消息发送与转发机制原理
    • 谈Objective-C block的实现
    • GPUImage源码解读(二十五)
    • podfile语法
    • 轻量级低风险 iOS 热更新方案
    • 使用objection来模块化开发iOS项目
    • swift 中delegate的使用注意
    • 使用appledoc自动生成api文档
    • UITextChecker的使用
    • ARKit 如何给SCNNode贴Gif图片
    • Unity与iOS平台交互和原生插件开发
    • SceneKit编程珠玑
Powered by GitBook
On this page
  • 1. 指纹识别传感器的用法介绍
  • 2. Touch ID指纹识别的代码实现
  • 3. 判断系统版本号的几种方法
  • 3.1 系统预留的快速通道 ,推荐使用
  • 3.2 通过UIDevice获取版本号,不推荐
  • 3.3 通过ProcessInfo,判断是否高于指定的版本号
  • 3.4 通过系统给定的Double类型版本号进行判断
  • 4. App从后台到前台,从前台到后台的动作
  • 4.1 App被加载到内存后首次并且唯一次调用的方法
  • 4.2 App已经进入到后台会被调用的方法
  • 4.3 App进入到前台会被调用的方法
  • 5. 距离传感器
  1. 每周阅读

iOS传感器:App前后台切换后,获取敏感信息使用touch ID进行校验

今天咱们要实现的一个案例需求就是:

  1. 使用touch ID进行指纹识别

  2. 指纹识别错误之后,可以使用apple ID的密码进行验证

  3. APP进入到后台,10秒之内切回到前台,不做二次验证。

  4. APP进入到后台,超过10秒切回到前台,再次进行指纹验证。

1. 指纹识别传感器的用法介绍

上面听完介绍,感觉好像屌屌的有没有?很高深,可是iOS封装的已经非常完善了。我们只需要简单的几个步骤就可以利用好手机最下面这个圆圆的指纹传感器了。 苹果在iOS8.0以后开放的TouchID接口,是包含在LocalAuthentication这个框架里面。我们需要引入头文件。 今天本文都是以Swfit为案例,OC的同学可以进行参考。思路一模一样,语法也几乎一模一样。 插一个私信里面的问题,挺具有代表性的。

宅胖你为什么又写Swift又写OC?Swift难吗?

1,我感觉现在会写Swift的同学基本上都是会写OC的。

2,Swift用了之后,当真会觉得OC麻烦很多,各种层面的麻烦。

3,我所写的这些所有的例子里面其实真正用到Swift特性的很少,绝大部分情况下都只是简单翻译了一下OC。

4,Swift难吗?你看到了,基本语法几乎和OC一模一样。只不过OC很多都是NS开头,Swift把它去掉了。

别害怕,快上车。看看排行榜,使用Swift的开发者数量正在稳定的上升。

好,回到今天的主题。使用指纹传感器,一样需要典型的几步:

导入头文件LocalAuthentication 判断版本号,必须在8.0以上 创建LAContext对象,开始验证

好了,就结束了。就这么简单,下面我们就几个重点部分分享一下代码。 然后,敲黑板!!!真正应用开发中中,几乎没人只是验证一下touch ID,就不干别的了。验证识别指纹,肯定是为了下一步的业务流程做服务。 既然是这样,验证的结果肯定直接影响到下一步的业务流程,同时也极大的影响了界面的展示。必然会影响到好几个控制器或者好几个View,极有可能是一对多的关系。 一对多,听上去好耳熟。是不是要暗示点什么?对了。通知,通知,通知,通知。嗯。这个不是这篇文章的重点。别忘记了通知。 因为会影响到好几个控制器或者好几个View,所以,请真心的不要忘记了。

2. Touch ID指纹识别的代码实现

第一步:导入头文件; 第二步:判断系统是否高于iOS 8.0 。下面会单独有一章来介绍四种方法,花样判断。啦啦啦啦啦。 第三步:创建LAContext。这个就是LocalAuthentication暴露出来,让开发者使用的类。 第四步:检查Touch ID是否可用。 不是判断了系统就好了嘛?当然不是啊。还有很多种情况下,Touch ID是不好用的。模拟器不可以使用,被替换了Touch ID,老手机木有这个硬件啦,等等。 第五步:进行识别。 只要识别,就有成功和不成功对不?所以我们还要根据结果进行下一步操作。 成功: 要回到主线程刷新UI,进行成功后的业务流程。 不成功: 根据返回的错误码,分析错误的原因。

因为多线程咱们说好了是下一个系列要分享的内容,所以这次关于线程的地方我就用伪代码替代了。

let laContext = LAContext()

//localizedFallbackTitle:验证TouchID时弹出Alert的输入密码按钮的标题
//ocalizedCancelTitle可以设置验证TouchID时弹出Alert的取消按钮的标题(iOS10才有)
laContext.localizedFallbackTitle = "手气不好,输入密码吧"
laContext.localizedCancelTitle = "点错了,取消取消"

var requestError: NSError? = nil
//        检查Touch ID是否可用
if laContext.canEvaluatePolicy(.deviceOwnerAuthentication, error: &requestError) {
    print("Touch ID可以使用,开始验证")

    laContext.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: "需要验证您的指纹来确认您的身份信息", reply: { (success, error) in

        if success {
            print("Successful,验证成功")
            //回主线程刷新UI
            OperationQueue.main.addOperation {
                self.successToInterface()
            }

        } else {
            print("Sorry,error = \(String(describing: error))")
            if let error1 = (error as NSError?) {
                switch error1.code {
                case LAError.userCancel.rawValue:
                    print("User Cancel")
                case LAError.userFallback.rawValue:
                    print("Wrong touch ID")
                case LAError.systemCancel.rawValue:
                    print("System Cancel")
                default:
                    break;
                }
            }
            self.successView?.removeFromSuperview()
        }
    })
} else {
    print("模拟器上不能使用,或者其他原因导致touchID不可使用");
}

3. 判断系统版本号的几种方法

3.1 系统预留的快速通道 ,推荐使用

if #available(iOS 8.0, *) {
    //系统版本高于8.0
} else {
    //系统版本低于8.0
}

3.2 通过UIDevice获取版本号,不推荐

//        获取当前字符串类型的版本号信息,最不推荐的一种方法
        let sysVersionString = UIDevice.current.systemVersion

3.3 通过ProcessInfo,判断是否高于指定的版本号

//        获取当前系统版本号。majorVersion:主版本号;minorVersion:次版本号;patchVersion:最后一位小版本号
       let systemVersion =  OperatingSystemVersion(majorVersion: 8, minorVersion: 0, patchVersion: 0)

        if ProcessInfo.processInfo.isOperatingSystemAtLeast(systemVersion) {
            //系统版本高于8.0
        } else {
            //系统版本低于8.0
        }

3.4 通过系统给定的Double类型版本号进行判断

//        通过系统给定的Double类型版本号进行判断
        if NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_8_0 {
            //系统版本高于8.0
        } else {
            //系统版本低于8.0
        }

4. App从后台到前台,从前台到后台的动作

指纹验证是已经做完了。但是,咱们需求里面是不是还有两条没实现?

APP进入到后台,10秒之内切回到前台,不做二次验证。 APP进入到后台,超过10秒切回到前台,再次进行指纹验证

接下来我们就要在AppDelegate.swift做文章了。 UIApplicationDelegate有很多方法,我们只说一些跟这次相关的方法。

4.1 App被加载到内存后首次并且唯一次调用的方法

@available(iOS 3.0, *)
optional public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool

程序被加载到内存,完成启动,application对象会自动调用delegate的上面这个方法,证明程序已经启动完成。这个方法是首先会被application回调的方法,且这个方法在整个程序的生命周期中只会被调用一次。 如果是手动创建根控制器就要在这里写点神马了,但是这次咱们就是使用最原始的加载,所以这里什么也不用写。

4.2 App已经进入到后台会被调用的方法

@available(iOS 4.0, *)
optional public func applicationDidEnterBackground(_ application: UIApplication)

在调用这个方法之前,还会被调用那个叫做WillResignActive,我们这次不会用到。那个方法是告诉我们,程序将要失去焦点,也就是失去控制。 紧接着,就会调用这个DidEnterBackground方法。在这个方法里面,我们需要记录一下当前时间。好到时候判断是不是超过了10秒钟。 可是这个地方我们并不能直接赋值到App里面的某个属性里面,进入后台后,App将很大程度上不受我们控制,这个数值极有可能会被释放掉。那怎么办? 所以我们要把这个时间存放在其他地方。数据持久化的几种方法还记得吗?

func applicationDidEnterBackground(_ application: UIApplication) {
    enterBackgroundDate = Date()
    UserDefaults.standard.set(enterBackgroundDate, forKey: "enterBackgroundDate")
    print("进入后台,时间:\(String(describing: enterBackgroundDate))")

}

我们在控制台打印一下,方便调试和看到结果。

4.3 App进入到前台会被调用的方法

@available(iOS 4.0, *)
optional public func applicationWillEnterForeground(_ application: UIApplication)

无论通过什么途径进入到前台,都会调用这个方法。什么叫做无论什么途径? 当然啦,我们回到App有各种情况啊,例如点桌面的应用图标进来了,双击Home键从后台切换回来的。 在这个里面咱们要干几件事情:

  1. 把刚才持久化存储的进入后台的时间取出来

  2. 获取当前时间

  3. 比较两个时间是不是相差超过10秒钟,选择执行相应的操作。比10秒长:重新进行指纹验证短语10秒:直接进入

这里需要注意,不管是什么结果,可能都会存在需要修改若干控制器和View。所以建议如果是这种一对多的情况下,最好使用通知,告诉大家判断的结果。另外,刷新UI请回到UI线程中。

func applicationWillEnterForeground(_ application: UIApplication) { 
    print("即将进入前台")
    let backgroundTime = UserDefaults.standard.value(forKey: "enterBackgroundDate")
    let currentDate = Date()

    print("enterBackgroundDate: \(String(describing: backgroundTime)), currentDate : \(currentDate)")

    let timeInterval = (backgroundTime as! Date).addingTimeInterval(10)

    let result = timeInterval.compare(currentDate)
    if result == .orderedAscending {
        homeVC.checkTouchID()
    } else {
        print("进入后台不足10秒,不需要验证")
    }

}

5. 距离传感器

我们在打电话的时候,当屏幕靠近自己的大脸( ̄ε(# ̄)☆╰╮( ̄▽ ̄///) ,屏幕就会关闭了。当远离障碍物的时候,屏幕就又亮了。这其实就用到了距离传感器。 要想实现距离传感器很简单,很简单就能让App支持检测是否有物体靠近了屏幕。但是并不是所有的 iOS 设备都支持,所以使用前和其他传感器一样,我们依然需要判断一下设备是否支持。

      //判断当前设备是否支持距离传感器
        if UIDevice.current.isProximityMonitoringEnabled {
//            设备支持距离传感器
            NotificationCenter.default.addObserver(self, selector: #selector(xxxxx), name: NSNotification.Name.UIDeviceProximityStateDidChange, object: nil)

//xxxxx 就是当靠近物体的时候需要执行的方法            
        } else {
//            不支持距离传感器
        }
PreviousYUV颜色编码解析NextGPUImage源码解读(二十二)

Last updated 7 years ago