【Flutter】iOSのWebViewで一部サイトが表示されないときに確認するべきこと【ATS】
はじめに
こんにちは。ぽぽらす(@popo_lus)と申します。
FlutterでWebViewを用いたアプリを開発している際、iOSでのみ一部サイトが正しく表示されない問題が発生しました。
同じような問題に陥っている方は、ぜひこの記事の手順を確認してみてください。
前提条件
- Flutter 3.27.0
- Dart 3.6.0
- WebViewパッケージ(以下2つのパッケージで同様の問題が発生することを確認しています)
- webview_flutter 4.11.0
- flutter_inappwebview 6.1.5
- 実行環境 iOS 18.4.1
WebViewパッケージのREADMEを参考に、最小限の設定を行いました。
その状態で動作確認を行ったところ、iOS環境かつ一部サイトでのみページ表示が正常に行えませんでした。(エミュレータ/実機環境双方で再現)
以下に、その状況に陥った際のコードを掲載しておきます。
webview_flutterでのコード
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebViewFlutterPage extends StatelessWidget {
const WebViewFlutterPage({super.key});
Widget build(BuildContext context) {
final controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(),
)
..loadRequest(Uri.parse('https://example.com'));
return Scaffold(
appBar: AppBar(),
body: WebViewWidget(
controller: controller,
),
);
}
}
flutter_inappwebviewでのコード
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class InAppWebViewPage extends StatelessWidget {
const InAppWebViewPage({super.key});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: InAppWebView(
initialUrlRequest: URLRequest(
url: WebUri('https://example.com'),
),
),
);
}
}
なお、webview_flutterではエラー等は特に表示されませんでしたが、flutter_inappwebviewでは下記のエラー(一部抜粋)が表示されました。
このエラーを元に調べたところ、iOSにはApp Transport Security (ATS)と呼ばれるセキュリティ機能が搭載されていることが分かりました。
App Transport Security (ATS)とは?
以下、ChatGPTさんより引用です。
App Transport Security (ATS)とは、iOSアプリがインターネット通信を行う際に、安全な接続(基本的にHTTPS)を強制する仕組みです。AppleがiOS 9から導入しました。
WebView(たとえばWKWebViewやUIWebView)が読み込むWebページに対してもATSが適用され、HTTP(暗号化されていない)通信は禁止されます。
ここではHTTP通信のみブロックされるような解説がされていますが、一部のHTTPS通信もブロックされる場合があるようです。
私がWebView経由でアクセスできなかったサイトも、HTTPS通信かつ通常のブラウザでは特にエラーが出ませんでした。
ATSの設定を変更する
それでは、ATSの設定を変更して該当サイトにアクセスできるようにしましょう。
ATS設定をオフにする
アプリ全体のATS設定をオフにする方法です。
ページが開けない原因がATSにあるかどうか分からない場合は、まずこの設定を試してみて正常に動作するようになるかを確認しましょう。
ios/Runner/Info.plist
を開き、以下の内容を<dict>の中に追記します。
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key><true/>
</dict>
この状態でWebViewを用いて該当ページにアクセスできた場合は次に進みましょう。
ATS設定を最適化する
以上の設定ではアプリ全体のATSを無効化しており、セキュリティ的に問題があります。
Appleのドキュメントでは、可能な場合には特定ドメインに絞ってATS設定を無効化することが推奨されています。
そこで、example.comをATSの対象外とし、それ以外のドメインに対してはATSを適用するようにしてみましょう。
ios/Runner/Info.plist
を再度開き、先ほど追記した内容を削除し、以下の内容に置き換えます。
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>example.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSTemporaryExceptionMinimumTLSVersion</key>
<string>TLSv1.1</string>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>
これで、example.comのみATSの対象外とすることができました。
なお、上記ではこのような設定を変更しています。
- NSIncludesSubdomains
- trueにすることで、設定したドメインの全てのサブドメインも例外に設定する
- NSTemporaryExceptionAllowsInsecureHTTPLoads
- trueにすることで、HTTPSではなくHTTP通信も許可し、一部のHTTPS通信の要件を緩和する
- この設定をtrueにすると、アプリ審査時に理由の申告が必要となる
- NSTemporaryExceptionMinimumTLSVersion
- HTTPS通信をする際のTLSバージョンの最低要件を設定する
- この設定をTLSv1.2未満にすると、アプリ審査時に理由の申告が必要となる
- NSExceptionRequiresForwardSecrecy
- falseにすることで、Perfect Forward Secrecy(PFS:前方秘匿性)をサポートしない暗号スイートも許可する
全ての設定を変更する必要はないので、各自の要件に応じたもののみ設定してください。
なお、私はNSExceptionRequiresForwardSecrecy
をfalseにすることで問題が解決しました。
まとめ
iOSのWebViewで一部サイトが表示されないときには、ATSを一度確認してみるべき。
私がアクセスを試みていたサイトは、HTTPS接続対応かつ通常のブラウザではエラーが出ないサイトであったので、ATSを疑うのに時間がかかってしまいました。
Appleの強固なセキュリティは利用者としては安心ですが、開発者としては辛い部分もありますね。
参考
Discussion
知らんかった!めちゃくちゃわかりやすい