关于javascript:iOS使用嵌入的tweet计算html字符串的正确WKWebview高度

iOS Calculate correct WKWebview height for html string with embeded tweet

我正在使用wkwebview使用loadHTMLString方法加载给定的HTML字符串。在wkwebview didFinishNavigation之后,我通过评估javascript" document.height"将wkwebview的高度更新为内容高度。
这适用于纯HTML字符串。

但对于带有嵌入推文高度的html字符串,计算会出错。
这是tweet内容

1
2
3
4
5
6
7
8
9
10
</p>
<blockquote class="twitter-tweet">
<p lang="fr" dir="ltr">Union Cabinet approves civil aviation policy.</p> Press Trust of India (@PTI_News)
June 15, 2016</blockquote>
<p>
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"));

因此,在webview完全加载twitter提要之后,我们不会在wkwebviewdelegate方法中获得回调。


在这种情况下,最好的解决方案是与观察者一起监听" contentSize"上的更改。

为此,您将需要以下两个变量:

1
2
3
4
5
6
7
8
9
10
11
12
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()
        }
    }
}

asyncAfter方法可以忽略,但是在我看来,没有它就无法很好地更新视图的大小。而且我在底部有一个空格。

开始观察和监听更改的方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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)
    }
}

如您所见,变量webViewHeight将在收到新值时更新。

在didFinish导航方法中,应为调用先前方法startObservingHeight的观察者开始"监听"。只要完成twitter的框架,这将开始更新高度。

1
2
3
4
5
6
7
8
9
func webView(_ webView: WKWebView,
             didFinish navigation: WKNavigation!) {
    indicatorLoading?.stopAnimating()
    webViewHeight = webView.scrollView.contentSize.height
    webView.isHidden = false
    if (!observing) {
        startObservingHeight()
    }
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    //Add some Scheme tag in your HTML string.

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

    let strTwitter =" twttr.ready(function(e){ twttr.events.bind('
rendered', function (event) { window.location = \\(urlwithScheme); } ); })"
    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)
}