3

I am using wkwebview to load given HTML strings using loadHTMLString method. After wkwebview didFinishNavigation I am updating height of wkwebview to content height by evaluating javascript "document.height". This is working for plain html string.

but for html string with embeded tweet height calculation goes wrong. here is tweet content

</p>
<blockquote class="twitter-tweet">
<p lang="fr" dir="ltr">Union Cabinet approves civil aviation policy.</p>&mdash; Press Trust of India (@PTI_News) 
<a href="https://twitter.com/PTI_News/status/742990663495647232">June 15, 2016</a></blockquote>
<p>
<script>window.twttr = (function(d, s, id) 
{var js, fjs = d.getElementsByTagName(s)[0],t = window.twttr || {};if (d.getElementById(id)) return t;js = d.createElement(s);js.id = id;
js.src = "https://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js, fjs);t._e = [];
t.ready = function(f) 
{t._e.push(f);};return t;}(document, "script", "twitter-wjs"));</script>

So after webview loads twitter feeds completely, we do not get callback in wkwebviewdelegate methods .

Pradip
  • 677
  • 9
  • 26

2 Answers2

1

The best solution in this case would be to listening for changes on the "contentSize" with an observer.

In order to do that you will need the following 2 variables:

var observing = false

internal var webViewHeight: CGFloat = 0 {
    didSet {
        guard let webViewHeightConstraint = self.heightConstraint else { return }
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            webViewHeightConstraint.constant = self.webViewHeight
            self.view.layoutSubviews()
            self.delegate?.view.layoutSubviews()
        }
    }
}

The asyncAfter method could be ignored, but in my case the size of the view was not well updated without it. And i was getting a blank space at the bottom.

The methods to start observe and listening for changes are the following:

func startObservingHeight() {
    let options = NSKeyValueObservingOptions([.new])
    webView?.scrollView.addObserver(self, forKeyPath: "contentSize", options: options, context: nil)
    observing = true
}

func stopObservingHeight() {
    webView?.scrollView.removeObserver(self, forKeyPath: "contentSize", context: nil)
    observing = false
}

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    guard let keyPath = keyPath else {
        super.observeValue(forKeyPath: nil, of: object, change: change, context: context)
        return
    }
    switch (keyPath, context) {
    case("contentSize", nil):
        webViewHeight = (webView?.scrollView.contentSize.height)!
    default:
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
    }
}

As you can see, the variable webViewHeight will be updated when received a new value.

In your didFinish navigation method you should start "listening" for the observer calling the previous method startObservingHeight. This will start updating the height as far as the frames of the twitter are completed.

func webView(_ webView: WKWebView,
             didFinish navigation: WKNavigation!) {
    indicatorLoading?.stopAnimating()
    webViewHeight = webView.scrollView.contentSize.height
    webView.isHidden = false
    if (!observing) {
        startObservingHeight()
    }
}
Tomas
  • 866
  • 16
  • 21
0
    //Add some Scheme tag in your HTML string. 

    let urlwithScheme = 'widget.twitter.myapp://url’

    let strTwitter = "<script> twttr.ready(function(e){ twttr.events.bind('rendered', function (event) { window.location = \(urlwithScheme); } ); }) </script>"
    let strHTML = "<!DOCTYPE html><html>\(strTwitter)</html>"



    // After load HTML check url scheme, if it belongs to twitter rendered action or not

    @available(iOS 8.0, *)


    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void){
        // If twitter feed finished renderin
        if(navigationAction.request.url?.scheme == "widget.twitter.myapp"){
            // Don’t update frame here
            decisionHandler(.cancel)
        }

        decisionHandler(.allow)
}
Pradip
  • 677
  • 9
  • 26