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

iOS中如何在UIWebView/WKWebView加载动效WebP图片?

iOS WebView加载动效WebP图片解决方案

刚踩过类似的坑,来给你梳理下可行的实现方案,分两种核心场景(推荐的WKWebView和已弃用的UIWebView)来说:

一、优先推荐:WKWebView 方案

苹果从iOS 14开始,WKWebView原生支持静态和动效WebP,但需要注意几个配置细节,尤其是本地HTML和远程资源的加载逻辑:

1. iOS 14+ 原生支持(无需第三方库)

如果你的App只适配iOS14及以上,那步骤非常简洁:

  • 对于本地HTML:确保WebP图片和HTML文件放在同一个Bundle目录下,HTML里直接用相对路径引用即可,比如:
    <img src="./bored_animation.webp" alt="Animated WebP">
    
    加载本地HTML时,要正确设置允许访问的目录:
    if let htmlURL = Bundle.main.url(forResource: "index", withExtension: "html") {
        let accessDir = htmlURL.deletingLastPathComponent()
        webView.loadFileURL(htmlURL, allowingReadAccessTo: accessDir)
    }
    
  • 对于远程WebP(比如你提供的Cloudinary链接):需要让WebView允许动效自动播放,在WKWebViewConfiguration里添加配置:
    let config = WKWebViewConfiguration()
    config.allowsInlineMediaPlayback = true
    config.mediaTypesRequiringUserActionForPlayback = .none
    let webView = WKWebView(frame: view.bounds, configuration: config)
    
    这样动效WebP就能像GIF一样自动循环播放了。

2. 兼容iOS 14以下版本

如果需要适配更低版本,就得借助第三方库解码WebP,推荐用SDWebImageWebPCoder(SDWebImage的官方WebP扩展),核心思路是拦截WebP请求,解码后转成WebView支持的格式(比如GIF)再返回:

步骤1:集成依赖

在Podfile里添加:

pod 'SDWebImageWebPCoder'

执行pod install完成集成。

步骤2:自定义Scheme拦截WebP请求

给WKWebView注册自定义scheme(比如webp://),然后拦截请求并解码:

class WebPWebViewController: UIViewController, WKURLSchemeHandler {
    private var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        setupWebView()
        loadLocalHTML()
    }

    private func setupWebView() {
        let config = WKWebViewConfiguration()
        // 注册自定义scheme处理WebP
        config.setURLSchemeHandler(self, forURLScheme: "webp")
        webView = WKWebView(frame: view.bounds, configuration: config)
        view.addSubview(webView)
    }

    private func loadLocalHTML() {
        guard let htmlURL = Bundle.main.url(forResource: "index", withExtension: "html") else { return }
        let accessDir = htmlURL.deletingLastPathComponent()
        webView.loadFileURL(htmlURL, allowingReadAccessTo: accessDir)
    }

    // MARK: - WKURLSchemeHandler
    func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) {
        guard let url = urlSchemeTask.request.url, url.scheme == "webp" else {
            urlSchemeTask.didFailWithError(NSError(domain: "WebPHandler", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效的Scheme"]))
            return
        }

        // 从Bundle获取WebP文件
        let fileName = url.path.trimmingCharacters(in: ["/"])
        guard let webPURL = Bundle.main.url(forResource: fileName, withExtension: "webp") else {
            urlSchemeTask.didFailWithError(NSError(domain: "WebPHandler", code: -2, userInfo: [NSLocalizedDescriptionKey: "WebP文件不存在"]))
            return
        }

        do {
            let webpData = try Data(contentsOf: webPURL)
            // 解码动效WebP
            let coder = SDImageWebPCoder.shared
            let options = [SDImageCoderOption.webpAllowAnimation: true] as [SDImageCoderOption: Any]
            guard let animatedImage = coder?.decodedImage(with: webpData, options: options) else {
                urlSchemeTask.didFailWithError(NSError(domain: "WebPHandler", code: -3, userInfo: [NSLocalizedDescriptionKey: "WebP解码失败"]))
                return
            }

            // 转成GIF格式返回给WebView
            guard let gifData = animatedImage.sd_imageData(as: .gif) else {
                urlSchemeTask.didFailWithError(NSError(domain: "WebPHandler", code: -4, userInfo: [NSLocalizedDescriptionKey: "转GIF失败"]))
                return
            }

            let response = URLResponse(url: url, mimeType: "image/gif", expectedContentLength: gifData.count, textEncodingName: nil)
            urlSchemeTask.didReceive(response)
            urlSchemeTask.didReceive(gifData)
            urlSchemeTask.didFinish()
        } catch {
            urlSchemeTask.didFailWithError(error)
        }
    }

    func webView(_ webView: WKWebView, stop urlSchemeTask: WKURLSchemeTask) {
        // 可选:处理请求取消逻辑
    }
}

步骤3:修改本地HTML的图片引用

把原来的WebP路径改成自定义scheme的格式:

<img src="webp://bored_animation" alt="Animated WebP">

二、UIWebView 方案(不推荐,已被苹果弃用)

如果还在维护旧项目使用UIWebView,同样可以用SDWebImageWebPCoder处理,核心是通过UIWebViewDelegate拦截WebP请求:

class UIWebPWebViewController: UIViewController, UIWebViewDelegate {
    private var webView: UIWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        webView = UIWebView(frame: view.bounds)
        webView.delegate = self
        view.addSubview(webView)
        
        // 加载本地HTML
        if let htmlPath = Bundle.main.path(forResource: "index", ofType: "html") {
            let htmlString = try? String(contentsOfFile: htmlPath, encoding: .utf8)
            webView.loadHTMLString(htmlString ?? "", baseURL: Bundle.main.bundleURL)
        }
    }

    // MARK: - UIWebViewDelegate
    func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebView.NavigationType) -> Bool {
        guard let url = request.url, url.pathExtension.lowercased() == "webp" else {
            return true
        }

        // 加载并解码WebP
        if let webpData = try? Data(contentsOf: url),
           let coder = SDImageWebPCoder.shared,
           let animatedImage = coder.decodedImage(with: webpData, options: [.webpAllowAnimation: true]),
           let gifData = animatedImage.sd_imageData(as: .gif) {
            // 加载转换后的GIF数据
            webView.load(gifData, mimeType: "image/gif", textEncodingName: "utf-8", baseURL: url.deletingLastPathComponent())
            return false
        }
        return true
    }
}

注意事项

  • 本地资源要确保添加到Xcode的Target中,勾选"Copy Bundle Resources";
  • 远程WebP要注意App Transport Security(ATS)设置,若链接是HTTP需要在Info.plist中添加例外;
  • 尽量迁移到WKWebView,UIWebView已被苹果弃用,不再接收安全更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:17:04