繁体   English   中英

WKWebView 无法使用 loadHTMLString(_, baseURL:) 加载图像和 CSS

[英]WKWebView fails to load images and CSS using loadHTMLString(_, baseURL:)

苹果的建议

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

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

问题

当我使用加载 HTML 字符串时

loadHTMLString(String, baseURL: URL?)

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

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

模拟器 真机

例子

我在我的视图 controller htmlString中定义了一个简单的 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加载到 web 视图中:

webView.loadHTMLString(htmlString, baseURL: libraryURL)

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

解决方案的想法

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

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

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

问题

有什么方法可以使用WKWebView加载本地资源,如图像和 styles

loadHTMLString(String, baseURL: URL?)

function? 或者仍然是 iOS 9+ 中的错误?

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

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

然而:

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 具有<img src="./img/1.png">并且您的 XCOde 项目具有类似的文件夹结构

test.htm

img/

    1.png 
    2.png

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

test.htm
1.png 
2.png

我几乎可以肯定,在您验证了这两个假设之后,您将可以使用此方法。

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

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 本身的位置,这也将隐式允许访问子文件夹。 对我来说,这个问题只在物理设备上很明显,这在模拟器中运行时似乎没有影响,这可能是模拟器和物理设备上的权限工作方式之间的另一个差异。

好吧,您应该能够将本地图像和 CSS 文件(以及与此相关的 JavaScript 文件)与 WKWebViews 与您已经找到的功能一起使用。 我的猜测是问题出在您的baseURL变量上。

2017 年 5 月 7 日更新:

我已经完全更新了我的另一个 SO 答案中的代码, 该答案曾经链接到我的答案here。 我有一个用于loadHTMLString().loadFileURL()的工作项目

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

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

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

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

尝试使用以下方法创建baseURL

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

而不是:

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

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

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

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

当我使用 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)

这对我有用。

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

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

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

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

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;
    }
}

我能够重现类似的问题。 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)

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

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

- 或 -

  • 图像 src 是"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 地址是同一来源后会自动删除 IP 地址。

WKWebView 可以从 NSTemporaryDirectory 加载图片或 css 文件,所以你可以将你的文件复制到 NSTemporaryDirectory,然后加载它。 它在 iOS 14 上对我有用! 看到这个问题。 ios-wkwebview-loadhtmlstring-baseurl-fails-to-load-images-and-read-css

我花了一段时间才弄明白,但基于这个答案,我让它工作了:

https://stackoverflow.com/a/73519282/5868066

尝试这个:

let htmlPath = URL(fileURLWithPath: "")
let htmlDirectory = htmlPath.deletingLastPathComponent() 
let htmlString = try! String(contentsOfFile: htmlPath.path, encoding: .utf8) 

let baseURL = URL(fileURLWithPath: htmlDirectory)
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[.zero]

webView.loadFileURL(htmlPath, allowingReadAccessTo: documentsDirectory)
webView.loadHTMLString(htmlString, baseURL: baseURL)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM