在 WWDC 2022,苹果发布了VisionKit 中的 DataScannerViewController,这是一个可以在本地无网络状态下识别文本以及条形码的视图控制器,它的相应速度以及精度都是比较高的,他可以支持汉语(简繁版均支持)、英语、日语、韩语、法语、意大利语、德语、西班牙语、葡萄牙语等 9 种语言。 WWDChttps://developer.apple.com/videos/play/wwdc2022/10026/
使用限制:
iOS 设备必须是 A12 或者更新的新版、系统必须为 iOS16 以及以上版本
官方文档
就像上面提到的一样,只有安装了 A12 以及更新芯片的设备才可以使用 DataScannerViewController,所以在使用前需要检查:
import VisionKit
// 检查设备是否支持
guard DataScannerViewController.isSupported else {
print("This device is NOT supported")
return
}
下面这些设备是 2018年发布,是第一批安装 A12 芯片的设备:
如果 DataScannerViewController 在 App 中是一个必不可少的功能,则可以通过在 Info.plist 文件的 “Required device capabilities” 中添加 “iPhone / iPad Minimum Performance A12” 来限制 App 只可以在安装 A12 芯片的设备中使用
在 Info.plist 文件中添加 「Privacy — Camera Usage Description」Key,并补充描述信息
然后根据下面的代码请求相机权限:
AVCaptureDevice.requestAccess(for: .video) { granted in
guard granted else {
print("相机权限未授权. 请在设置中添加权限")
return
}
/// NOTE: 需要特别注意,需要在主线程中展示 DataScannerViewController,否则可能出现 runtime 错误
DispatchQueue.main.async { [weak self] in
guard let strongSelf = self else {
return
}
strongSelf.showDataScannerViewController()
}
}
如何设置请求权限信息支持多语言:
- 创建 InfoPlist.strings
- 使用本地化 key NSCameraUsageDescription 填写多语言文本
官方论坛
DataScannerViewController 有七个属性可以在初始化时进行配置,并且这些属性都是只读的,在执行的时候是不可以修改的。
recognizedDataTypes
支持识别的数据类型,是一组 Option 数据类型,包括文本、条形码、二维码等
qualityLevel
.balanced 平衡
.fast 快速
.accurate 精确
recognizesMultipleItems 默认为 false
isHighFrameRateTrackingEnabled 默认为 true
isPinchToZoomEnabled 默认为 true
isHighlightingEnabled 默认为 false
// 创建 `DataScannerViewController`
let dataScannerViewController = DataScannerViewController(recognizedDataTypes: [.text(), .barcode()],
qualityLevel: .accurate,
recognizesMultipleItems: true,
isHighFrameRateTrackingEnabled: true,
isPinchToZoomEnabled: true,
isGuidanceEnabled: true,
isHighlightingEnabled: true)
我们可以在视图控制器中,通过模态推出 dataScannerViewController 来开始扫描文本和条形码
present(dataScannerViewController, animated: true) {
do {
// 开始扫码
try dataScannerViewController.startScanning()
} catch {
print("Error on scanning: \(error.localizedDescription)")
}
}
我们需要实现 DataScannerViewController 的代理 DataScannerViewControllerDelegate,来监听被识别的文本和条形码,
// Set the delegate to your `UIViewController`
dataScannerViewController.delegate = self
extension YourOwnViewController: DataScannerViewControllerDelegate {
}
只要监测到任何可以识别的文本或者二维码,都会触发 didAdd 回调方法
/// Called when the the scanner recognizes new items in the scene.
/// - Parameters:
/// - dataScanner: The DataScannerViewController object providing the update.
/// - addedItems: The newly recognized items.
/// - allItems: The new complete collection of items remaining after adding `addedItems`.
func dataScanner(_ dataScanner: DataScannerViewController, didAdd addedItems: [RecognizedItem], allItems: [RecognizedItem]) {
addedItems.forEach { recognizedItem in
switch recognizedItem {
case .text(let text):
print("DataScannerViewControllerDelegate: didAdd new items - \(text.transcript)")
case .barcode(let barcode):
print("DataScannerViewControllerDelegate: didAdd new items - \(barcode.payloadStringValue ?? "")")
}
}
}
然而,只要新的视频帧被扫描,新识别的内容会更新或者移除已被识别的文本或者条形码。所以,我们也需要实现 didUpdate 以及 didRemove 的回调
/// Called when the the scanner updates the geometry or content of an item previously recognized in the scene.
/// - Parameters:
/// - dataScanner: The DataScannerViewController object providing the update.
/// - updatedItems: the items that have been updated.
/// - allItems: The complete collection of items.
func dataScanner(_ dataScanner: DataScannerViewController, didUpdate updatedItems: [RecognizedItem], allItems: [RecognizedItem]) {
updatedItems.forEach { recognizedItem in
switch recognizedItem {
case .text(let text):
print("DataScannerViewControllerDelegate: didUpdate updated items - \(text.transcript)")
case .barcode(let barcode):
print("DataScannerViewControllerDelegate: didUpdate updated items - \(barcode.payloadStringValue ?? "")")
}
}
}
/// Called when the scanner no longer sees a previously recognized item in the scene.
/// - Parameters:
/// - dataScanner: The DataScannerViewController object providing the update.
/// - removedItems: The items that were removed.
/// - allItems: The new complete collection of items remaining after removing `removedItems`.
func dataScanner(_ dataScanner: DataScannerViewController, didRemove removedItems: [RecognizedItem], allItems: [RecognizedItem]) {
removedItems.forEach { recognizedItem in
switch recognizedItem {
case .text(let text):
print("DataScannerViewControllerDelegate: didRemove removed items - \(text.transcript)")
case .barcode(let barcode):
print("DataScannerViewControllerDelegate: didRemove removed items - \(barcode.payloadStringValue ?? "")")
}
}
}
DataScannerViewController 是内置在 VisionKit 中的 UIViewController。它是通过 Google Cloud Vision 的 API 以及 Amazon Rekognition API 的服务来实现的,可以监测 9 种语言以及条形码和二维条形码,监测速度又快又准,不过目前只可以运行在 A12 芯片以及 iOS 16以及以上版本的系统