it-roy-ru.com

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, но это не помогло.)
23
Peter

Это упрощенная версия того, что я использовал для загрузки локальных файлов в моем проекте (iOS 10, Swift 3). Я только что обновил свой код (7.5.2017) после того, как снова протестировал его на iOS 10.3.1 и iPhone 7+ в соответствии с просьбой Raghuram и 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
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

Версия 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
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

Gotchas, чтобы высматривать:

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

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>

web/CSS/styles.css

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

Если кому-то нужен пример проекта GitHub, сообщите мне об этом в разделе комментариев, и я его выложу.

29
tech4242

Свифт 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)
    }

}

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

7
Matt Swift

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

[configuration.preferences setValue:@YES forKey:@"allowFileAccessFromFileURLs"];
2
Christian Anchor Dampf

Это хорошо работает (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.")
            }
        }
    }
}
0
hkdalex

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

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