概要
WKWebView
を使って Web ページを読み込む処理を実装したところ、端末がオフライン状態で通信失敗する等のエラー時に、 WKWebView
の navigationDelegate
のメソッド経由で得られるエラーがローカライズされない問題に遭遇しました。
ローカライズされないというのは、より具体的にいうと、アプリを実行している端末の言語設定に関わらず、 Error
オブジェクトの localizedDescription
等のローカライズ可能な文字列が常に英語になっているということです。
Xcodeプロジェクトの設定をいろいろと試したり、インターネット上での検索をしたりしているうちに、この問題が iOS 側の問題である可能性が高いことがわかりました。
確認環境
ビルド環境
- macOS 10.15.5
- Xcode 11.5 (11E608c)
- Deployment Target: iOS 13.0
実行環境
- 機種・OS
- iPhone 11 Pro Max (iOS 13.5.1)
- 言語と地域の設定
- 使用する言語の優先順序: 日本語、English(英語)
- 地域: 日本
確認方法
Xcodeプロジェクトの多言語対応
実際に WKWebView
のエラーを確認をする前に、Xcode プロジェクトの多言語対応をします。今回は、アプリを英語と日本語に対応させます。
下の画像のようにして、Xcode プロジェクトについての設定画面で Info
ペインの中の Localizations
セクションの +
ボタンから Japanese (ja)
を選択することにより、日本語対応を追加します。これにより、デフォルトで対応していた英語に加えて、日本語にも対応するようになります。
WKWebView
で Web ページを読み込んだ時のエラー内容を確認する
WKWebView
を使って Web ページを読み込むための実装例を以下に示します。コードの中では読み込み対象の URL を https://www.example.com
としていますが、この部分は実際に読み込みたいページの URL に置き換えてください。
import UIKit
import WebKit
class SampleViewController: UIViewController {
@IBOutlet private weak var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
webView.navigationDelegate = self
let url = URL(string: "https://www.example.com")!
let request = URLRequest(url: url)
webView.load(request)
}
}
extension SampleViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
}
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
print(error)
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
print(error)
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
}
}
アプリを実行する端末がオフライン状態のときに、この SampleViewController
に遷移させてみると、 webView(_:didFailProvisionalNavigation:withError:)
が呼び出されます。このメソッドの引数に渡される Error
オブジェクトは次のようになっていました。
Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={NSErrorFailingURLKey=https://www.example.com/, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <747BB86D-7AFF-478E-B62E-E0496E9CBE3A>.<2>, _kCFStreamErrorCodeKey=50, NSLocalizedDescription=The Internet connection appears to be offline., _WKRecoveryAttempterErrorKey=<WKReloadFrameErrorRecoveryAttempter: 0x600001993540>, networkTaskDescription=LocalDataTask <747BB86D-7AFF-478E-B62E-E0496E9CBE3A>.<2>, _kCFStreamErrorDomainKey=1, NSErrorFailingURLStringKey=https://www.example.com/, NSUnderlyingError=0x6000017b7e70 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorCodeKey=50, _kCFStreamErrorDomainKey=1}}}
アプリが日本語に対応していて、端末の言語設定で日本語が優先されているのにもかかわらず、 NSLocalizedDescription
の値が The Internet connection appears to be offline.
となっています。
比較: URLSession
の通信エラーを確認する
WKWebView
の通信エラー内の情報はローカライズされませんが、他のエラーについてはどうでしょうか。比較として、 URLSession
の通信エラーについても確認してみます。
アプリを実行する端末がオフライン状態のときに次の処理を実行して、出力されるエラー情報を確認します。
let session = URLSession(configuration: .default)
let url = URL(string: "https://www.example.com")!
let task = session.dataTask(with: url) { _, _, error in
if let error = error {
print(error)
}
}
task.resume()
dataTask(with:completionHandler:)
の completionHandler
に渡される Error
オブジェクトは次のようになっていました。
Error Domain=NSURLErrorDomain Code=-1009 "インターネット接続がオフラインのようです。" UserInfo={NSUnderlyingError=0x600003d97390 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorCodeKey=50, _kCFStreamErrorDomainKey=1}}, NSErrorFailingURLStringKey=https://www.example.com/, NSErrorFailingURLKey=https://www.example.com/, _kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=50, NSLocalizedDescription=インターネット接続がオフラインのようです。}
URLSession
のエラーでは、NSLocalizedDescription
の値が インターネット接続がオフラインのようです。
となっていて、日本語にローカライズされていることがわかります。
iOS 側の問題である可能性
インターネット上で関連情報がないか検索していたところ、次のバグレポートを発見しました。
rdar://22818481: Localized Error Messages missing in WKWebView
多言語対応しているアプリにおいて webView(_:didFailProvisionalNavigation:withError:)
から得られるエラーの localizedDescription
がローカライズされない(常に英語となる)という、まさに今回問題としている現象が指摘されています。また、このバグレポートのページによると、iOS 8.x, 9, 10においてこの問題が発生していることが報告されています。
もしこれが本当に iOS 側の問題だったのだとすると、現時点での最新バージョンである iOS 13.5.1 においてもまだ解決されていないのかもしれません。しかし、この現象について言及している他のページが見つからなかったので、果たして本当に iOS 側の問題なのか確信を持てずにいます。
今後 iOS のアップデートがあったときには、このエラーのローカライズについての変更があるのかに注目しようと思います。