В моем приложении 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, но это не помогло).
38
Peter 5 Сен 2016 в 21:53

8 ответов

Лучший ответ

Это упрощенная версия того, что я использовал для загрузки локальных файлов в свой проект (iOS 10, Swift 3). Я только что обновил свой код (7.5.2017) после того, как снова протестировал его на iOS 10.3.1 и iPhone 7+ в соответствии с просьбой Рагурама и Fox5150 в комментариях.

Я только что создал совершенно новый проект, и это структура папок: введите описание изображения здесь

Обновление 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
    }
}

На что следует обратить внимание:

  • Убедитесь, что ваши локальные файлы 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">

Учитывая две версии и ошибки, вот мои файлы html / css из проекта:

Web / 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, сообщите мне в разделе комментариев, и я его загружу.

38
Cœur 18 Сен 2019 в 13:15

Swift 4 Метод

Этот метод позволяет WKWebView правильно читать вашу иерархию каталогов и подкаталогов для связанных файлов CSS / JS. Вам НЕ нужно менять код HTML, CSS или JS.

Обновлено для Xcode 9.3

Шаг 1

Импортируйте папку локальных веб-файлов в любое место вашего проекта. Убедитесь, что вы:

Xcode > File > Add Files to "Project"

☑️ Копировать элементы при необходимости

Strong Создать ссылки на папки (не «Создавать группы»)

☑️ Добавить к целям

Шаг 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)
    }

}

Если у кого-то из вас есть дополнительные вопросы об этом методе или коде, я постараюсь ответить. :)

12
Justin Bush 3 Апр 2018 в 19:32

Создание 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)
1
hgwhittle 27 Мар 2020 в 15:11

Проверьте этот билет: 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)
}
-1
ΩlostA 23 Окт 2018 в 16:27

Это хорошо работает (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.")
            }
        }
    }
}
1
hkdalex 24 Июн 2017 в 13:52

Мне помогло это решение:

[configuration.preferences setValue:@YES forKey:@"allowFileAccessFromFileURLs"];
3
Christian Anchor Dampf 11 Окт 2017 в 06:38

Это хорошо работает с URL-адресом файла или удаленным URL-адресом, а также независимо от того, находится ли файл в пакете или в документах:

if url.isFileURL {
    webView.loadFileURL(url, allowingReadAccessTo: url)
} else {
    let request = URLRequest(url: url)
    webView.load(request)
}
1
drewster 13 Янв 2019 в 20:50

Файлы должны находиться в каталоге документов.

Для получения документа я реализовал следующее:

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)
}
0
Prakash 11 Июл 2020 в 07:33