[SwiftUI 100 天] 扫描二维码

981 阅读4分钟

译自 www.hackingwithswift.com/books/ios-s…

更多内容,欢迎关注公众号 「Swift花园」

喜欢文章?不如来个 🔺💛➕三连?关注专栏,关注我 🚀🚀🚀

扫描二维码

扫描二维码 —— 或者任何可视的码,比如条形码 —— 都可以借助 Apple 的 AVFoundation 库实现。但这个库没有被很好地集成到 SwiftUI 中,因此为了免去直接使用 AVFoundation 库的麻烦,我把一个二维码读取器封装成 Swift 包,方便我们在 Xcode 工程中使用。

我的包叫 CodeScanner,可以在 GitHub 上找到,地址为 github.com/twostraws/C… MIT 许可证,欢迎你检视或者编辑源码。这里,我们通过以下步骤添加该 Swift 包:

  1. 执行 File > Swift Packages > Add Package Dependency。
  2. 输入 github.com/twostraws/C… 作为包版本库的 URL。
  3. 至于版本规则,选择 “Up to Next Major”,也就是说,你会获得后续的 bug 修复和新增的特性,但不会获得破坏 API 兼容的改变。
  4. 点击 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
}

在我们显示扫描器并且处理扫描结果之前,我们需要向用户请求使用相机的权限:

  1. 打开 Info.plist。
  2. 右键空白处,选择 Add Row。
  3. 选择 “Privacy - Camera Usage Description” 作为键。
  4. 输入 “We need to scan QR codes.” 作为值。

现在我们已经准备好扫描二维码了! 借助 isShowingScanner 状态来确定是否展示二维码扫描器,我们可以用 sheet() modifier 来展示扫描器 UI。

创建一个 CodeScanner 视图需要三个参数:

  1. 一组要扫描的码的类型数组,由于我们在这个应用里只处理二维码,所以 [.qr] 就可以了,不过 iOS 也知道很多其他类型。
  2. 作为模拟数据的字符串。Xcode 的模拟器并不支持使用相机扫描二维码,所以 CodeScannerView 会自动提供一个替代的 UI。这个替代 UI 会直接传回我们传入的模拟数据。
  3. 一个完成函数,可以是一个闭包,但我们可以简单地写一个 handleScan() 方法。

把下面这段代码添加到 ProspectsViewnavigationBarItems() 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及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~

Swift花园微信公众号