SwiftUI学习100天(Day69 - 项目 14,第二部分)

原创链接:https://www.hackingwithswift.com/100/swiftui
以下内容仅供学习参考:

在本项目技术概述的第二部分,我们将了解 iOS 上两个非常重要的框架:用于在我们的应用程序中呈现地图的 MapKit,以及用于使用 Touch ID 和 Face ID 的 LocalAuthentication。
知道位置、指纹和面部识别对用户来说确实是个人的,你不会感到惊讶,这意味着我们需要始终尊重他们。请记住,用户相信我们会始终以最大程度的谨慎和意图来处理他们的数据,因此让我们认识到隐私、安全和信任是你的核心价值而不是可选的附加值是一件好事。
埃尔维斯·普雷斯利 (Elvis Presley) 曾说过:“价值观就像指纹:每个人的价值观都不相同,但你会在触摸的所有事物上留下它们。” 好吧,这个项目位于价值和指纹维恩图的中心,所以保持敏锐——这很重要。
今天你有两个主题要完成,你将在其中学习如何将地图嵌入到 SwiftUI 应用程序中,如何使用 Face ID 解锁你的应用程序,等等。

将 MapKit 与 SwiftUI 集成
自从 2007 年首款设备问世以来,地图一直是 iPhone 的核心功能,开发者可以使用底层框架的时间几乎与 iPhone 一样长。更好的是,Apple 提供了一个 SwiftUI Map
视图,它漂亮地包装了底层地图框架,让我们可以将地图、注释等与我们的 SwiftUI 视图层次结构的其余部分放在一起。
让我们从一些简单的事情开始:显示地图意味着创建一些程序状态来存储地图的当前中心坐标和缩放级别,这是通过称为MKCoordinateRegion
. 该名称中的“MK”表示它来自 Apple 的 MapKit 框架,因此我们的第一步是导入该框架:
现在我们可以创建一个这样的属性:
那以伦敦市为中心。两组纬度和经度均以度为单位,但实际上,当你远离赤道时,经度的基础值会发生变化,因此可能需要进行一些实验才能找到你喜欢的起始值。
最后,我们可以像这样添加一个地图视图:
它具有与区域的双向绑定,因此它可以随着用户在地图上移动而更新,并且当应用程序运行时,你应该会在地图上看到伦敦。
在创建地图时,我们可以使用多种额外的选项,但到目前为止,最重要的是向地图添加注释的能力——代表我们选择的不同地点的标记。
为此,根据你的目标至少需要三个步骤:定义包含你的位置的新数据类型,创建包含你所有位置的数据类型的数组,然后将它们作为注释添加到地图中。无论你创建什么新数据类型来存储位置,它都必须符合Identifiable
协议,以便 SwiftUI 可以唯一地识别每个地图标记。
例如,我们可以从这种Location
结构开始:
现在我们可以继续定义一个位置数组,无论我们希望地图注释出现在哪里:
第三步是重要的部分:我们可以将位置数组输入Map
视图,并提供将一个位置转换为地图上可见注释的功能。SwiftUI 为我们提供了几种不同的注释类型,但最简单的是MapMarker
:一个带有纬度/经度坐标的简单气球。
例如,我们可以像这样在两个位置放置标记:
当它运行时,你会在地图上看到两个红色气球,尽管它们没有显示任何有用的信息——例如,我们的位置的名称不可见。要添加额外的信息,我们需要使用不同的注释类型创建一个完全自定义的视图,有用的只是称为MapAnnotation
. 它接受与MapMarker
相同的坐标
,除了不只是显示系统样式的气球,我们还可以传入我们想要的任何自定义 SwiftUI 视图。
所以,我们可以用这样的描边红色圆圈替换气球:
使用MapAnnotation
后,你可以传入任何你想要的 SwiftUI 视图——这是一个很好的自定义点,并且可以包含你想要的任何交互性。
例如,我们可以像这样向我们的注释添加点击手势:
我们甚至可以将 NavigationLink
放入我们的地图注释中,在点击注释时将用户引导至不同的视图:
关键是你可以决定是想要简单的东西还是更高级的东西,然后使用你已经知道的所有 SwiftUI 工具和技术添加任何交互性。



