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

时间:2016-10-06 17:12:35

标签: ios css swift image wkwebview

Apple's recommendation

  

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

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

问题

使用

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

网页视图加载并呈现纯HTML,但它不会加载htmlString 中引用的任何图片或CSS文件。

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

Simulator Real Device

实施例

我在视图控制器类中定义了一个简单的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+ →✅有效。

  3. 但是,我无法使用解决方案2,因为我的HTML文件已加密,并且解密的文件不得存储在磁盘上。

    问题

    有没有办法使用WKWebView

    加载图片和样式等本地资源
    loadHTMLString(String, baseURL: URL?)
    

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

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

11 个答案:

答案 0 :(得分:11)

如果不看一下你的实际项目,很难给出一些肯定的肯定建议。

然而:

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网址 - 例如包含文件夹。这适用于设备和设备。模拟器 - 检查设备快照。我已将示例项目上传到https://github.com/soxjke/WKWebViewTest,因此您可以查看一下(我已从git中删除了代码签名信息)

Device snapshot

所以,回顾 - 方法是有效的,功能是有效的,只是你做错了。为了帮助您解决您的解决方案的问题,我将添加一些建议:  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

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

答案 1 :(得分:3)

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

更新7.5.2017:

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

的工作项目

答案 2 :(得分:2)

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

有点好笑,我只是遇到了相反的问题 - 从base64编码转移到图像文件。

答案 3 :(得分:2)

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

似乎有点矫枉过正,但这就是我最终要做的事情。

答案 4 :(得分:2)

我今天遇到了这个问题,我找到了解决方法,并可能是原因:

loadHTMLString(String, baseURL: URL?) 

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

loadFileURL(URL, allowingReadAccessTo: URL)

使用此功能,可以将WKWebview指向FileManager中的html文件,并指向带有“ allowingReadAccessTo”的文件夹。由于html存储在FileManager中,因此它将允许呈现的HTML访问本地存储的媒体。

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

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

编辑#1:错别字。

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

答案 5 :(得分:1)

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

编辑:我已为此rdar://29130863

提交了雷达

答案 6 :(得分:1)

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

我的问题是:将远程HTML内容解析为字符串,并添加本地保存的图像(也动态下载,该应用程序无资源)。在模拟器上,所有工具都可以正常工作,但是在手动设备上,本地图像没有显示(也没有显示?或任何表示错误的内容,只是空白帧)。 Xamarin Webview还提供了“ BaseURL”选项,该选项无济于事,也不能在自定义iOS wkWebView上使用BaseURL。

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

我用于加载Web和本地内容的自定义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;
    }
}

答案 7 :(得分:0)

我能够重现类似的问题。除了我的app服务器之外,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"

- 或 -

  • 图片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地址。

答案 8 :(得分:0)

尝试使用以下方法创建baseURL

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

代替:

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

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

答案 9 :(得分:0)

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

这对我有用。

答案 10 :(得分:0)

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