译自 www.hackingwithswift.com/books/ios-s…
更多内容,欢迎关注公众号 「Swift花园」
喜欢文章?不如来个 🔺💛➕三连?关注专栏,关注我 🚀🚀🚀
扫描二维码
扫描二维码 —— 或者任何可视的码,比如条形码 —— 都可以借助 Apple 的 AVFoundation 库实现。但这个库没有被很好地集成到 SwiftUI 中,因此为了免去直接使用 AVFoundation 库的麻烦,我把一个二维码读取器封装成 Swift 包,方便我们在 Xcode 工程中使用。
我的包叫 CodeScanner,可以在 GitHub 上找到,地址为 github.com/twostraws/C… MIT 许可证,欢迎你检视或者编辑源码。这里,我们通过以下步骤添加该 Swift 包:
- 执行 File > Swift Packages > Add Package Dependency。
- 输入 github.com/twostraws/C… 作为包版本库的 URL。
- 至于版本规则,选择 “Up to Next Major”,也就是说,你会获得后续的 bug 修复和新增的特性,但不会获得破坏 API 兼容的改变。
- 点击 Finish 把完成的包导入工程。
CodeScanner 包给到我们一个 CodeScanner
的 SwiftUI 视图,它可以通过 sheet 显示,以比较干净,独立的方式处理二维码扫描。我可能有点啰嗦,但本意是希望强调:编写 SwiftUI 代码的最佳实践是以互不关联的方法和包装器来分离功能,这样你就可以用一种干净、清晰无歧义的方式暴露接口给 SwiftUI 布局。
ProspectsView
里有一个 “扫描” 按钮,我们要用它来触发二维码扫描。把下面这个新的 @State
属性添加到 ProspectsView
:
@State private var isShowingScanner = false
早前我们添加了一个测试功能到 “扫描” 按钮,以便插入示例数据,现在我们不再需要这个功能了,因为我们将要扫描真实的二维码。把导航栏按钮项的动作代码替换成下面的代码:
self.isShowingScanner = true
对于二维码扫描,我让 CodeScanner 包处理了全部的工作,包括识别二维码以及返回结果,所以我们要做的是捕捉结果并进行处理。
当 CodeScannerView
发现二维码时,它会调用一个完成闭包,返回一个包含找到的二维码字符串的 Result
实例, 或者是一个说明问题的 CodeScannerView.ScanError
。只可能发生两种错误:要么是相机不可用,要么是相机无法识别二维码。不管返回了字符串还是错误,我们都要关闭视图。
首先是 ProspectsView.swift 里导入 CodeScanner
:
import CodeScanner
然后把下面这个方法添加到 ProspectsView
:
func handleScan(result: Result<String, CodeScannerView.ScanError>) {
self.isShowingScanner = false
// more code to come
}
在我们显示扫描器并且处理扫描结果之前,我们需要向用户请求使用相机的权限:
- 打开 Info.plist。
- 右键空白处,选择 Add Row。
- 选择 “Privacy - Camera Usage Description” 作为键。
- 输入 “We need to scan QR codes.” 作为值。
现在我们已经准备好扫描二维码了! 借助 isShowingScanner
状态来确定是否展示二维码扫描器,我们可以用 sheet()
modifier 来展示扫描器 UI。
创建一个 CodeScanner
视图需要三个参数:
- 一组要扫描的码的类型数组,由于我们在这个应用里只处理二维码,所以
[.qr]
就可以了,不过 iOS 也知道很多其他类型。 - 作为模拟数据的字符串。Xcode 的模拟器并不支持使用相机扫描二维码,所以
CodeScannerView
会自动提供一个替代的 UI。这个替代 UI 会直接传回我们传入的模拟数据。 - 一个完成函数,可以是一个闭包,但我们可以简单地写一个
handleScan()
方法。
把下面这段代码添加到 ProspectsView
的 navigationBarItems()
modifier 下面:
.sheet(isPresented: $isShowingScanner) {
CodeScannerView(codeTypes: [.qr], simulatedData: "Paul Hudson\npaul@hackingwithswift.com", completion: self.handleScan)
}
这样就完成了大部分工作,最后一步是用 handleScan()
替换 // more code to come
注释,实现对数据的处理。
回忆一下,我们生成的二维码是基于一个名字加一个换行,再加上一个邮件地址。所以如果扫描成功,我们可以把拿到的字符串分解成三部分,然后构建出一个新的 Prospect
。如果扫描失败,我们会打印错误。
把 // more code to come
注释替换成下面的代码:
switch result {
case .success(let code):
let details = code.components(separatedBy: "\n")
guard details.count == 2 else { return }
let person = Prospect()
person.name = details[0]
person.emailAddress = details[1]
self.prospects.people.append(person)
case .failure(let error):
print("Scanning failed")
}
再次运行代码,如果你用的是模拟器,会看到测试 UI,点击任何区域关闭测试 UI 并返回我们的模拟数据。如果你用的是真机,你会看到一个权限消息,向用户请求相机使用,在你授权之后就会看到扫描视图。为了测试扫描功能,你可以同时启动模拟器和真机上的应用,切换模拟器上的 tab 到 Me,然后用真机扫描模拟器的屏幕。
我的公众号 这里有Swift及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~