14
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

WKWebView で JS を使用して値を取得する 3 つの方法

Last updated at Posted at 2019-03-16

環境

  • Swift 4.2
  • iOS 12.1
  • Xcode 10.1

方法

JS 部分は document.documentElement.innerHTML としてます。

1. evaluateJavaScript(_:completionHandler:) を使う

webView.evaluateJavaScript("document.documentElement.innerHTML") { value, error in
    print(value as? String)
}

一番良く見るやり方。
このコードを実行する場合、読み込みが完了した WKNavigationDelegate の webView(_:didFinish:) 内などで実行する。

2. evaluteJavaScript を同期的に

UIWebView の stringByEvaluatingJavaScript(from:) 的な感じで。

extension WKWebView {
    
    @discardableResult
    func evaluate(javaScript script: String) -> String? {
        var result: String?
        var isCompletion: Bool = false
        
        self.evaluateJavaScript(script) { value, _ in
            result = value as? String
            isCompletion = true
        }
        
        while !isCompletion { RunLoop.current.run(mode: .default, before: Date() + 0.1) }
        return result
    }
}

値が取得できるまで 0.1 秒ずつ待って、取得できたら値を返す。っていうイメージです。

同期処理なので、もちろん重い処理などは特に工夫したほうがいいですね。

DispatchSemaphore で実現しようとすると、デッドロックが発生しうまくいきません。
そもそも evaluateJavaScript(_:completionHandler:) は(UI系の操作も可能なため)メインスレッドでの実行を求められ、引数の closure もメインスレッドで実行されるため。

3. WKScriptMessageHandler を使う

これは日本語の解説記事があんまりなかったイメージ。

let js = """
var html = document.documentElement.innerHTML;
webkit.messageHandlers.getHtml.postMessage(html);
"""
        
let script = WKUserScript(source: js, injectionTime: .atDocumentEnd, forMainFrameOnly: true)
webView.configuration.userContentController.addUserScript(script)
webView.configuration.userContentController.add(self, name: "getHtml")
extension ViewController: WKScriptMessageHandler {
    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
        print(message.name) // "getHtml"
        print(message.body) // HTML全文
    }
}

気をつけるべきポイントとしては、上記コード例でいう2箇所の getHtml の部分は一致してなければいけません。

この stack overflow の回答 のように、 extension を用意すると便利かもしれません。

参考

他にも方法があれば教えてください。
間違いのご指摘もお願いします!

14
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?