在 SwiftUI 中使用 Touch ID 和 Face ID
绝大多数 Apple 设备都标配生物识别身份验证,这意味着它们使用指纹和面部识别来解锁。我们也可以使用此功能,这意味着我们可以确保只有在有效用户解锁时才能读取敏感数据。
这是另一个 Objective-C API,但与 SwiftUI 一起使用时有点不愉快,这比我们目前使用过的其他一些框架要好。
在我们编写任何代码之前,你需要在你的项目选项中添加一个新密钥,向用户解释你为什么要访问 Face ID。由于只有 Apple 知道的原因,我们在代码中传递了 Touch ID 请求原因,在项目选项中传递了 Face ID 请求原因。
因此,选择你当前的目标,转到“信息”选项卡,右键单击现有键,然后选择“添加行”。滚动密钥列表,直到找到“Privacy - Face ID Usage Description”并为其赋值“(We need to unlock your data.)我们需要解锁你的数据”。
现在回到 ContentView.swift,并在文件顶部附近添加此导入:
这样,我们就可以编写一些生物识别代码了。
我之前提到过这“只是有点不愉快”,这就是它的用武之地:Swift 开发人员使用Error
协议来表示运行时发生的错误,但 Objective-C 使用一个名为NSError
. 我们需要能够将它传递到函数中并在函数内部更改它而不是返回一个新值——尽管这是 Objective-C 中的标准,但它在 Swift 中是一种非常陌生的工作方式所以我们需要标记它行为特别是通过使用&
.
我们将编写一种authenticate()
方法,将所有生物识别功能隔离在一个地方。要做到这一点需要四个步骤:
创建
LAContext
的实例
,它允许我们查询生物识别状态并执行身份验证检查。询问上下文是否能够执行生物识别身份验证——这很重要,因为 iPod touch 既没有 Touch ID 也没有 Face ID。
如果生物识别是可能的,那么我们开始实际的身份验证请求,传递一个闭包以在身份验证完成时运行。
当用户通过或未通过身份验证时,我们的完成闭包将被调用并告诉我们它是否有效,如果没有,错误是什么。
请继续并将此方法添加到ContentView
:
该方法本身不会执行任何操作,因为它根本没有连接到 SwiftUI。为了解决这个问题,我们需要添加一些我们可以在身份验证成功时进行调整的状态,以及一个onAppear()
触发身份验证的修饰符。
因此,首先将此属性添加到ContentView
:
这个简单的布尔值将存储应用程序是否显示其受保护的数据,因此我们将在身份验证成功时将其翻转为真。将// authenticated successfully
评论替换为:
最后,我们可以显示当前身份验证状态并在body
属性内开始身份验证过程,如下所示:
如果你运行该应用程序,你很可能只会看到“已锁定”而没有其他任何内容。这是因为默认情况下模拟器没有选择生物识别,而且我们没有提供任何错误消息,所以它会默默地失败。
要试用面容 ID,请转到“功能”菜单并选择“面容 ID”>“已注册”,然后再次启动该应用程序。这次你应该会看到 Face ID 提示出现,你可以通过返回“功能”菜单并选择“Face ID”>“匹配面部”或“非匹配面部”来触发成功或失败的身份验证。
一切顺利,你应该会看到 Face ID 提示消失,在它下面将是“解锁”文本视图——我们的应用程序已检测到身份验证,现在可以使用了。
重要提示:在使用生物识别身份验证时,你应该始终寻找一个备份计划,让用户无需生物识别即可进行身份验证。想一想那些现在可能戴着口罩或可能戴着手套的人——如果你试图强迫他们一直使用生物识别技术,你只会激怒用户。因此,考虑添加一个提示输入密码的屏幕,然后在生物识别失败时将其作为备用。


