文字っぽいの。

文字を書いています。写真も混ざります。

WKWebViewで表示しているコンテンツのサイズ変更をKVOで検知する

課題

WKWebViewでなんらかのWebページを表示している時に、ページ全体の高さや幅などを取得したい場合がある。簡単に検索して実装をすると、

func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
    // ここで高さを取得する
}

このようなコードを書くことになる。しかし、Webページは画像の読み込みやiframe、JavaScriptの影響で後からサイズが変わっていくので、このコードでは正しくサイズ取得するのは困難である。

解決方法

WKWebViewはUIScrollViewを内包しており、UIScrollViewはKVOに対応しているため、これを利用する。

import UIKit
import WebKit

final class ViewController: UIViewController {
    @IBOutlet weak var webView: WKWebView!

    private var observer: NSKeyValueObservation?

    override func viewDidLoad() {
        super.viewDidLoad()

        observer = webView.scrollView.observe(\.contentSize, options: [.new], changeHandler: { scrollView, value in
            guard let newValue = value.newValue else {
                return
            }

            print(newValue.height, newValue.width)
        })

        let request = URLRequest(url: URL(string: "https://fromatom.hatenablog.com/entry/2023/03/08/100000")!)
        webView.load(request)
    }
}

これによって、WKWebViewで表示したWebページのサイズが変更が監視されるため、サイズが変わるたびに print(newValue.height, newValue.width) が呼ばれるようになる。

なお、KVOは古い書き方もあるが、Swift4から使えるようになったこのBlock-baseのものを使うのが推奨される。