Flutter アプリでシステムの手動プロキシ設定を自動検知・適用する(Android/iOS)
はじめに
企業向け Flutter アプリを開発していると、社内ネットワークのプロキシ設定に対応する必要があります。
本記事では、デバイスに設定された手動プロキシ(固定の host:port)を自動検知し、Flutter アプリの HTTP 通信に適用する方法を解説します。
Flutter の標準 HTTP クライアント (dart:io の HttpClient) はデフォルトではシステムのプロキシ設定を参照しません。
そのため、ネイティブ側でプロキシ設定を取得し、Flutter 側に渡す仕組みを自前で実装する必要があります。
アーキテクチャ
MethodChannel を使ってネイティブ(Android/iOS)側のプロキシ設定を Dart 側に橋渡しします。
┌─────────────────────────────────────┐
│ Flutter (Dart) │
│ │
│ ProxySettingsHelper │
│ ↓ MethodChannel 呼び出し │
│ HttpOverrides.global に適用 │
│ → dart:io HttpClient がプロキシ使用│
└──────────────┬──────────────────────┘
│ com.example/proxy
┌───────────┴───────────┐
│ │
▼ ▼
Android (Kotlin) iOS (Swift)
MainActivity.kt AppDelegate.swift
ConnectivityManager CFNetworkCopy
.defaultProxy SystemProxySettings()
Android 実装(Kotlin)
プロキシの検知
ConnectivityManager.defaultProxy を使ってシステムのプロキシ設定を取得します。
// MainActivity.kt
private fun detectProxyConfig(): ProxyConfig? {
return try {
val connectivityManager =
getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
?: return null
val proxy = connectivityManager.defaultProxy ?: return null
if (!proxy.host.isNullOrEmpty() && proxy.port != -1) {
ProxyConfig(proxy.host, proxy.port)
} else {
null
}
} catch (e: Exception) {
Log.e(TAG, "Error detecting proxy configuration", e)
null
}
}
JVM システムプロパティへの適用
取得したプロキシ情報を JVM のシステムプロパティに設定します。
これにより OkHttp や AWS Amplify 等のネイティブ SDK も自動でプロキシを使用するようになります。
private fun applyProxyProperties(host: String, port: String) {
System.setProperty("http.proxyHost", host)
System.setProperty("http.proxyPort", port)
System.setProperty("https.proxyHost", host)
System.setProperty("https.proxyPort", port)
}
private fun clearProxyProperties() {
System.clearProperty("http.proxyHost")
System.clearProperty("http.proxyPort")
System.clearProperty("https.proxyHost")
System.clearProperty("https.proxyPort")
}
アプリ起動時の自動適用
configureFlutterEngine でアプリ起動時にプロキシを自動検知・適用します。
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
applySystemProxyIfAvailable()
setupMethodChannel(flutterEngine)
}
private fun applySystemProxyIfAvailable() {
val proxyConfig = detectProxyConfig()
if (proxyConfig != null) {
applyProxyProperties(proxyConfig.host, proxyConfig.port.toString())
Log.i(TAG, "Auto-detected and set system proxy to ${proxyConfig.host}:${proxyConfig.port}")
} else {
clearProxyProperties()
}
}
MethodChannel のセットアップ
Dart 側からも呼び出せるよう MethodChannel を実装します。
private fun setupMethodChannel(flutterEngine: FlutterEngine) {
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
.setMethodCallHandler { call, result ->
when (call.method) {
METHOD_GET_PROXY_SETTING -> {
result.success(getProxySetting())
}
METHOD_APPLY_SYSTEM_PROXY_IF_AVAILABLE -> {
applySystemProxyIfAvailable()
result.success(null)
}
else -> result.notImplemented()
}
}
}
private fun getProxySetting(): String? {
return detectProxyConfig()?.let { "${it.host}:${it.port}" }
}
iOS 実装(Swift)
プロキシの検知
CFNetworkCopySystemProxySettings() でシステムのプロキシ設定を取得します。
// ProxyManager.swift
import Foundation
import SystemConfiguration
class ProxyManager {
static let shared = ProxyManager()
private init() {}
func getProxyString() -> String? {
guard let settings = fetchProxySettings(),
let host = settings[kCFNetworkProxiesHTTPProxy as String] as? String,
let port = settings[kCFNetworkProxiesHTTPPort as String] as? NSNumber else {
return nil
}
return "\(host):\(port)"
}
private func fetchProxySettings() -> [String: Any]? {
return CFNetworkCopySystemProxySettings()?.takeUnretainedValue() as? [String: Any]
}
private func hasProxy(settings: [String: Any]) -> Bool {
return settings[kCFNetworkProxiesHTTPProxy as String] != nil &&
settings[kCFNetworkProxiesHTTPPort as String] != nil
}
}
URLSession への適用
取得したプロキシ設定を URLSessionConfiguration.default.connectionProxyDictionary に設定します。
func configure() {
if let settings = fetchProxySettings(), hasProxy(settings: settings) {
applyProxyConfiguration(settings: settings)
} else {
clearProxyConfiguration()
}
}
private func applyProxyConfiguration(settings: [String: Any]) {
guard let host = settings[kCFNetworkProxiesHTTPProxy as String] as? String,
let port = settings[kCFNetworkProxiesHTTPPort as String] as? NSNumber else {
return
}
URLSessionConfiguration.default.connectionProxyDictionary = [
kCFNetworkProxiesHTTPEnable: true,
kCFNetworkProxiesHTTPProxy: host,
kCFNetworkProxiesHTTPPort: port
]
print("Proxy configured: \(host):\(port)")
}
private func clearProxyConfiguration() {
URLSessionConfiguration.default.connectionProxyDictionary = nil
}
AppDelegate での初期化と MethodChannel
// AppDelegate.swift
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
// 起動時にプロキシを適用
ProxyManager.shared.configure()
setupMethodChannel()
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
private func handleMethodCall(call: FlutterMethodCall, result: @escaping FlutterResult) {
switch call.method {
case "getProxySetting":
result(ProxyManager.shared.getProxyString())
case "applySystemProxyIfAvailable":
ProxyManager.shared.configure()
result(nil)
default:
result(FlutterMethodNotImplemented)
}
}
Dart 実装
HttpProxyOverrides
dart:io の HttpClient にプロキシを適用するためのクラスです。
デバッグ・プロファイルモードでは証明書エラーを無視する設定も含めています。
// http_proxy_overrides.dart
import 'dart:io';
import 'package:flutter/foundation.dart';
class HttpProxyOverrides extends HttpOverrides {
HttpProxyOverrides({this.proxyString});
/// プロキシの URL(例: "192.168.1.100:8080")
final String? proxyString;
@override
HttpClient createHttpClient(SecurityContext? context) {
final client = super.createHttpClient(context);
if (kDebugMode || kProfileMode) {
// 開発環境では自己署名証明書を許可
client.badCertificateCallback = (cert, host, port) => true;
}
if (proxyString != null && proxyString!.isNotEmpty) {
client.findProxy = (uri) => 'PROXY $proxyString; DIRECT';
}
return client;
}
}
ProxySettingsHelper
ネイティブ側と通信してプロキシ設定を取得・適用するヘルパークラスです。
// proxy_settings_helper.dart
import 'dart:io';
import 'package:flutter/services.dart';
class ProxySettingsHelper {
ProxySettingsHelper({
MethodChannel? methodChannel,
}) : _methodChannel =
methodChannel ?? const MethodChannel('com.example/proxy');
final MethodChannel _methodChannel;
/// システムプロキシ設定を検出して適用します
Future<void> detectAndApplyProxySettings() async {
try {
final proxyInfo = await _methodChannel
.invokeMethod<String?>('getProxySetting');
if (proxyInfo != null && proxyInfo.isNotEmpty) {
HttpOverrides.global = HttpProxyOverrides(proxyString: proxyInfo);
debugPrint('Auto-detected and set HttpOverrides proxy: $proxyInfo');
} else {
HttpOverrides.global = null;
debugPrint('No proxy detected');
}
} catch (e, stackTrace) {
// do something
}
}
}
main.dart での初期化
アプリ起動時にプロキシ設定を検知・適用します。
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final proxySettingsHelper = ProxySettingsHelper();
await proxySettingsHelper.detectAndApplyProxySettings();
runApp(const MyApp());
}
動作の仕組みまとめ
Android
-
ConnectivityManager.defaultProxyでシステムプロキシを取得 - JVM のシステムプロパティ(
http.proxyHost/http.proxyPort)に設定 - MethodChannel 経由で Dart 側に
"host:port"を渡す -
HttpOverrides.globalにHttpProxyOverridesを設定 -
dart:ioのHttpClient(Dio・graphql_flutter 等)がプロキシを通る
iOS
-
CFNetworkCopySystemProxySettings()でプロキシ設定を取得 -
URLSessionConfiguration.default.connectionProxyDictionaryに設定 - MethodChannel 経由で Dart 側に
"host:port"を渡す -
HttpOverrides.globalにHttpProxyOverridesを設定
制限事項
PAC(自動プロキシ)には対応できない
CFNetworkCopySystemProxySettings() はプロキシの種別が「自動」の場合、
kCFNetworkProxiesHTTPProxy / Port を返さず、PAC ファイルの URL のみを返します。
そのため hasProxy() が false となり、プロキシは適用されません。
// PAC 設定時の CFNetworkCopySystemProxySettings() の返り値(例)
{
"ProxyAutoConfigEnable": 1,
"ProxyAutoConfigURLString": "http://192.168.1.1:8000/proxy.pac"
// HTTPProxy / HTTPPort は含まれない
}
PAC(自動プロキシ)への対応は cupertino_http パッケージを使った別のアプローチが必要です。
詳しくは関連記事「Flutter アプリで PAC ファイルベースの自動プロキシに対応する」を参照してください。
まとめ
| 項目 | Android | iOS |
|---|---|---|
| プロキシ検知 API | ConnectivityManager.defaultProxy |
CFNetworkCopySystemProxySettings() |
| 適用先(ネイティブ) | JVM システムプロパティ | URLSessionConfiguration.default |
| 適用先(Dart) | HttpOverrides.global |
HttpOverrides.global |
| 手動プロキシ対応 | ✅ | ✅ |
| PAC 自動プロキシ対応 | ✅(Android OS が解決) | ❌ |
Flutter アプリでプロキシ対応を実装する際の参考になれば幸いです。