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

如何实现在WKWebView加载的PDF文件中查找并高亮指定字符串?

WKWebView加载PDF时页面内查找功能失效的解决方法

问题原因

WKWebView加载PDF时,底层依赖PDFKit渲染而非WebKit的DOM环境,导致:

  • find(_:configuration:completionHandler:)原生方法对PDF内容无作用
  • 原代码中依赖的window.getSelection()等JavaScript API无法执行,无法完成滚动和高亮逻辑

解决方案

需要针对PDF内容单独处理,直接使用PDFKit的搜索API实现页面内查找功能,步骤如下:

  1. 区分内容类型:调用查找方法前,先判断当前WKWebView加载的是HTML还是PDF
  2. PDF场景下的搜索实现:
    • 获取对应PDFDocument实例
    • 用PDFKit的API查找匹配内容
    • 定位到匹配的页面并滚动到对应位置
    • 高亮匹配内容

代码示例

修改原searchInPage方法,增加PDF处理分支:

import PDFKit

private func searchInPage(forward: Bool) {
    ktWebView.select(nil)
    searchIsAtTop = false
    searchIsAtEnd = false
    
    // 判断当前内容是否为PDF
    guard let url = ktWebView.url, url.pathExtension.lowercased() == "pdf",
          let pdfDocument = PDFDocument(url: url) else {
        // HTML场景沿用原逻辑
        let searchConfig = WKFindConfiguration()
        searchConfig.backwards = !forward
        searchConfig.caseSensitive = false
        searchConfig.wraps = false
        ktWebView.find(searchString, configuration: searchConfig, completionHandler: { result in
            guard result.matchFound else {
                if forward { searchIsAtEnd = true }
                else { searchIsAtTop = true }
                return
            }
            ktWebView.evaluateJavaScript("window.getSelection().getRangeAt(0).getBoundingClientRect().top") { offset, _ in
                guard let offset = offset as? CGFloat else { return }
                ktWebView.scrollView.scrollRectToVisible(
                    .init(x: 0, y: offset + ktWebView.scrollView.contentOffset.y,
                          width: 100, height: 100), animated: true)
            }
        })
        return
    }
    
    // PDF场景处理逻辑
    let options: NSString.CompareOptions = [.caseInsensitive]
    let currentPageIndex = ktWebView.scrollView.contentOffset.y / ktWebView.scrollView.contentSize.height * CGFloat(pdfDocument.pageCount)
    
    // 获取初始匹配项
    guard let baseSelection = pdfDocument.findString(searchString, withOptions: options) else {
        if forward { searchIsAtEnd = true }
        else { searchIsAtTop = true }
        return
    }
    
    // 根据查找方向获取目标匹配项
    let targetSelection: PDFSelection? = forward ? baseSelection.findNextMatch() : baseSelection.findPreviousMatch()
    guard let target = targetSelection else {
        if forward { searchIsAtEnd = true }
        else { searchIsAtTop = true }
        return
    }
    
    // 滚动到匹配位置
    guard let targetPage = target.pages.first else { return }
    let pageHeightRatio = CGFloat(targetPage.index) / CGFloat(pdfDocument.pageCount)
    let scrollBaseY = pageHeightRatio * ktWebView.scrollView.contentSize.height
    let matchRect = target.bounds(for: targetPage)
    let absoluteY = scrollBaseY + matchRect.origin.y
    
    ktWebView.scrollView.scrollRectToVisible(
        CGRect(x: 0, y: absoluteY, width: 100, height: 100),
        animated: true)
    
    // 高亮匹配内容
    target.color = UIColor.yellow.withAlphaComponent(0.5)
    if let pdfView = ktWebView.subviews.first(where: { $0 is PDFView }) as? PDFView {
        pdfView.setSelections([target], animate: true)
    }
}

注意事项

  • 如果PDF是通过load(_:mimeType:characterEncodingName:baseURL:)加载的,需保留PDF数据并直接初始化PDFDocument,而非通过URL获取
  • WKWebView中的PDFView为私有子视图,若兼容性要求高,建议直接使用PDFView替代WKWebView显示PDF,搜索逻辑会更易维护
  • 高亮效果可根据需求调整颜色和透明度,确保在PDF内容中清晰可见

内容的提问来源于stack exchange,提问作者Clemens

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 13:25:24