Edited at

iOSでWebViewを開発する際に気をつけるべき9のこと


概要

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

NSCameraUsageDescriptionNSPhotoLibraryUsageDescription を記述し、

アクセス時にダイアログに表示される説明文を設定する必要があります

  <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 の初期設定では動画のインライン再生に対応していないので、

WKWebViewConfigurationallowsInlineMediaPlaybacktrue に設定する必要があります

※ 参考

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