iOS13のUIWebViewにつまずいた

# はじめに
2019年9月初旬くらいからアプリをアップロードしようとすると下記のようなメールがとんでくるようになった。

>ITMS-90809: Deprecated API Usage - Apple will stop accepting submissions of apps that use UIWebView APIs . See https://developer.apple.com/documentation/uikit/uiwebview for more information.

お客さんからさぞ問い合わせが殺到したことでしょう:scream:

# 原因
[iOS8 の頃から `WKWebView` 使えよ](https://developer.apple.com/documentation/uikit/uiwebview)と言われてましたがとうとう `UIWebView` が使えなくなる模様。

あくまでも今回のメールは警告なのでまだ `UIWebView` を使っていても問題ないようです。

正確な期限はまだよくわからない模様（[参考](https://forums.developer.apple.com/thread/122114)）

この警告はとにかくアプリに `UIWebView` が含まれているとくるようです。依存ライブラリに `UIWebView` があっても出るようです。 Cordovaで開発してると大打撃なんだとか。使ったことないんで詳しく知りませんが `WKWebView` に変更されてるやつもあるとか聞きました:hear_no_evil: (Capaciter とか？？）

# 2019/12/24追記
[Updating Apps that Use Web Views](https://developer.apple.com/news/?id=12232019b)
`UIWebView` の明確な寿命が決まりました！！！
新規アプリは 2020/4 まで
既存アプリは 2020/12 まで

# 対応
## ライブラリ
ライブラリに `UIWebView` を使っているものがある場合は別のものを利用するか、修正を待ちましょう！！この警告メールがとぶようになってすぐにいろんなライブラリに Issue がたてられたらしいので人気のライブラリならいつか修正されるでしょう:sleeping:

## プロジェクト
プロジェクト内で `UIWebView` を使っている場合、対応策は下記３つかと思います。

* 外部ブラウザを使う
* SFSafariViewControllerを使う
* WKWebViewを使う

### 外部ブラウザを使う
これはそのまま下記のように外部ブラウザで開く対応です。

```swift
UIApplication.shared.open(URL)
```

まあ、これでいいなら最初からこうしてると思うのでこの方法はあまり使えないでしょう:expressionless:

### SFSafariViewControllerを使う
アプリ内で Web ページを表示するだけなら [SFSafariViewController](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller) を使うのもありかと思います。

```swift
let vc = SFSafariViewController(url: URL)
present(vc, animated: true, completion: nil)
```

ほぼカスタマイズできないし、受け取れるイベントも「初回のページ表示」、「画面を閉じる」くらいなのでちょっと凝ったことをしたい場合は適しません。その代わり Safari と Cookie の同期ができたりします。([参考](https://qiita.com/zakiyamaaaaa/items/26f4edcdbcd1aeaec6d6))

### WKWebViewを使う
結局無難なのが `WKWebView` に置き換える方法。UA や Cookie の設定方法など結構書き換えないといけません:neutral_face:手前味噌ですが下記記事参考にある程度 `UIWebView` から置き換えれるのではないかと思います。

* [iOS(swift)ガワアプリの作成で色々苦労した話](https://qiita.com/am10/items/23ca5b5c8fbbe7ab2b77)

# 余談(target="_blank")
余談ですがリンクの `target="_blank"` について少し。。。

下記のような `target="_blank"` で２回開くようなページがあったとします。

```HTML:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8"/>
	<title>index</title>
</head>
<body>
	<a href="blank1.html" target="_blank">blank1</a>
</body>
</html>
```

```HTML:blank1.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8"/>
	<title>blank1</title>
</head>
<body>
	<a href="blank2.html" target="_blank">blank2</a>
</body>
</html>
```

```HTML:blank2.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8"/>
	<title>blank2</title>
</head>
<body>
	blank2です
</body>
</html>
```

Safari で開くとこんな感じ

![blank](https://user-images.githubusercontent.com/34936885/70371201-baf65400-1913-11ea-8cf8-9d1af0355dfe.gif)

## UIWebViewの場合
何もしなくても blank2.html まで表示できます（戻るボタンとかないので戻る方法はありませんが:expressionless:）

## WKWebViewの場合
何もしない場合リンクが反応しません:crying_cat_face:

下記のように `WKNavigationDelegate` を実装すると `UIWebView` 同様表示できるようになります（戻るボタン...:expressionless:）

```swift
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
  guard let url = navigationAction.request.url else {
    decisionHandler(.cancel)
    return
  }

  if navigationAction.navigationType == .linkActivated {
    if navigationAction.targetFrame == nil 
    || !navigationAction.targetFrame!.isMainFrame {
      webView.load(.init(url: url))
      decisionHandler(.cancel)
      return
   }
  }
  decisionHandler(.allow)
}
```

ちゃんとやる場合はもっと細かく判定処理を書く必要があります（[参考](https://qiita.com/ShingoFukuyama/items/b3a1441025a36ab7659c)）

## SFSafariViewControllerの場合
開けません:expressionless:(２個目が無理と思ってたので２階層にしましたがそもそも開けませんでした:see_no_evil:)

* [Target _blank links not opening in SFSafariViewController](https://stackoverflow.com/questions/53701940/target-blank-links-not-opening-in-sfsafariviewcontroller)

※開けないと思いましたが、もう一回試したら１つ目は開けました（２つ目は開けませんでした）

こういうハマりポイントがあるので置き換える際は気をつけましょう！！（そもそも `target="_blank"` やめた方がいい気もします...）

# さいごに
まだ対応必須ではないですが、いずれ `UIWebView` を使用しているアプリはリジェクトされるようになると思うのでそろそろ対応した方がいいでしょう。

テストなどを考慮するとそこそこの工数がかかるので余裕を持って対応することをお勧めします:exclamation:

結構前から `WKWebView` 使えよ！って感じでしたが iOS10 とかで POST できないとか[色々問題](https://qiita.com/am10/items/23ca5b5c8fbbe7ab2b77)あったので `UIWebView` 使ってるのまだある...:confused:

# 参考
* [審査に出したiOSアプリが ITMS-90809 としてAppleから問題を指摘される話](https://qiita.com/YutoMizutani/items/2b5185c84c31edfdc2d4)
* [UIWebView ドキュメント](https://developer.apple.com/documentation/uikit/uiwebview)
* [SFSafariViewController ドキュメント](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller)
* [Apple Developer Forums:- ITMS-90809: Deprecated API Usage - Apple will stop accepting submissions of apps that use UIWebView APIs](https://forums.developer.apple.com/thread/122114)
* [WKWebViewとSFSafariViewControllerの違いについて](https://qiita.com/zakiyamaaaaa/items/26f4edcdbcd1aeaec6d6)
* [iOS(swift)ガワアプリの作成で色々苦労した話](https://qiita.com/am10/items/23ca5b5c8fbbe7ab2b77)
* [WKWebViewでtarget="_blank"なリンクが開かない時の対処法](https://qiita.com/ShingoFukuyama/items/b3a1441025a36ab7659c)
* [Target _blank links not opening in SFSafariViewController](https://stackoverflow.com/questions/53701940/target-blank-links-not-opening-in-sfsafariviewcontroller)