You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 15:36:28