如何在Swift/SwiftUI中触发iOS内置键盘OCR扫描器?
在SwiftUI中触发系统键盘OCR扫描器的实现方案
你要调用的是iOS系统键盘内置的**文本扫描(Live Text)**功能,以下提供两种可行的实现方案,优先推荐第二种(稳定性更高):
方案1:桥接UITextField触发键盘自带扫描按钮
通过SwiftUI与UIKit的桥接,让输入框成为第一响应者弹出键盘后,自动触发键盘上的扫描按钮:
import SwiftUI import UIKit struct ScanTextField: UIViewRepresentable { @Binding var text: String func makeUIView(context: Context) -> UITextField { let textField = UITextField() textField.borderStyle = .roundedRect // 确保键盘显示扫描按钮(iOS 15+支持) textField.textContentType = .oneTimeCode textField.delegate = context.coordinator return textField } func updateUIView(_ uiView: UITextField, context: Context) { uiView.text = text } func makeCoordinator() -> Coordinator { Coordinator(parent: self) } class Coordinator: NSObject, UITextFieldDelegate { let parent: ScanTextField init(parent: ScanTextField) { self.parent = parent } func textFieldDidBeginEditing(_ textField: UITextField) { // 延迟执行,确保键盘完全加载 DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { self.triggerScannerButton() } } private func triggerScannerButton() { guard let window = UIApplication.shared.windows.first else { return } // 遍历视图层级找到扫描按钮 if let scannerBtn = findScannerButton(in: window) { scannerBtn.sendActions(for: .touchUpInside) } } private func findScannerButton(in view: UIView) -> UIButton? { // 通过 accessibilityLabel 定位扫描按钮(适配多语言) if let btn = view as? UIButton, btn.accessibilityLabel == "扫描文本" { return btn } for subview in view.subviews { if let found = findScannerButton(in: subview) { return found } } return nil } } } // SwiftUI 使用示例 struct ContentView: View { @State private var inputText = "" var body: some View { VStack(spacing: 20) { ScanTextField(text: $inputText) .frame(height: 44) Button("触发OCR扫描") { // 让输入框成为第一响应者,自动触发扫描 UIApplication.shared.sendAction(#selector(UITextField.becomeFirstResponder), to: nil, from: nil, for: nil) } .buttonStyle(.borderedProminent) } .padding() } }
方案1说明
- 仅支持iOS 15及以上版本;
- 依赖系统键盘的视图结构,若苹果后续修改键盘布局,可能失效;
- 无需额外添加权限。
方案2:直接调用系统Live Text识别控制器(推荐)
避开键盘视图层级的依赖,直接使用VisionKit框架的VNDocumentCameraViewController实现OCR扫描,效果与键盘扫描一致,稳定性更高:
import SwiftUI import VisionKit struct LiveTextScanner: UIViewControllerRepresentable { @Binding var scannedText: String @Environment(\.dismiss) var dismiss func makeUIViewController(context: Context) -> VNDocumentCameraViewController { let scanner = VNDocumentCameraViewController() scanner.delegate = context.coordinator return scanner } func updateUIViewController(_ uiViewController: VNDocumentCameraViewController, context: Context) {} func makeCoordinator() -> Coordinator { Coordinator(parent: self) } class Coordinator: NSObject, VNDocumentCameraViewControllerDelegate { let parent: LiveTextScanner init(parent: LiveTextScanner) { self.parent = parent } func documentCameraViewController(_ controller: VNDocumentCameraViewController, didFinishWith scan: VNDocumentCameraScan) { // 处理扫描页面,提取文本 for pageIdx in 0..<scan.pageCount { let pageImage = scan.imageOfPage(at: pageIdx) guard let cgImage = pageImage.cgImage else { continue } let textRequest = VNRecognizeTextRequest { [weak self] request, error in guard let observations = request.results as? [VNRecognizedTextObservation], error == nil else { return } let extractedText = observations.compactMap { $0.topCandidates(1).first?.string }.joined(separator: "\n") DispatchQueue.main.async { self?.parent.scannedText = extractedText self?.parent.dismiss() } } // 设置识别语言,可添加更多语言 textRequest.recognitionLanguages = ["zh-Hans", "en-US"] textRequest.usesLanguageCorrection = true let handler = VNImageRequestHandler(cgImage: cgImage) try? handler.perform([textRequest]) } } func documentCameraViewControllerDidCancel(_ controller: VNDocumentCameraViewController) { parent.dismiss() } } } // SwiftUI 使用示例 struct ContentView: View { @State private var inputText = "" @State private var showScanner = false var body: some View { VStack(spacing: 20) { TextField("扫描结果", text: $inputText) .frame(height: 44) .border(Color.gray) Button("触发OCR扫描") { showScanner = true } .buttonStyle(.borderedProminent) .sheet(isPresented: $showScanner) { LiveTextScanner(scannedText: $inputText) } } .padding() } }
方案2说明
- 支持iOS 13及以上版本;
- 需要在
Info.plist中添加相机权限描述:<key>NSCameraUsageDescription</key> <string>需要使用相机进行文本扫描</string> - 可自定义识别语言、是否启用语言修正等参数;
- 稳定性不受系统键盘布局变更影响。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

