简体   繁体   中英

Preload multiple local WebViews

Because I could just find some outdated information / not working solutions to my problem I decided to ask this kind of question again. (See outdated / wrong solutions:)


My app is separated in one native part and one HTML part. The HTML is saved as a local file (index.html) and should be load into the myWebView view.

@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
}

Because my DOM tree is very large, switching from the native part to the web part (on button click) takes quite a long time at - least for the first time switching - because afterward, I'm sure the webView-request gets cached.

To my question : How can I preload the WebView on app init to avoid the white screen ( maybe 0.5s - 1s duration ) when switching from the native to the Web part?

EDIT:

The WKWebView is displaying the scrollbar while the UIWebView was not!

Using (like with UIWebView) this styles:

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

is not working and adding these lines:

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

is also not working at all.

Firstly, you should switch to WKWebView , UIWebView is no longer recommended to be used by Apple.

Secondly, you can create a pool of web views that get created and asked to load when the app starts. This way by the time the user switches to the web interface the web view might've got a chance to fully load.

For this you can use a class like this:

/// 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
    }
}

and ask it to preload the url sometimes during the app startup:

// 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)

Thirdly, you might need to use a container view instead of the actual web view, in your controller:

@IBOutlet weak var webviewContainer: UIView!

What remains is to add the preloaded web view to the container when needed:

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)
}

And not lastly, be aware that keeping alive instances of web views, might carry performance penalties - memory and CPU-wise.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM