WKWebViewとSFSafariViewControllerの違いについて


## 概要
 iOS開発でWebViewを実装するときに、WKWebViewかSFSafariViewControllerがあります。それぞれの特性について、調べたことを書きます。

## 今回取り上げなかったUIWebViewについて
　iOSの初期のほう(iOS 2.0~)では、WebViewの表示にUIWebViewを使ってきました。しかし、[公式ドキュメント](https://developer.apple.com/documentation/uikit/uiwebview)では、**iOS8以降ではWKWebViewを代わりに使うこと**をアナウンスしています。この理由としては、クラッシュ率、そしてセキリュティの欠陥であると考えられています。なので、これから開発でWebViewを使う場合は、WkWebViewかSFSafariViewControllerを使いましょう。
　
## WKWebViewについて

### 特徴
- iOS 8.0以降使用可能
- カスタマイズの自由性があるが、閉じるボタンを追加したり、場合によっては戻るボタンを自前で用意する必要がある
- ローカルのHTMLファイルの読み込みが可能
- NativeからJavaScriptが使える
- Xcode9以降Storyboard上からWKWebViewを利用可能

### 使い方(ただ表示するだけ)

```
import UIKit
import WebKit

class ViewController: UIViewController, WKUIDelegate {
    
    var webView: WKWebView!
    
    override func loadView() {
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        view = webView
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let myURL = URL(string: "https://www.apple.com")
        let myRequest = URLRequest(url: myURL!)
        webView.load(myRequest)
    }}
```

### Delegate Methods(いくつかピックアップ)

- **func webView(WKWebView, didCommit: WKNavigation!)**
Webページの内容を読み込み始めた所で呼ばれます


- **func webView(WKWebView, didFail: WKNavigation!, withError: Error)**
読み込みが失敗したところで呼ばれます


- **func webView(WKWebView, didFinish: WKNavigation!)**
Webページの内容が読み込み終わったところで呼ばれます


### クッキーの同期について
 WKWebViewでは、Safariブラウザとクッキーの共有はできません。しかし、異なるWKWebView同士の場合クッキーを共有することができます。
 WKProcessPoolにて、staticなプロパティをもたせましょう

```
extension WKProcessPool {

 static let shared = WKProcessPool

}

~ ~ ~

webView.configuration.processPool = sharedProcessPool
```


## SFSafariViewController

### 特徴

- iOS9.0以降使用可能
- Safariの標準機能を備えたViewControllerを作成
- カスタマイズ出来る部分が限られている。登場した頃よりは増えているものの、iOS11現在では、BarのTintColorやDoneボタンのスタイルなど一部しか変更がきかない
- 実装がシンプル
- SafariブラウザとCookieやウェブサイトのデータの共有が可能
- Storyboardからは出来ない

### 使い方(ただ表示するだけ)
```
import SafariServices
let url = URL(string:"https://www.example.com")
if let url = url{
	let vc = SFSafariViewController(URL: url)
	prensetViewController(vc, animated: true, completion: nil)
}

```
これだけで、新しいページが勝手に立ち上がりWebViewが表示されます。実装の手順からすると、WkWebViewよりもお手軽に出来ます。

### Delegate Methods
- **func safariViewController(SFSafariViewController, didCompleteInitialLoad: Bool)**
先頭のURLの読み込みが終わったことを通知します

- **func safariViewController(SFSafariViewController, activityItemsFor: URL, title: String?)**
ユーザーのアクションボタンのタップを通知します

- **func safariViewControllerDidFinish(SFSafariViewController)**
SFSafariViewControllerを閉じたことを通知します

### Cookieの同期について
　SFSafariViewControllerの特徴としては、なんといってもSafariとの同期が出来ることでした。これによっていちいちログインする手間が省けました。
　しかしiOS11から仕様が変わり、Cookie等のデータがSafariとは独立した領域に保存されるようになりました。ただ、Apple側も手を打っていて、**SFAuthenticationSessionクラス**という認証情報を共有するためのクラスが提供されました。これによって、サードパーティーのSafari上での認証を共有することが可能になりました。
　詳しい実装については、[こちらの記事](https://qiita.com/koogawa/items/55a7405c2c323a8f413a)にて参照ください

## まとめ

||WkWebView|SFSafariViewController|
|:---:|:---:|:---:|
|使用可能iOSバージョン| 8.0 ~ | 9.0 ~ |
|基底クラス|UIView|UIViewController|
|Cookieの同期|Safariとは :x: WkWebView同士では :o: |Safariと :o: |
|見た目のカスタマイズ| :o: | :x: (一部のみ) |
|Local htmlの読み込み| :o:  | :x: |


## 参考
- [UIWebViewを使わない理由とWKWebViewを使う理由](https://qiita.com/ShingoFukuyama/items/01a9cdf24090931b4ef3)
- [iOS 11 から追加された SFAuthenticationSession でシングルサインオン](https://qiita.com/koogawa/items/55a7405c2c323a8f413a)
- [WKWebView - WebKit | Apple Developer Documentation](https://developer.apple.com/documentation/webkit/wkwebview)
- [SFSafariViewController - SafariServices | Apple Developer](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller)