WKWebView загружает ресурсы из локальной папки документа
В моем приложении 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, но это не помогло.)
Ответы
Ответ 1
Это упрощенная версия того, что я использовал для загрузки локальных файлов в моем проекте (iOS 10, Swift 3). Я только что обновил свой код (7.5.2017) после его повторного тестирования на iOS 10.3.1 и iPhone 7+ в соответствии с просьбами Рагурама и Fox5150 в комментариях.
Я только что создал совершенно новый проект, и это структура папок:![enter image description here]()
Обновление 19.04.2018: Добавлена новая функция для загрузки .zip с файлами HTML, CSS, JS, разархивируйте его в /Documents/(Alamofire + Zip) и затем загрузите эти файлы в webView. Вы также можете найти его в примере проекта GitHub. Опять же, не стесняйтесь вилка & звезда! :)
Обновление 08.02.2018: наконец-то добавил пример проекта GitHub, который также включает локальный файл JavaScript. Не стесняйтесь раскошелиться звезда! :)
Версия 1 с webView.loadFileURL()
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
}
}
Версия 2 с webView.loadHTMLString()
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
}
}
Gotchas, чтобы высматривать:
- Убедитесь, что ваши локальные html/js/css файлы находятся в Project → Target → Build Phase → 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>
веб /CSS/styles.css
#webkit-h1 {
font-size: 80px;
color: lightblue;
}
Если кому-то нужен пример проекта GitHub, сообщите мне об этом в разделе комментариев, и я его выложу.
Ответ 2
Свифт 4 Метод
Этот метод позволяет WKWebView правильно читать иерархию каталогов и подкаталогов для связанных файлов CSS/JS. Вам НЕ нужно менять код HTML, CSS или JS.
Обновлено для Xcode 9.3
Шаг 1
Импортируйте папку локальных веб файлов в любое место вашего проекта. Убедитесь, что вы:
![Xcode > File > Add Files to "Project"]()
☑️ Копировать элементы при необходимости
☑️ Создавать ссылки на папки (не "Создавать группы")
☑️ Добавить к целям
Шаг 2
Перейдите в View Controller с помощью 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)
}
}
Если у кого-то из вас возникнут дополнительные вопросы об этом методе или коде, я постараюсь ответить. :)
Ответ 3
Это решение помогло мне:
[configuration.preferences setValue:@YES forKey:@"allowFileAccessFromFileURLs"];
Ответ 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
Проверьте этот тикет: iOS: Как загрузить локальные файлы (не в комплекте) в 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)
}