开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情
好久不见,我是 new_cheng。
苹果在 iPhone X 上发布 Face ID 后,这一功能基本已经成为 iPhone 系列的标配了;在 IOS 开发中也会经常用到 Face ID。
以下简称 面容 ID。
在使用面容 ID 之前,我们先来看看,它的常用场景:
- APP 解锁
- 支付
这里我们以解锁的场景为例,看看如何使用面容 ID:
从 App 解锁的使用角度来看,用户会有以下相关操作:
- 首先用户要去 app 的设置页面开启 faceid 解锁选项。
- 开启面容 ID 解锁时需要检查 app 是否拥有面容id的授权。
- 没有面容id的授权时,弹窗提醒,用户点击确认后需要跳转去系统设置页面给app开启面容id授权。
- 授权完成后,用户可以打开 faceid 解锁选项。
- 重新进入app的时候,显示一个解锁页面,调用面容 ID解锁,如果用户取消了解锁,那就无法显示 app 的其他内容
以上是涉及到面容 ID 解锁的一个基本业务流程,下面我们来完成具体实现。
面容 ID 解锁的开关设置
我们先要在 app 的设置页面里面加入一个 Face ID 解锁 的开关设置,先来简单的编写这个页面。
Setting.swift:
struct Settings: View {
@EnvironmentObject var appSetting: AppSetting
@State private var isOpenFaceIdLock = false
var body: some View {
ScrollView {
VStack(alignment: .leading) {
// ...
HStack {
Toggle(isOn: $isOpenFaceIdLock) {
HStack {
Text("😃")
.font(.system(size: 16))
Text("FaceID 解锁")
.font(.body)
.fontWeight(.medium)
.foregroundColor(.gray)
Spacer()
Image(systemName: "chevron.right")
.foregroundColor(Color.gray)
.font(.system(size: 14))
}
}
.onChange(of: isOpenFaceIdLock) { value in
// 将用户设置保存起来
appSetting.isOpenFaceIdLock = value
}
}
}
}
.onAppear {
// 初始化时,使用 AppSetting 的值
self.isOpenFaceIdLock = UserDefaults.standard.bool(forKey: "isOpenFaceIdLock")
}
}
}
一个简单的设置页面就完成了,在这里我们还引入了 AppSetting,用于持久化存储用户的设置,上一次我们在 SwiftUI 开发之旅:适配深色模式 中用到了它。现在,我们会继续在原有的基础上往 AppSetting 中添加关于面容 ID 的内容。
对 AppSetting 有不了解的可以点击适配深色模式的链接前往查看。
我们要在 AppSetting 中加入一个新的字段 isOpenFaceIdLock,用于存储 面容 ID 解锁的设置:
// 是否开启 FaceId 解锁
@Published var isOpenFaceIdLock: Bool = UserDefaults.standard.bool(forKey: "isOpenFaceIdLock") {
didSet {
// 监听数据变化,持久化数据
UserDefaults.standard.set(self.isOpenFaceIdLock, forKey: "isOpenFaceIdLock")
}
}
检查是否授权使用面容 ID
面容 ID 解锁默认是不开启的,当用户开启该设置的时候,我们要先检查我们的 App 是否被系统授权使用 面容 ID 解锁。
在 Setting.swift 中新增 authenticate 函数和用于提示用户需要开启授权的控制变量 isGoOpenAuth:
- 先引入 LocalAuthentication 依赖:
import LocalAuthentication
- 新增函数和变量:
// 是否需要前往设置页面开启权限
@State private var isGoOpenAuth: Bool = false
// 先检测是否开启面容id授权
func authenticate() {
let context = LAContext()
var error: NSError?
// 检查是否可以进行生物特征识别
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
self.isGoOpenAuth = false
} else {
// 没有生物指纹识别功能
if (error?.code == -6) {
self.isGoOpenAuth = true
print("没有生物指纹识别功能")
}
}
}
- 当系统没有授权使用面容 ID 时,提醒用户前往开启授权
ScrollView {
// ...
}
.alert("", isPresented: $isGoOpenAuth) {
Button(role: .cancel) {
self.isGoOpenAuth = false
self.isOpenFaceIdLock = false
} label: {
Text("取消")
}
Button() {
// 前往设置页面进行授权
guard let url = URL(string: UIApplication.openSettingsURLString) **else** {
return
}
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(url)
}
} label: {
Text("去开启")
}
} message: {
Text("开启面容 ID 权限才能够使用解锁哦")
}
请用真机运行。
点击 【去开启】 后,会直接跳转到系统设置中对应 App 的设置页面。
到这里,一个检查授权面容 ID 和持久化用户设置的功能就完成了。
面容 ID 的解锁页面
在用面容 ID 解锁前,为了用户信息安全,是不能显示 App 内的页面内容的。这时候我们就需要一个专用与解锁的页面,当没有进行解锁的时候, App 会一直显示该页面直到解锁成功。
FaceIdLock.swift:
import SwiftUI
struct FaceIdLock: View {
@EnvironmentObject var appSetting: AppSetting
// 是否需要前往设置页面开启权限
@State private var isGoOpenAuth: Bool = false
// 先检测是否开启面容id授权
func authenticateFaceId() {
let context = LAContext()
var error: NSError?
// 检查是否可以进行生物特征识别
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
self.isGoOpenAuth = false
} else {
// 没有生物指纹识别功能
if (error?.code == -6) {
self.isGoOpenAuth = **true**
print("没有生物指纹识别功能")
}
}
}
var body: some View {
ZStack {
Color("mainBg").edgesIgnoringSafeArea(.all)
VStack {
Button(action: {
// 如果用户不小心取消了解锁,需要提供一个点击重新解锁的方式:当用户点击时,调用面容 ID 解锁
authenticateFaceId() // 还是先检查系统是否授权了面容 ID
if !isGoOpenAuth {
appSetting.authenticate()
}
}, label: {
VStack {
Image(systemName: "faceid")
.foregroundColor(Color.blue)
.font(.system(size: 54))
.padding()
Text("点击进行面容 ID 登录")
.foregroundColor(Color.textColor)
}
})
}
}
.alert("", isPresented: $isGoOpenAuth) {
Button(role: .cancel) {
self.isGoOpenAuth = **false**
} label: {
Text("取消")
}
Button() {
// 前往设置页面进行授权
guard let url = URL(string: UIApplication.openSettingsURLString) else {
**return**
}
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
UIApplication.shared.openURL(url)
}
} label: {
Text("去开启")
}
} message: {
Text("开启面容 ID 权限才能够使用解锁哦")
}
.ignoresSafeArea(edges: .top)
.onAppear {
// 初始化显示时,先判断是否授权了faceid
authenticateFaceId()
if !isGoOpenAuth {
appSetting.authenticate()
}
}
}
}
struct FaceIdLock_Previews: PreviewProvider {
static var previews: some View {
FaceIdLock()
.environmentObject(AppSetting())
}
}
在 FaceIdLock 页面,我们同样需要检测是否授权了面容 ID 权限,不然,App 会一直停留在该页面,且无法调起面容 ID 进行解锁。
接着在入口页面 ContentView.swift 中添加一个条件判断:
struct ContentView: View {
@EnvironmentObject var appSetting: AppSetting
var body: some View {
VStack {
if appSetting.isOpenFaceIdLock && !appSetting.isUnlocked {
FaceIdLock()
.frame(maxHeight: .infinity)
} else {
// ...
}
}
}
}
调用面容 ID API
接下来我们需要完成在 FaceIdLock.swift 中解锁时调用的 AppSetting 的 authenticate 函数。
AppSetting.swift:
import LocalAuthentication
class AppSetting: ObservableObject {
// 是否已解锁,只有在使用 faceid 的前提下才能使用该变量,用于判断后面的操作是否能进行
@Published var isUnlocked: Bool = false
func authenticate() {
let context = LAContext()
var error: NSError?
// 检查是否可以进行生物特征识别
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
// 如果可以,执行识别
let reason = "开启面容 ID 权限才能够使用解锁哦"
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, authenticationError **in**
// 鉴权完成
DispatchQueue.main.async {
if success {
// 鉴权成功
self.isUnlocked = true
} else {
// 鉴权失败
self.isUnlocked = false
}
}
}
} else {
// 没有生物指纹识别功能
if (error?.code == -6) {
print("没有生物指纹识别功能")
}
}
}
}
到这里,我们已经完成了一个比较完整的使用面容 ID 解锁的功能了🎉
总结
我们通过实操,完成了一个面容 ID 的使用功能,完整还原了使用面容 ID 的的业务流程。除了自己编写代码来使用面容 ID,你还可以通过诸如 BiometricAuthentication 的第三方库来完成面容 ID 或者指纹识别的使用。合理的运用苹果提供的功能,来提升你应用的用户体验吧。
这是 SwiftUI 开发之旅专栏的文章,是 swiftui 开发学习的经验总结及实用技巧分享,欢迎关注该专栏,会坚持输出。同时欢迎关注我的个人公众号 @JSHub:提供最新的开发信息速报,优质的技术干货推荐。或是查看我的个人博客:Devcursor。
👍点赞:如果有收获和帮助,请点个赞支持一下!
🌟收藏:欢迎收藏文章,随时查看!
💬评论:欢迎评论交流学习,共同进步!