iOS传感器:App前后台切换后,获取敏感信息使用touch ID进行校验1. 指纹识别传感器的用法介绍2. Touch ID指纹识别的代码实现3. 判断系统版本号的几种方法4. App从后台到前台,

今天咱们主要是说指纹识别传感器,在文章的最后也会顺带说一下距离传感器。

Touch ID是苹果公司的一种指纹识别技术。Touch ID不存储用户的任何指纹图像,只保存代表指纹的数字字符。iPhone 的处理器采用了新的高级安全架构,其中有一块名为Secure Enclave的区域用以专门保护密码和指纹数据。只有Secure Enclave可以访问指纹数据,而且它还把这些数据同处理器和系统隔开,因而这些永远不会被存储在苹果的服务器上,也不会被同步到iCloud或其他地方。除了Touch ID之外,它们不会被匹配到其他指纹库中。

也就是说,每个Touch ID组件只与一个处理器匹配。对于重视安全性的用户来说,这个发现当然是个好消息。不过这让iPhone的维修更为复杂,假如你的Touch ID不小心坏了,或者拆屏幕的时候不小心碰断了Touch ID的某根线缆,或许你就再也无法在你的手机上使用指纹识别功能了。

以下视频截图来自重案组第四季第四集,看上有点玄乎呀。

重案组S4.png

重案组S4.png

重案组S4.png

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

  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的开发者数量正在稳定的上升。

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

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

好了,就结束了。就这么简单,下面我们就几个重点部分分享一下代码。

然后,敲黑板!!!真正应用开发中中,几乎没人只是验证一下touch ID,就不干别的了。验证识别指纹,肯定是为了下一步的业务流程做服务。

既然是这样,验证的结果肯定直接影响到下一步的业务流程,同时也极大的影响了界面的展示。必然会影响到好几个控制器或者好几个View,极有可能是一对多的关系

一对多,听上去好耳熟。是不是要暗示点什么?对了。通知,通知,通知,通知。嗯。这个不是这篇文章的重点。别忘记了通知。

因为会影响到好几个控制器或者好几个View,所以,请真心的不要忘记了咱们前面分享过的四大对象之UIApplication对象iOS四大对象之AppDelegate及UIApplicationMain函数/程序启动过程。 一定要好好看看呀。

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

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

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

image.png

image.png

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将很大程度上不受我们控制,这个数值极有可能会被释放掉。那怎么办?

所以我们要把这个时间存放在其他地方。数据持久化的几种方法还记得吗?不记得啦?传送门:《iOS使用沙盒进行数据持久化》

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 {
//            不支持距离传感器
        }

今天的分享就到这里啦。代码实在太少了,就不上传了。好不好?


俺又回去看了看这个系列第一天的时候立下的宏愿,哈哈,要写八篇。加速传感器、陀螺仪、磁力计、指纹识别传感器、距离传感器、好玩的综合例子,这六个都搞完了。

最后就剩下蓝牙了。目前还没有想好定位是啥,要不要分享BLE的iBeacon在室内定位上的应用。所以计划就改了,宅胖就是这么善变随机应变的人。

啦啦啦啦。下一个系列,多线程。嗯。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏陈仁松博客

ASP.NET Core 'Microsoft.Win32.Registry' 错误修复

今天在发布Asp.net Core应用到Azure的时候出现错误InvalidOperationException: Cannot find compilati...

4818
来自专栏pangguoming

Spring Boot集成JasperReports生成PDF文档

由于工作需要,要实现后端根据模板动态填充数据生成PDF文档,通过技术选型,使用Ireport5.6来设计模板,结合JasperReports5.6工具库来调用渲...

1.2K7
来自专栏Ceph对象存储方案

Luminous版本PG 分布调优

Luminous版本开始新增的balancer模块在PG分布优化方面效果非常明显,操作也非常简便,强烈推荐各位在集群上线之前进行这一操作,能够极大的提升整个集群...

3095
来自专栏转载gongluck的CSDN博客

cocos2dx 打灰机

#include "GamePlane.h" #include "PlaneSprite.h" #include "BulletNode.h" #include...

5346
来自专栏张善友的专栏

Miguel de Icaza 细说 Mix 07大会上的Silverlight和DLR

Mono之父Miguel de Icaza 详细报道微软Mix 07大会上的Silverlight和DLR ,上面还谈到了Mono and Silverligh...

2697
来自专栏Golang语言社区

【Golang语言社区】GO1.9 map并发安全测试

var m sync.Map //全局 func maintest() { // 第一个 YongHuomap := make(map[st...

4688
来自专栏闻道于事

js登录滑动验证,不滑动无法登陆

js的判断这里是根据滑块的位置进行判断,应该是用一个flag判断 <%@ page language="java" contentType="text/html...

6708
来自专栏跟着阿笨一起玩NET

c#实现打印功能

2632
来自专栏C#

DotNet加密方式解析--非对称加密

    新年新气象,也希望新年可以挣大钱。不管今年年底会不会跟去年一样,满怀抱负却又壮志未酬。(不过没事,我已为各位卜上一卦,卦象显示各位都能挣钱...)...

4828
来自专栏java 成神之路

使用 NIO 实现 echo 服务器

4537

扫码关注云+社区