概要
WKWebViewを使ってWebViewを開発する気をつけるべきことをメモ
対象: iOS11以降
言語: Swift4.x
1. HTTP通信
iOS9以降ではATS(App Transport Security)が導入され、HTTP経由の通信ができなくなりました
WebViewアプリにおいては、下記の設定を Info.plist
に加えることで
URLSession
経由での通信には影響を与えることなく、WebView経由での通信のみATSから除外するこができます
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSAllowsArbitraryLoadsInWebContent</key>
<true/>
</dict>
※ 参考
必須化まで約2ヵ月半!App Transport Securityについて _ セキュリティ対策のラック
2. Cookie管理
iOS11以降は下記が参考になりました
iOS 11 WKWebView 3大新機能 (WWDC 2017) - Qiita
iOS11未満に関しては以前こちらにまとめました
WKWebViewでのSessionの共有 - Qiita
3. alert & confirm
JavaScripのalertやconfirmはデフォルトでは無視されてしまうので、
以下のようにデリゲートメソッドを実装し、アクションをハンドリングする必要があります
// window.alert()
func webView(_ webView: WKWebView, runJavaScriptAlertPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping () -> Void) {
}
// window.confirm()
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
}
4. target="_blank"
WKWebViewでは target="_blank"
時に無反応になってしまうので、
以下のようにデリゲートメソッドを実装し、アクションをハンドリングする必要があります
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
guard let url = navigationAction.request.url else {
return nil
}
guard let targetFrame = navigationAction.targetFrame, targetFrame.isMainFrame else {
webView.load(URLRequest(url: url))
return nil
}
return nil
}
5. カメラロール&フォトライブラリへのアクセスを許可
カメラロールやフォトライブラリにアクセスする必要がある場合は Info.plist
に
NSCameraUsageDescription
と NSPhotoLibraryUsageDescription
を記述し、
アクセス時にダイアログに表示される説明文を設定する必要があります
<key>NSCameraUsageDescription</key>
<string>カメラロールにアクセスする説明文</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>フォトライブラリにアクセスする説明文</string>
6. 位置情報へのアクセスを許可
位置情報にアクセスする際は、 CoreLocation
のデリゲートメソッドを実装し、
またこの時、位置情報を利用する説明文を Info.plist
に記述する必要があります
設定された説明文は、位置情報へのアクセスが求められたときに表示されるダイアログに表示されます
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
lazy var locationManager: CLLocationManager = { [unowned self] in
var manager = CLLocationManager()
manager.delegate = self
return manager
}()
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
case .restricted, .denied:
break
case .authorizedAlways, .authorizedWhenInUse:
break
}
}
}
起動中のみ位置情報を取得する場合
<key>NSLocationWhenInUseUsageDescription</key>
<string>起動中に位置情報を利用する説明文</string>
常に位置情報を取得する場合
<key>NSLocationAlwaysUsageDescription</key>
<string>常にに位置情報を利用する説明文</string>
7. URLスキーマ経由で別アプリを起動
電話番号やメールアドレスなど、URLスキーマ経由でアプリを開くためには
リンクの形式を判別してから処理を実行する必要があります
extension ViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
guard let url = navigationAction.request.url else {
isAllow = false
return
}
if (/* 外部アプリを開く場合 */) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
decisionHandler(.cancel)
}
decisionHandler(.allow)
}
}
8. ビデオのインライン再生
WKWebView
の初期設定では動画のインライン再生に対応していないので、
WKWebViewConfiguration
の allowsInlineMediaPlayback
を true
に設定する必要があります
※ 参考
iOS10のWKWebViewではビデオのインライン再生はできない→できます! - swift life
9. 初回のloadが失敗した場合にreloadが実行されない対策
ネットワークが接続されていなかったときなど初回のloadが失敗した場合、WKWebView
のurlプロパティの値がnilに設定されていまい、
reload時の処理が無視されてしまいます
WKWebView
のurlプロパティの値がnilかどうかを検証し、nilの場合は新規にloadすることで意図した挙動が実現できます
func reload() {
if let url = webview.url {
webview.reload()
} else {
webview.load(URLRequest(url: originalURL))
}
}
※ 参考
ios - WKWebView reload() can't refresh current page - Stack Overflow