Предварительная загрузка нескольких локальных WebView

Поскольку я мог просто найти некоторые устаревшие/неработающие решения моей проблемы, я решил снова задать этот вопрос. (См. Устаревшие/неправильные решения:)


Мое приложение разделено в одной нативной части и одной части HTML. HTML сохраняется как локальный файл (index.html) и должен загружаться в представление myWebView.

@IBOutlet weak var myWebView: UIWebView!
func loadWebview() {
    let url = Bundle.main.url(forResource: "index", withExtension: "html")
    let request = URLRequest(url: url!)
    myWebView.loadRequest(request)
    myWebView.scrollView.isScrollEnabled = false
    myWebView.allowsLinkPreview = false
    myWebView.delegate = self
}

Поскольку мое дерево DOM очень велико, переход из основной части в веб-часть (при нажатии кнопки) занимает довольно много времени - по крайней мере, для первого после этого я уверен, что webView-запрос получает кеширование.

To my question: Как я могу предварительно загрузить WebView в приложении init, чтобы избежать белого экрана (возможно, 0,5 с - 1 с) при переключении с родного на Веб-часть?

ИЗМЕНИТЬ:

WKWebView отображает полосу прокрутки, пока UIWebView не был!

Используя (например, с UIWebView) эти стили:

::-webkit-scrollbar {
     display: none;
}

не работает и добавляет следующие строки:

webview.scrollView.showsHorizontalScrollIndicator = false
webview.scrollView.showsVerticalScrollIndicator = false

также не работает.

Ответ 1

Во-первых, вы должны переключиться на WKWebView, UIVewView больше не рекомендуется для использования Apple.

Во-вторых, вы можете создать пул веб-представлений, которые создаются, и попросить загрузить их при запуске приложения. Таким образом, к тому моменту, когда пользователь переключится на веб-интерфейс, веб-просмотр может иметь возможность полностью загрузить.

Для этого вы можете использовать такой класс:

/// Keeps a cache of webviews and starts loading them the first time they are queried
class WebViewPreloader {
    var webviews = [URL: WKWebView]()


    /// Registers a web view for preloading. If an webview for that URL already
    /// exists, the web view reloads the request
    ///
    /// - Parameter url: the URL to preload
    func preload(url: URL) {
        webview(for: url).load(URLRequest(url: url))
    }

    /// Creates or returns an already cached webview for the given URL.
    /// If the webview doesn't exist, it gets created and asked to load the URL
    ///
    /// - Parameter url: the URL to prefecth
    /// - Returns: a new or existing web view
    func webview(for url: URL) -> WKWebView {
        if let cachedWebView = webviews[url] { return cachedWebView }

        let webview = WKWebView(frame: .zero)
        webview.load(URLRequest(url: url))
        webviews[url] = webview
        return webview
    }
}

и попросите его предварительно загрузить URL-адрес иногда во время запуска приложения:

// extension added for convenience, as we'll use the index url in at least
// two places
extension Bundle {
    var indexURL: URL { return self.url(forResource: "index", withExtension: "html")! }
}

webviewPreloader.preload(url: Bundle.main.indexURL)

В-третьих, вам может потребоваться использовать представление контейнера вместо фактического веб-представления в вашем контроллере:

@IBOutlet weak var webviewContainer: UIView!

Осталось добавить предварительно загруженный веб-представление в контейнер:

func loadWebview() {
    // retrieve the preloaded web view, add it to the container
    let webview = webviewPreloader.webview(for: Bundle.main.indexURL)
    webview.frame = webviewContainer.bounds
    webview.translatesAutoresizingMaskIntoConstraints = true
    webview.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    webviewContainer.addSubview(webview)
}

И не в последнюю очередь помните, что сохранение живых экземпляров веб-представлений может привести к снижению производительности - памяти и процессора.