Add Live Text interaction to your app
System & Services 进阶 20m

在 App 中集成 Live Text:让图片中的文字活起来

Add Live Text interaction to your app

2022年6月6日

在 Apple 官方观看视频

一句话判断

Live Text API 只需要四个类就能让你的图片查看器支持文字选择、数据检测和 QR 码交互——几行代码就能获得系统级的视觉智能能力,不支持太浪费了。

这场 Session 讲了什么

iOS 15 引入了 Live Text 让用户在系统层面和图片中的文字交互。iOS 16 把这个能力开放给了所有开发者。API 非常简洁,只有四个核心类:ImageAnalyzer 执行异步分析,ImageAnalysis 存储分析结果,ImageAnalysisInteraction(iOS/macOS)或 ImageAnalysisOverlayView(macOS)提供交互层。

Session 通过一个实际的图片查看器 demo 展示了集成过程。只需要把 interaction 添加到 UIImageView,在图片加载后调用 analyzer,设置 .automatic 交互类型,就能让用户在图片中选择文字、点击电话号码拨打、点击地址打开地图、扫描 QR 码。整个过程不到 20 行有效代码。

API 还提供了精细的控制:你可以只开启文字选择(.textSelection),只开启数据检测(.dataDetectors),或者让系统自动决定(.automatic)。底部会出现一个 Live Text 按钮和 Quick Actions,你可以隐藏它们、调整 insets、自定义字体。

值得深挖的点

分析时机很重要。 ImageAnalyzer 利用 Neural Engine 做分析,效率很高,但你仍然需要在正确的时机触发。Session 明确建议:只在图片即将显示或已经显示在屏幕上时才开始分析。如果你的 app 有 timeline 这样的滚动列表,等滚动停止后再开始分析。在整个 app 中只共享一个 ImageAnalyzer 实例。这些细节决定了用户体验的流畅度。

手势冲突是需要留意的坑。 Live Text interaction 自带丰富的手势识别器,可能和你的 app 已有手势冲突。Session 提供了三种解决方案:实现 interactionShouldBeginAtPoint delegate 方法检查是否有可交互项目;在 gestureRecognizer 的 gestureRecognizerShouldBegin 中做类似检查;或者 override hitTest 返回正确的 view。如果你的 interaction 在有放大功能的 ScrollView 里,记得把坐标先转换到 window coordinate space 再转换到 interaction 的 view。

代码片段

完整的 Live Text 集成:

import UIKit
import VisionKit

class ImageViewController: UIViewController {
    let analyzer = ImageAnalyzer()          // 整个 app 共享一个
    let interaction = ImageAnalysisInteraction()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        imageView.addInteraction(interaction)   // 添加到承载图片的 view
    }
    
    func updateImage(_ newImage: UIImage) {
        // 先重置旧的交互
        interaction.preferredInteractionTypes = []
        interaction.analysis = nil
        
        Task {
            let config = ImageAnalyzer.Configuration([.text, .machineReadableCode])
            let analysis = try await analyzer.analyze(newImage, configuration: config)
            // 确保图片没变
            if let analysis = analysis, newImage == currentImage {
                interaction.analysis = analysis
                interaction.preferredInteractionTypes = .automatic
            }
        }
    }
}

控制交互类型和自定义 UI:

// 只要文字选择,不要数据检测
interaction.preferredInteractionTypes = .textSelection

// 隐藏底部 Live Text 按钮,但保留文字选择功能
interaction.isSupplementaryInterfaceHidden = true

// 调整内容边距避免和你的 UI 重叠
interaction.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 44, trailing: 0)

// 用自定义字体显示 Live Text 按钮
interaction.supplementaryInterfaceFont = .systemFont(ofSize: 14, weight: .medium)

处理手势冲突:

// 方法一:通过 delegate 控制交互是否开始
func interactionShouldBegin(at point: CGPoint) -> Bool {
    // 如果有可交互的项目或有活跃的文字选择,允许交互
    return interaction.hasInteractiveItem(at: point) || interaction.hasActiveTextSelection
}

// 方法二:在你的 gestureRecognizer delegate 中
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
    let point = gestureRecognizer.location(in: nil)  // window 坐标
    let convertedPoint = interaction.view?.convert(point, from: nil) ?? point
    return !interaction.hasInteractiveItem(at: convertedPoint)
}

最佳实践

  • 只创建一个 ImageAnalyzer 实例并在整个 app 中共享。
  • 传入你手头最原始的图像类型,避免不必要的类型转换。如果碰巧有 CVPixelBuffer,直接用它——最高效。
  • 如果你的图片 view 不是 UIImageView,实现 contentsRectForInteraction delegate 方法,返回正确的 unit rect 来匹配图片的实际显示区域。
  • 在 ScrollView 中的图片,把 interaction 放在 image view 上,不要放在 ScrollView 上。
  • 对于视频帧分析,使用 AVPlayerLayer 的 currentlyDisplayedPixelBuffer——这是唯一保证能拿到正确帧的方式。

还有什么值得关注

  • AVPlayerView 和 AVPlayerViewController 在 iOS 16 自动支持暂停帧的 Live Text,通过 allowsVideoFrameAnalysis 属性控制(默认开启)。
  • UITextField、UITextView、WebKit 和 Quick Look 已经自动支持 Live Text。
  • Live Text 仅在配备 Apple Neural Engine 的设备上可用(iOS),macOS 13 上所有设备都支持。
WWDC 2022