いまさらWKWebViewメモ

使った時のメモ

2017/10くらいに書いて下書きのまま放置されてたのを、Qiitaの下書きが圧迫されてきたので2018/03にそのまま公開。なんで最後の方は適当です。

[公式のリファレンス](https://developer.apple.com/documentation/webkit/wkwebview)でexampleが乗ってるのでとりあえず動かしたい場合はコレで良さ気。

## レイアウト

IBでは`UIWebView`しかないので、Storyboardなどで配置できない。
公式例にある通り、コード上で初期化して制約をつけて配置する。

全画面をWebViewとして使う場合は、VCの`loadView()`をoverrideして`self.view`に紐付ける。

```swift
var webView: WKWebView!
    
override func loadView() {
    let webConfiguration = WKWebViewConfiguration()
    self.webView = WKWebView(frame: .zero, configuration: webConfiguration)
    self.webView.uiDelegate = self
    self.webView.navigationDelegate = self
    self.view = self.webView
}
```

※2018/03追記
Xcode9 (iOS11 SDK)よりIB上でWKWebViewが配置できるようになった。
が、iOS10以前も対応するには結局コード上で置かないといけないのであまり状況は変わってない。

## delegate周り

ドキュメント見つつ、delegateどれがいつ呼ばれるかぜんぜん分からないのでとりあえず全部書いて適当に標準出力してみる。

適当な場所でnavigationのデリゲートセット

```swift
self.webView.navigationDelegate = self
```
全デリゲートメソッドを標準出力だけするようにとりあえず実装。
一部はクロージャ実行しないとエラーになったのでそこだけ修正。

以下呼ばれたメソッド(時系列順)

適当なURLで初回読み込み時

```swift

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!)
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void)
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!)
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
```
まぁだいたい予想できそうな名前になっててくれてて、その通りの動きっぽい。


スクロールボタン(WebViewの画面最下部までスクロールするボタン)押下時

```swift
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)
```

リンクのボタン押下時

```swift
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!)
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error)
```

上から、遷移先に遷移するかの判断をする関数、遷移開始時に呼ばれる関数、遷移失敗時に呼ばれる関数。
遷移失敗するようにしてたのでFailになった。(アプリで遷移先URLだけ拾って別で処理するようにしてたので)


遷移先のURLは下記で取れる

```swift
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
    if let url = webView.url {
        print(url)
    }
}
```

と思って下記を消したら取れなくなった。

```swift
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)
```

このメソッドがないと、ボタン押した時に

```swift

func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!)
```
が呼ばれない??


結局、URLが取りたいなら

```swift

func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!)
```

はナビゲーション開始時のものなので一旦おいといて．

```swift

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void)
```

こっちの遷移前判断のほうででURL拾って判断した。