WKWebView 确实从本地文档文件夹加载资源

Posted

技术标签:

【中文标题】WKWebView 确实从本地文档文件夹加载资源【英文标题】:WKWebView does load resources from local document folder 【发布时间】:2016-09-05 18:53:16 【问题描述】:

在我的 Swift ios 应用程序中,我想从远程服务器下载一些动态 html 页面,将它们保存在文档目录中,然后从文档目录中显示这些页面。

我正在使用它来加载页面:

var appWebView:WKWebView?
...
appWebView!.loadRequest(NSURLRequest(URL: NSURL(fileURLWithPath: htmlPath)))

一切都在模拟器上运行,但是当我转移到真实手机时,它只是显示一个空白页面。然后我使用 Safari 连接到应用程序,发现它抱怨“加载资源失败”。

然后我尝试先阅读htmlPath的页面内容,然后使用

appWebView!.loadHTMLString()

加载页面。它适用于 HTML 页面很简单的情况。但如果 HTML 引用了其他内容,即文档目录中的 javascript 文件(具有像 <script src="file:////var/mobile/Containers/Data/Application/762035C9-2BF2-4CDD-B5B1-574A0E2B0728/Documents/xxxxx.js"> 这样的绝对路径),它将无法加载。

有谁知道为什么会发生这种情况,以及如何解决这个问题?

更多信息:

XCode 版本:7.3.1 部署目标:8.1(我也尝试使用 9.3,但没有帮助。)

【问题讨论】:

你检查this了吗? 谢谢!!我会试试的.. 请粘贴您下载/保存的html内容代码 根据我的经验 - 当 web 视图与视图层次结构分离时,WKWebView 会出现加载问题。这可能是你的问题。此外,您可以尝试使用以下 API 来处理文件请求:func loadFileURL(_ URL: URL, allowingReadAccessTo readAccessURL: URL) -> WKNavigation? [developer.apple.com/reference/webkit/wkwebview/… 【参考方案1】:

这是我用来在我的项目(iOS 10、Swift 3)中加载本地文件的简化版本。根据 Raghuram 和 Fox5150 在 cmets 中的要求,我刚刚更新了我的代码 (7.5.2017) 在 iOS 10.3.1 和 iPhone 7+ 上再次测试后。

我刚刚创建了一个全新的项目,这是文件夹结构:

19.04.2018 更新: 添加了一项新功能,用于下载包含 HTML、CSS、JS 文件的 .zip,将其解压缩到 /Documents/(Alamofire + Zip)中,然后将这些文件加载​​到网络视图。您也可以在GitHub sample project 中找到它。再次,请随意分叉和加星! :)

更新 08.02.2018: 终于添加了一个GitHub sample project,其中还包括一个本地 JavaScript 文件。随意分叉和加星! :)

带有 webView.loadFileURL() 的版本 1

ViewController.swift

import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate 
    override func viewDidLoad() 
        super.viewDidLoad()
        let webView = WKWebView()
        let htmlPath = Bundle.main.path(forResource: "index", ofType: "html")
        let htmlUrl = URL(fileURLWithPath: htmlPath!, isDirectory: false)
        webView.loadFileURL(htmlUrl, allowingReadAccessTo: htmlUrl)
        webView.navigationDelegate = self
        view = webView
    

带有 webView.loadHTMLString() 的版本 2

ViewController.swift

import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate 
    override func viewDidLoad() 
        super.viewDidLoad()
        let webView = WKWebView()
        let htmlPath = Bundle.main.path(forResource: "index", ofType: "html")
        let folderPath = Bundle.main.bundlePath
        let baseUrl = URL(fileURLWithPath: folderPath, isDirectory: true)
        do 
            let htmlString = try NSString(contentsOfFile: htmlPath!, encoding: String.Encoding.utf8.rawValue)
             webView.loadHTMLString(htmlString as String, baseURL: baseUrl)
         catch 
            // catch error
        
        webView.navigationDelegate = self
        view = webView
    

需要注意的问题:

确保您的本地 html/js/css 文件位于 Project -> Target -> Build Phases -> Copy Bundle Resources 确保您的 html 文件不引用相对路径,例如css/styles.css 因为 iOS 会扁平化你的文件结构,styles.css 将与 index.html 处于同一级别,所以改写 <link rel="stylesheet" type="text/css" href="styles.css">

鉴于有 2 个版本,这里的问题是我的项目中的 html/css 文件:

网页/index.html

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
    <title>Offline WebKit</title>
    <link rel="stylesheet" type="text/css" href="styles.css">
  </head>
  <body>
    <h1 id="webkit-h1">Offline WebKit!</h1>
  </body>
</html>

web/css/styles.css

#webkit-h1 
  font-size: 80px;
  color: lightblue;

如果有人想要 GitHub 示例项目,请在 cmets 部分告诉我,我会上传。

【讨论】:

