WKWebView加载异常:自定义字体/CSS与loadHTMLString使用问题
解决WKWebView加载修改后HTML时在线资源与本地字体共存的问题
这个矛盾确实挺头疼的——baseURL设本地Bundle就断了在线资源,设nil又拿不到本地字体。我给你两个靠谱的解决方案,你可以根据自己的需求选:
方案一:转换在线资源为绝对URL,保留本地资源路径
核心思路是把原HTML里所有相对路径的在线资源(比如/css/main.css、image.jpg)改成绝对URL指向原网站,这样baseURL设为Bundle时,WebView只会去本地找你自定义的CSS和字体,在线资源还是从原网站拉。
步骤:
下载HTML后处理资源路径
推荐用HTML解析库(比如SwiftSoup)来批量修改所有资源的href/src属性,比正则更可靠。示例代码:import SwiftSoup func processHTML(_ html: String, originalBaseURL: URL) throws -> String { let doc = try SwiftSoup.parse(html) // 遍历所有带资源路径的标签 let resourceElements = try doc.select("link[href], img[src], script[src]") for element in resourceElements { let attr = element.hasAttr("href") ? "href" : "src" let originalPath = try element.attr(attr) // 把相对路径转换成原网站的绝对URL if let absoluteURL = URL(string: originalPath, relativeTo: originalBaseURL) { try element.attr(attr, absoluteURL.absoluteString) } } // 在head里插入自定义CSS链接 let customCSSLink = try ElementFactory.createElement("link") try customCSSLink.attr("rel", "stylesheet") try customCSSLink.attr("type", "text/css") try customCSSLink.attr("href", "styles.css") // 相对Bundle的路径 try doc.head()?.appendChild(customCSSLink) return try doc.html() }配置本地CSS和字体
确保styles.css和字体文件(比如CustomFont.ttf)都添加到项目中,并且勾选了Target Membership。CSS里的字体路径用相对Bundle的写法:@font-face { font-family: 'CustomFont'; src: url('CustomFont.ttf') format('truetype'); font-weight: normal; font-style: normal; } /* 其他自定义样式 */ body { font-family: 'CustomFont', sans-serif !important; }加载处理后的HTML
let originalURL = URL(string: "https://your-target-site.com")! URLSession.shared.dataTask(with: originalURL) { data, _, error in guard let data = data, let rawHTML = String(data: data, encoding: .utf8) else { return } do { let processedHTML = try processHTML(rawHTML, originalBaseURL: originalURL) DispatchQueue.main.async { self.webView.loadHTMLString(processedHTML, baseURL: Bundle.main.bundleURL) } } catch { print("HTML处理失败:\(error)") } }.resume()
方案二:用WKUserScript注入自定义样式(更简洁)
如果不需要修改HTML结构,只是要覆盖样式和加载本地字体,用WKUserScript直接把CSS注入到页面里是更省心的办法。baseURL设为原网站的URL,保证在线资源正常加载,而字体用本地的绝对file URL。
步骤:
构建包含字体的自定义CSS
先获取本地字体的绝对URL,然后把它写到CSS的@font-face里:guard let fontURL = Bundle.main.url(forResource: "CustomFont", withExtension: "ttf") else { print("字体文件未找到") return } let fontURLString = fontURL.absoluteString let customCSS = """ @font-face { font-family: 'CustomFont'; src: url('\(fontURLString)') format('truetype'); } /* 你的其他自定义样式 */ h1 { font-family: 'CustomFont' !important; color: #2c3e50 !important; } """配置WKWebView注入脚本
let userScript = WKUserScript( source: customCSS, injectionTime: .atDocumentEnd, // 页面加载完再注入,确保覆盖原有样式 forMainFrameOnly: true ) let config = WKWebViewConfiguration() config.userContentController.addUserScript(userScript) // 初始化WebView webView = WKWebView(frame: view.bounds, configuration: config) view.addSubview(webView)加载页面
不管是加载原网页,还是加载下载后的HTML,baseURL都设为原网站的URL:// 直接加载原网页 webView.load(URLRequest(url: originalURL)) // 或者加载下载后的HTML webView.loadHTMLString(downloadedHTML, baseURL: originalURL)
注意事项
- 不管用哪种方案,都要确保本地文件(CSS、字体)在Target Membership里被勾选,否则Bundle里不会包含这些文件。
- 方案一的正则替换容易踩坑(比如匹配到字符串里的路径),所以优先用SwiftSoup这类HTML解析库。
- 方案二里的
!important是为了确保自定义样式能覆盖原页面的样式,根据实际情况调整。
内容的提问来源于stack exchange,提问作者Exprove
相关产品推荐
相关产品推荐

