在WKWebView中加载本地网页文件和资源

56
与 UIWebView 和之前的WKWebView版本(iOS 10和macOS 10.12)不同,本地文件的默认加载操作已从 Bundle.main.path 移到 Bundle.main.url。同样,loadFileURL 也成为 WKWebView 中加载本地资源的默认功能。
我知道 .path.url 完全不同,并且过去两者都可以工作-历史上选择默认方法的是 .path; 然而,最新版本的Swift似乎破坏了大部分, 如果不是全部的 .path 解决方案。 .path 解决方案似乎现在会“展平”目录层次结构,将所有 CSS、JS 和任何其他子目录内容放入一个大目录中。这样做会在WKWebView尝试加载index.html时导致加载错误,例如带有链接的子文件夹样式表(即/css/style.css)。
看到无数问题和无数不确定/损坏的答案,是否有快速且无痛的解决方案来实现可以加载本地资源(包括链接的CSS/JS文件)的WKWebView,而不需要任何变通方法?
5个回答

97

更新至Swift 4,Xcode 9.3


这个方法允许WKWebView正确读取您目录和子目录中链接的CSS、JS和大多数其他文件。 您不需要更改您的HTML、CSS或JS代码。

解决方案(快速)

  1. 将Web文件夹添加到您的项目中(文件>添加文件到项目)
    • 如果需要,复制项目
    • 创建文件夹引用*
    • 添加到适用的目标
  2. 将以下代码添加到viewDidLoad中,并根据您的需求进行个性化设置:

    let url = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "website")!
    webView.loadFileURL(url, allowingReadAccessTo: url)
    let request = URLRequest(url: url)
    webView.load(request)
    

解决方案(详细版)

步骤1

将本地网页文件夹导入到项目中的任意位置。确保你:

Xcode > File > Add Files to "Project"

☑️ 复制项目文件(如果需要)

☑️ 创建文件夹引用 (不是“创建分组”)

☑️ 添加到目标

步骤2

进入带有WKWebView的视图控制器,并将以下代码添加到viewDidLoad 方法中:

let url = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "website")!
webView.loadFileURL(url, allowingReadAccessTo: url)
let request = URLRequest(url: url)
webView.load(request)
  • index — 加载文件的名称(不包括 .html 扩展名)
  • website — 您网站文件夹的名称(index.html 应位于此目录根目录中)

结论

整体代码应该类似于以下内容:

import UIKit
import WebKit

class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {

    @IBOutlet weak var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        webView.uiDelegate = self
        webView.navigationDelegate = self

        let url = Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "Website")!
        webView.loadFileURL(url, allowingReadAccessTo: url)
        let request = URLRequest(url: url)
        webView.load(request)
    }

}
如果你对这个方法或者代码还有任何疑问,我会尽力回答!

1
非常感谢。一直在努力寻找可行的解决方案! - Rhuari Glen
1
这也是将一个简单的HTML5(包括几个JS库)应用程序封装成macOS应用程序的方法吗? - z80crew
31
我不确定为什么会调用.load(request)。我认为loadFileURL()是加载本地文件的首选方式,那么load(request)是否有任何额外的作用呢? - Austin
7
我得到了一个致命错误:在解包可选值时意外发现了nil。唯一让它工作的方法是将index.html放在与xcodeproj文件相同的文件夹中,并使用“/”作为子目录。 - Curtis
6
您不需要调用 load 方法。只需调用 loadFileURL 方法即可,第二个 load 是无意义的。 - rmaddy
显示剩余6条评论

15

这对我来说有效:

        WKWebView *wkwebView = [[WKWebView alloc] initWithFrame:CGRectMake(0, 0, 1024, 768)];
        wkwebView.navigationDelegate = self;
        wkwebView.UIDelegate = self;
        [wkwebView.configuration.preferences setValue:@"TRUE" forKey:@"allowFileAccessFromFileURLs"];
        NSURL *url = [NSURL fileURLWithPath:YOURFILEPATH];
        [wkwebView loadFileURL:url allowingReadAccessToURL:url.URLByDeletingLastPathComponent];
        [self.view addSubview:wkwebView];

1
我需要在委托方法中做些什么吗?我下载了一个PDF文件并保存到文档目录。我可以从模拟器的文档目录预览PDF文件,但wkWebView没有显示任何内容,也不知道为什么。我还错过了其他什么吗? - Zhengqian Kuang
1
对于 PDF 文件,您可以使用 PDFKit。 - Zouhair Sassi
请查看此处 https://dev59.com/25_ha4cB1Zd3GeqPzn94#57428675 - Zouhair Sassi
非常感谢! - Zhengqian Kuang

2

1、打开项目设置并转到“Build Phases”选项卡,打开“Link Binary with Libraries”。添加Webkit框架。

2、将html文件添加到您的项目中(如果需要,请复制项目)

3、将以下内容添加到您的代码中: @IBOutlet weak var webView: WKWebView!

4、viewDidLoad viewDidLoad


我必须迁移古老的代码。添加WebKit框架对我非常有帮助。非常感谢。 - CGN

2

我曾经遇到过同样的问题,我的情况是这样的:我从服务器下载了一些HTML内容并将其保存到文档目录中,在应用程序中显示它。同一个控制器也使用了实时URL,因此我必须在URL方案中加入条件。在iOS 13 Xcode 11上进行了测试

  if Url.scheme == "file" as String {
         wkWebView.loadFileURL(Url, allowingReadAccessTo: Url)
    }
    else {
         let request = URLRequest.init(url: Url, cachePolicy:.reloadIgnoringLocalCacheData, timeoutInterval:60)
         wkWebView.load(request)
    }

对我来说,它完美地工作了。


我已经将图像下载到本地文档目录文件夹中,现在我有一个包含 img 的最后路径组件的 HTML 字符串,这些图像理想情况下保存在 docDirectory 中,我如何将该字符串中的所有图像加载到 wkwebview 中,请您指导我具体步骤。 - iMinion
你把HTML内容保存在哪种格式中了?我已经把所有的图片都单独保存了。 - iMinion

0

使用WKWebView,可以在HTML代码中使用项目资源甚至共享库。
例如,我展示了如何从包含ResourceContainingBundleClassNamed类的捆绑包中加载pic.png

NSSTring * htmlCode = @"<img src='pic.png'>";
NSBundle * bundle = [NSBundle bundleForClass:[ResourceContainingBundleClassNamed class]];
NSURL * base = bundle.resourceURL;
WKWebView * represent = [WKWebView new];
[represent loadHtmlString: htmlCode baseURL: base];

魔法在于 resourceURL bundle 属性。如果你只是获取所需文件的路径,然后将其转换为 URL - 将无法成功。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接