所以看起来我在调用 loadHTMLString 时可能错过了“baseURL”参数。但我更喜欢 Roman 指出的更好:(***.com/questions/24882834/…)。实际上,我的 html 页面中确实有一个 标记,它引用了一个远程服务器(因为该文件包含一些调用远程服务器但没有使用绝对路径的 javascript,我不想浏览整个 javascript文件来更新所有这些调用),同时,html 也在本地驱动器上使用了一些 javascript 和 css 文件。 我收到此错误:在展开可选值时意外发现 nil @tech4242 很好的答案!您还可以通过使用文件夹引用添加资产来支持 html/css/js 中的子文件夹引用。您可以在 Xcode 中将您的 html 资产文件夹拖到您的项目结构中,然后选择“创建文件夹引用”。然后,您可以通过执行以下操作访问整个资产目录结构:(假设您的文件夹名为 HtmlAssetsBundle.main.url(forResource: "HtmlAssets", withExtension: nil). 版本 1 在 macOS 上使用 WKWebView。不过,版本 2 不适用于我在 macOS 上使用 WKWebView。似乎allowReadAccessTo参数可能是解锁对macOS上应用程序访问baseURL路径的关键。 @tech4242 上面的例子效果很好,但是如果我添加与styles.css相同的javascript文件,它不会加载到html中。【参考方案2】:

Swift 4 方法

此方法允许 WKWebView 正确读取链接的 CSS/JS 文件的目录和子目录的层次结构。您确实需要更改您的 HTML、CSS 或 JS 代码。

为 Xcode 9.3 更新

步骤 1

将本地 Web 文件的文件夹导入到您的项目中。确保您:

☑️ 如果需要,复制项目

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

☑️ 添加到目标

第二步

使用 WKWebView 转到 View Controller 并将以下代码添加到 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 – 您的 Web 文件夹的名称(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)
    


如果你们中的任何人对此方法或代码有任何疑问,我会尽力回答。 :)

【讨论】:

如果你允许我问一个简单的问题:你为什么使用webView.loadFileURL 然后+webView.load 稍后?只是loadFileURL 不起作用? 那是个错误。你不想要两者。【参考方案3】:

这个解决方案帮助了我:

[configuration.preferences setValue:@YES forKey:@"allowFileAccessFromFileURLs"];

【讨论】:

如果我们使用这个,苹果会接受应用商店的申请吗? 我遇到了我使用这个的问题,现在它正在加载文件 我使用的是 xcode 9.4.1,它可以在最新版本中运行,但我无法让它在 ios 9.0 中运行【参考方案4】:

这很好用(Swift 3、Xcode 8):

import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate 

    var webView: WKWebView!

    override func loadView() 
        webView = WKWebView()
        webView.navigationDelegate = self
        view = webView
    

    override func viewDidLoad() 
        super.viewDidLoad()
        if let url = Bundle.main.url(forResource: "file", withExtension: "txt")
        
            do
            
                let contents = try String(contentsOfFile: url.path)
                webView.loadHTMLString(contents, baseURL: url.deletingLastPathComponent())
            
            catch
            
                print("Could not load the HTML string.")
            
        
    

【讨论】:

【参考方案5】:

这适用于文件 URL 或远程 URL,以及文件是在包中还是在文档中:

if url.isFileURL 
    webView.loadFileURL(url, allowingReadAccessTo: url)
 else 
    let request = URLRequest(url: url)
    webView.load(request)

【讨论】:

【参考方案6】:

以这种方式构造 URL 允许我使用 WKWebView 从文档目录加载资源:

guard let docDir = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) else 
    return


let resourceURL = docDir.appendingPathComponent("/Path/To/Your/Resource")
self.wkWebView.loadFileURL(resourceURL, allowingReadAccessTo: docDir)

【讨论】:

使用上面的解决方案,我完全可以将一个图像从 doc dir 加载到 WKWebView 中,但是你能帮我吗?我有一个包含 .图片的最后路径,我已经下载了文档目录中的图片如何在 WKWEBview 中显示 html 图片【参考方案7】:

文件必须在文档目录中。

我实现了以下内容来检索文档:

let documentDirUrl = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let fileNameWithExtension = "IMG_0002.PNG"
let indexFileUrl = documentDirUrl.appendingPathComponent(fileNameWithExtension)
if FileManager.default.fileExists(atPath: indexFileUrl.path) 
    webView.loadFileURL(indexFileUrl, allowingReadAccessTo: documentDirUrl)

【讨论】:

【参考方案8】:

检查那张票:iOS: How to load local files (not in the bundle) in a WKWebView?

var nsurl = URL(fileURLWithPath: URL(fileURLWithPath: URL(fileURLWithPath: documentsDirectory()).appendingPathComponent(user_appli).absoluteString).appendingPathComponent("index.html").absoluteString) //locally
var readAccessToURL: URL? = nsurl.deletingLastPathComponent?.deletingLastPathComponent

if let anURL = readAccessToURL 
    webView?.loadFileURL(nsurl, allowingReadAccessTo: anURL)

【讨论】:

以上是关于WKWebView 确实从本地文档文件夹加载资源的主要内容,如果未能解决你的问题,请参考以下文章

从应用程序的文档目录加载本地 html 文件 swift wkwebview

LoadFileUrl 和 LoadHtmlString 未加载本地文档资源

如何使用 WKWebview 从 iPad 的 Document 目录加载 javascript 和 css 资源?

在 WKWebview 中使用本地资源

在 WKwebView (SWIFT) 中加载本地资源以及 HTML 字符串?

使用 JavaScript 访问 WKWebView 中的本地文件