【问题标题】:WKWebView fails to load images and CSS using loadHTMLString(_, baseURL:)WKWebView 无法使用 loadHTMLString(_, baseURL:) 加载图像和 CSS
【发布时间】:2017-02-15 13:15:16
【问题描述】:

Apple's recommendation:

在 iOS 8 及更高版本中运行的应用程序中,使用 WKWebView 类而不是 UIWebView。

因此,我用闪亮的新 WKWebView 替换了我的旧 UIWebView。但是我认为是一个简单的练习(简单地交换类并替换委托方法)结果却是一团糟。

问题

当我使用

加载 HTML 字符串时
loadHTMLString(String, baseURL: URL?)

Web 视图加载并呈现纯 HTML,但 它不加载在 htmlString 中引用的任何图像或 CSS 文件

这种情况只发生在真实设备上
在 Simultor 中,所有引用的资源都已正确加载。

示例

我在视图控制器类中定义了一个简单的htmlString

let imageName = "image.png"

let libraryURL: URL // The default Library URL

var htmlString: String {
    return "<html> ... <img src=\"\(imageName)\" /> ... </html>"
    // "..." represents more valid HTML code incl. header and body tags
}

图像存储在库根文件夹中,因此其 URL 为:

let imageURL = libraryURL.appendingPathComponent(imageName)

现在我将htmlString 加载到网络视图中:

webView.loadHTMLString(htmlString, baseURL: libraryURL)

即使baseURL 设置正确,它也不会加载图像。

解决方案的想法

  1. 可能WKWebView 在解析相对路径时遇到问题,所以我的第一个想法是在 HTML 字符串中使用 绝对路径
    → ❌ 不起作用。

  2. another SO post 的两个答案建议使用
    loadFileURL(URL, allowingReadAccessTo: URL)
    而不是 loadHTMLString(...) 适用于 iOS 9+。
    → ✅ 行得通。

但是,我不能使用解决方案 2,因为我的 HTML 文件是加密的,解密后的文件不能存储在磁盘上。

问题

有没有办法使用WKWebView's 加载本地资源,例如图片和样式

loadHTMLString(String, baseURL: URL?)

功能?还是 iOS 9+ 中的 bug?

(我简直不敢相信 Apple 提供并推荐使用无法从 HTML 字符串中加载任何本地 Web 内容的 Web 视图?!)

【问题讨论】:

标签: ios css swift image wkwebview


【解决方案1】:

WKWebView 可以从 NSTemporaryDirectory 加载图像或 css 文件,因此您可以将文件复制到 NSTemporaryDirectory,然后加载它。它适用于我在 iOS 14 上!看到这个问题。 ios-wkwebview-loadhtmlstring-baseurl-fails-to-load-images-and-read-css

【讨论】:

    【解决方案2】:

    当我使用 UIWebview 时,我使用 baseURL 作为,

    let baseUrl = NSURL(string: Bundle.main.path(forResource: "cms", ofType: "html")!)! as URL
    
    webView.loadHTMLString(bodyPage, baseURL: baseUrl)
    

    但是对于 WKWebView,我使用 baseURL 作为

    let baseUrl = Bundle.main.bundleURL
    
    webView.loadHTMLString(bodyPage, baseURL: baseUrl)
    

    这对我有用。

    【讨论】:

      【解决方案3】:

      我知道这已经很老了,但我遇到了完全相同的问题,我花了几个小时的试验,甚至找到了这个有同样问题的线程(Xamarin Forms App)

      我的问题是:将远程 HTML 内容解析为字符串并添加本地保存的图像(也是动态下载的,没有应用程序的资源)。在模拟器上一切正常,但在实际设备上,本地图像没有显示(也没有?或任何指示错误的东西,只是一个空白帧)。 Xamarin webview 还提供了没有帮助的“BaseURL”选项,也不能在自定义 iOS wkWebView 上使用 BaseURL。

      上面 Scott 指出的唯一可行的解​​决方案是将 HTML 写入文件,然后使用“LoadFileUrl”函数并允许对基本目录进行读取访问。这也适用于 HTML 中图像的绝对文件路径(不仅相对于 basedir,当然还相对于 basedir 中的某个位置)。

      我用来加载网页和本地内容的自定义 webview 渲染器现在看起来像这样:

      protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) {
          base.OnElementPropertyChanged(sender, e);
          NSUrl baseURL = new NSUrl(App.dirNews, true);
          string viewFile = Path.Combine(App.dirNews, "view.html");
          NSUrl fileURL = new NSUrl(viewFile, false);
      
          switch (e.PropertyName) {
              case "Url":
                  System.Console.WriteLine("--- Loading Web page ---");
                  System.Console.WriteLine("--- " + Element.Url + " ---");
                  NSUrlRequest myRequest = new NSUrlRequest(new NSUrl(Element.Url), NSUrlRequestCachePolicy.ReloadIgnoringLocalAndRemoteCacheData, 120);
                  Control.LoadRequest(myRequest);
                  break;
      
              case "HTML":
                  System.Console.WriteLine("--- Showing HTTP content ---");
                  File.WriteAllText(viewFile, Element.HTML, System.Text.Encoding.UTF8);
                  Control.LoadFileUrl(fileURL, baseURL);
                  break;
          }
      }
      

      【讨论】:

        【解决方案4】:

        我今天遇到了这个问题,我找到了解决方案和可能的原因:

        loadHTMLString(String, baseURL: URL?) 
        

        据我所知,此功能不允许渲染的 HTML 访问本地媒体,这是因为它存在注入风险,这可能允许渲染的 HTML 访问和操作您的本地文件系统。使用 html 字符串,它可以来自任何地方或任何人。

        loadFileURL(URL, allowingReadAccessTo: URL)
        

        使用此函数,您可以将 WKWebview 指向 FileManager 中的 html 文件,并使用“allowingReadAccessTo”指向包含文件夹。由于 html 存储在 FileManager 中,它将允许呈现的 HTML 访问本地存储的媒体。

        如果您由于某种原因没有将 html 文件存储在本地(我假设您有),您可以将 html 字符串写入 .html 文件,然后指向该文件的 URL。但是,这只是在破坏 Apple 的保护,所以后果自负(不要这样做)。

        这只是对我有用的解决方案,以及我对我们为什么会遇到问题的理解。

        编辑 #1:错字。

        编辑 #2:我发现了另一个细微差别,当声明“allowingReadAccessTo:”URL 时,如果 HTML 本身需要访问父文件夹中的内容(即:.css、.js 文件),您需要指定父文件夹,不一定是 HTML 本身的位置,这将隐含地允许根据需要访问子文件夹。对我来说,这个问题只在物理设备上很明显,在模拟器中运行时这似乎没有影响,可能是模拟器和物理设备上权限工作方式之间的另一个差异。

        【讨论】:

        • 就是这样!移至 WKWebView 后,CSS 停止工作,这在 UIWebView 中运行良好。现在我将 html 保存到文件中并将其作为文件 url 读取,并带有 allowingReadAccessTo: 到,一切都加载正常。
        • @green0range 如果你能帮助我stackoverflow.com/questions/63800637/…
        【解决方案5】:

        尝试使用以下方法创建baseURL

        let baseURL = URL(fileURLWithPath: "#path#")

        代替:

        let baseURL = URL(string: "#path#")

        主要区别在于第一种方法在路径前添加file://前缀。

        【讨论】:

          【解决方案6】:

          您应该能够通过 WKWebViews 使用本地图像和 CSS 文件(以及 JavaScript 文件)以及您已经找到的功能。我的猜测是问题出在您的 baseURL 变量上。

          7.5.2017 更新:

          我已经完全更新了我的 another SO answer 的代码,这些代码曾经与我的答案相关联。我有一个 loadHTMLString().loadFileURL() 的工作项目

          【讨论】:

          • 你在真机上试过了吗?因为这几乎就是我所做的。 baseURL 应该是解决您的相对路径的位置,但问题实际上与此无关,因为我也尝试在 HTML 中引用绝对路径,但它也不起作用。
          • (顺便说一句:一旦你弄清楚了怪癖一切都很好。首先不应该有任何怪癖!)
          【解决方案7】:

          我能够重现类似的问题。 WKWebView 特别加载我的图像,如果它们位于远程,除了我的应用服务器。

          对于非 SSL 安全的服务器(http 代替 https),您可以按以下方式设置您的 info.plist

          App Transport Security Settings
          
           - Allow Arbitrary Loads in Web Content (Set to YES)
           - Allow Arbitrary Loads (Set to YES)
          

          问题实际上出在服务器上。服务器应用程序是:

          • 将图像 src 从 "http://IP-or-domain/uploads/file.jpg" 更改为 "../../uploads/file.jpg"

          - 或 -

          • 图像源是"http://localhost/uploads/file.jpg" "http://127.0.0.1/uploads/file.jpg" 而不是 "http://YOUR-SERVER-IP-ADDRESS/uploads/file.jpg"

          在这些情况下,实际设备将无法定位图像。这仅适用于 iOS 模拟器,因为虚拟设备与服务器和开发机器相同。它可以读取LOCALHOST127.0.0.1

          在我的服务器中,我使用的是富文本编辑器 (TinyMCE),它会在检测到 IP 地址是同一来源后自动删除它。

          【讨论】:

            【解决方案8】:

            我也一直在尝试这个,有类似的限制,问题似乎是除非baseURL 引用应用程序包,否则路径不会被解析。例如,如果您在应用程序的文档中包含某些内容,则它不起作用。

            编辑:我已经为此 rdar://29130863 提交了雷达

            【讨论】:

            • 我遇到了和 rdar 完全相同的问题。你有机会记得你最终做了什么吗? :)
            【解决方案9】:

            如果不查看您的实际项目,很难给出百分百确定的建议。

            但是:

            class ViewController: UIViewController {
            
                var webView = WKWebView()
            
                override func viewDidLoad() {
                    super.viewDidLoad()
                    webView.translatesAutoresizingMaskIntoConstraints = false
                    let views = [
                        "webView" : webView
                    ]
                    view.addSubview(webView)
                    var constraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|[webView]|", options: [.AlignAllLeading, .AlignAllTrailing], metrics: nil, views: views)
                    constraints.appendContentsOf(NSLayoutConstraint.constraintsWithVisualFormat("V:|[webView]|", options: [.AlignAllTop, .AlignAllBottom], metrics: nil, views: views))
                    NSLayoutConstraint.activateConstraints(constraints)
            
                    let path = NSBundle.mainBundle().pathForResource("ios - WKWebView fails to load images and CSS using loadHTMLString(_, baseURL_) - Stack Overflow", ofType: "htm")
                    let url = NSURL(fileURLWithPath: path!)
                    webView.loadHTMLString(try! String(contentsOfURL: url), baseURL: url.URLByDeletingLastPathComponent)
            
                    // Do any additional setup after loading the view, typically from a nib.
                }
            
                override func didReceiveMemoryWarning() {
                    super.didReceiveMemoryWarning()
                    // Dispose of any resources that can be recreated.
                }
            }
            

            我认为这里的重点是baseUrl参数,你应该正确设置它。在我的情况下,我使用了没有最后一个路径组件的 html 的 url - 例如包含文件夹。这在设备和模拟器上都可以正常工作 - 检查设备快照。我已经将示例项目上传到https://github.com/soxjke/WKWebViewTest,所以你可以看看(我已经从 git 中删除了代码签名信息)

            所以,回顾一下 - 方法有效,功能有效,只是你做错了什么。为了帮助您解决解决方案的问题,我将添加一些建议: 1. 请记住,模拟器文件系统不区分大小写,设备文件系统区分大小写。因此,如果您在 html 中使用小写的文件名 - 这将无法在设备上运行。 8fFsD.png != 8ffsd.png 2. 请记住,在复制资源时,XCode 会忽略您的文件夹结构。因此,如果您的 html 具有 &lt;img src="./img/1.png"&gt; 并且您的 XCOde 项目具有类似

            的文件夹结构
            test.htm
            
            img/
            
                1.png 
                2.png
            

            构建后会被展平,因此 test.htm 和 1.png 和 2.png 将驻留在同一级别

            test.htm
            1.png 
            2.png
            

            我几乎可以肯定,在你验证了这两个假设之后,你会得到这个方法的工作。

            【讨论】:

            • 感谢您在 GitHub 上分享示例项目。有了这个,我已经能够让 webview 在我的 iPhone 上加载资源。我还没有完全弄清楚我的实现有什么问题以及为什么它只能在模拟器中工作,但我会尽快研究它,并将我的发现发布在此页面上的另一个答案中。
            • 很高兴我的回答有帮助。正如我所写,我建议先检查文件名和大小写,然后再检查文件夹结构。 99% 你会发现问题。
            • 解决了我的问题。谢谢!
            • 能否请您检查我的问题,HTMLString 是我的要求,面临同样的问题stackoverflow.com/questions/66050435/…
            【解决方案10】:

            就我个人而言,我不得不改用XWebView,因为 WKWebView 的开箱即用行为不允许加载本地文件。 XWebView 通过在后台加载本地 Web 服务器并通过它引导本地流量来欺骗它。 (XWebView 是基于 WKWebView 之上的)

            似乎有点矫枉过正,但这是我最终不得不做的。

            【讨论】:

            • 感谢您的建议。我已经在其他帖子中阅读了有关此 Web 服务器技巧的信息。但是,使用外部库来设置本地 Web 服务器只是为了呈现一些基本的 HTML 确实感觉有点矫枉过正——这是 webview 的主要目的!
            【解决方案11】:

            您可以对图像进行 base64 编码...我知道这很有效。但不确定它是否适合您的用例。

            有点有趣,我只是在做相反的事情时遇到了这个问题 - 从 base64 编码转换为图像文件。

            【讨论】:

            • 听起来是个聪明的变通办法!会尝试的。但是,在我的情况下,这真的感觉像是肮脏的黑客攻击,因为我必须解析 HTML,找到所有图像 URL,将它们编码为 base64 数据并用数据替换 URL。
            • 是的,我可以看到。在我的情况下,我已经有了想要进入 html 的图像,所以它更干净一些。
            • 我已经尝试对图像进行 base64 编码,但仍然无法正常工作。 github.com/starkindustries/Print2PDFTest
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-01-22
            • 2020-05-22
            • 2020-10-11
            相关资源
            最近更新 更多