LoginSignup
2
2

【Flutter】Androidでhttp通信を許可する方法

Last updated at Posted at 2024-04-30

はじめに

開発の段階ではdev環境のサーバーを用意して、そこに対してAPIを投げて通信するのが一般的だと思います。
しかし今の現場でバックエンドとフロントエンドで繋ぎこみを行う際に、
まずはフロントエンドのローカル環境で試して成功を確認→サーバーにデプロイすることとなりました。
この時にhttp通信となるのですが、Androidでは次のエラーが出て上手くいきませんでした。

Error: SocketException: Connection refused (OS Error: Connection refused, 
errno = 111), address = localhost, port = 52604

結果的にこのエラーを解消して無事にhttp通信を許可させることができましたので、
その方法をまとめてみたいと思います。

筆者の経歴

  • UIKitでのiOSアプリケーション開発の学習9ヶ月
  • SwiftUIでのiOSアプリケーション開発学習4ヶ月
  • Flutterでのモバイルアプリケーション開発3ヶ月

記事の対象者

  • Androidでhttp通信ができずに悩まれている方

記事を執筆時点での筆者の環境

  • macOS 14.3.1
  • Xcode 15.2
  • Swift 5.9
  • iPhone11 pro ⇒ iOS 17.2.1
  • Flutter 3.19.0
  • Dart 3.3.0
  • Pixel 7a ⇒ Android 14

1. 実装の概要

ローカル環境でhttp通信を行いAPIの接続テストを行う場合には設定が必要でした。
iOSは設定しないでも繋がりました。(もしかしたら現場の先輩が設定しているのかも?)
Androidでは対応が必要です。

以下がその対応内容です。

  1. エミュレーターのwifi設定からゲートウェイの値を確認
  2. Androidマニフェストに追記
  3. network_security_config.xml の作成
  4. httpクライアントの接続先をOSごとに分岐

2. エミュレーターのwifi設定からゲートウェイの値を確認

エミュレーターの設定アプリ >> インターネット >> ネットワークとインターネット

Androidでhttp通信を許可する方法 .001.png

AndroidWifi >> 画面を下にスクロールしてゲートウェイの値を控えておきます。
おそらくここの値はどのエミュレーターでも10.0.2.2で固定の数値だと思います。
違かった場合でもその値を使えばいいので大丈夫です。

Androidでhttp通信を許可する方法 .002.png

3. Androidマニフェストに追記

今回はFlavorなどで環境を分けている前提で書きます。
あくまで開発する時だけhttp通信を許可したいだけなので、
mainの方のマニフェストではなくdevのAndroidマニフェストに書きます。

スクリーンショット 2024-04-30 22.48.35.png

追記するのは<application android:networkSecurityConfig="@xml/network_security_config">の部分です。

AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>
<!-- 以下を追加 -->
	<application android:networkSecurityConfig="@xml/network_security_config">
  </application>
</manifest>

4. network_security_config.xml の作成

resディレクトリの配下にxmlディレクトリを作ります。
そしてその中にnetwork_security_config.xmlファイル を作ります。
スクリーンショット 2024-04-30 22.59.26.png

network_security_config.xml
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

5. httpクライアントの接続先を分岐させる

flavorのdevで開発していてもさらにサーバーはdevサーバーなのか、ローカル環境のサーバーなのかで切り替えなければいけません。
ここがちょっとややこしいですね💦

flavorでは以下の3つの環境を作ります。

  • dev => デベロップ、開発環境
  • stg => ステージング、テストで配布する時
  • prot => プロダクト、製品版、本番環境

なので、通信してデータを保存したりとってきたりするサーバーも上記のように分けておいきます。
そして各環境によって接続する先を別々に紐づけておくことで、開発中に誤ってユーザーが使っている正規のサーバーのデータを書き換えるリスクを防止したりします。

ただ今回はさらにローカル環境に繋げなければいけません。

ローカル環境をざっくりいうと、dockerを使って自分のPCにサーバーを作ることです。
大抵はバックエンドの方が作ったソースコードをGithubなどから自分のPCに落としてきて
それをdockerで実行して構築する流れです。

まとめると、flavorのdevモードの時にサーバー通信とローカル通信で分けておきたいということです。

今回はflavorの各種設定が終わってる前提で話しています。
flavorによる開発環境と本番環境を分けるための設定方法は割愛します。

5-1.DartDefineを使って環境変数を作る

まずflavorは一旦おいておいて、ローカル通信のフラグを設定します。

define.dart
class Define {
  const Define({required this.isLocal});

  static Define instance = const Define(
    isLocal: bool.fromEnvironment('isLocal'),
  );

  final bool isLocal;
}

5-2. launch.jsonに設定を追加

先に述べたようにflavorのdevモードの時にローカル通信を行うモードを
debug-dev-isLocalとして追記します。

launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "debug-dev",
            "request": "launch",
            "type": "dart",
            "program": "lib/main_dev.dart",
            "env": {
                "FLAVOR": "dev"
            },
            "args": [
                "--debug",
                "--flavor",
                "dev",
                "--dart-define=FLAVOR=dev",
            ],
        },
        ///
        /// ここから追加
        ///
        {
            "name": "debug-dev-isLocal",
            "request": "launch",
            "type": "dart",
            "program": "lib/main_dev.dart",
            "env": {
                "FLAVOR": "dev"
            },
            "args": [
                "--debug",
                "--flavor",
                "dev",
                "--dart-define=FLAVOR=dev",
                "--dart-define=isLocal=true",
            ],
        },
        ///
        /// ここまで
        ///
        {
            "name": "debug-stg",
            "request": "launch",
            "type": "dart",
            "program": "lib/main_stg.dart",
            "env": {
                "FLAVOR": "stg"
            },
            "args": [
                "--debug",
                "--flavor",
                "stg",
                "--dart-define=FLAVOR=stg",
            ],
        },
        {
            "name": "debug-prod",
            "request": "launch",
            "type": "dart",
            "program": "lib/main_prod.dart",
            "env": {
                "FLAVOR": "prod"
            },
            "args": [
                "--debug",
                "--flavor",
                "prod",
                "--dart-define=FLAVOR=prod",
            ],
        },
    ]
}

5-3. httpクライアントで通信する際の接続先を分ける

今回はriverpodを使ってhttpクライアントのパッケージであるdioのインスタンスを渡す設計になってます。

以下のコード内のコメントのようにAPIリクエストを送信する接続先を3つのパターンで分けています。

  1. ローカル通信でiOSの場合
  2. ローカル通信のAndroidの場合
  3. それ以外、すなわちオンラインのサーバーに接続する場合でOSは問わない

ここで気になるのはローカル通信でOSごとに接続先を変えていることです。
本来はローカルで一つのパターンにしたいところです。
しかしAndroidに限ってはwifi接続の出入り口を指定しないとローカルにつながってくれません。

http.dart
@Riverpod(keepAlive: true)
Dio http(HttpRef ref) {
    // switchの条件はサーバーがローカルか否かとOSがiOSか否か(否はAndroidを想定) 
  final baseUrl = switch ((Define.instance.isLocal, Platform.isIOS)) {
	  // ローカル通信のiOS
    (true, true) => 'http://localhost',
    // ローカル通信のAndroid
    // エミュレーターのゲートウェイを xx.x.x.x に入力
    (true, false) => 'http://xx.x.x.x',
    // 通常の接続先
    _ => 'https://hogehoge-api',
  };
  return Dio(
    BaseOptions(
      baseUrl: baseUrl,
      listFormat: ListFormat.csv,
    ),
  ),
}

ここでAndroidの場合の接続先xx.x.x.xの部分は
「2. エミュレーターのwifi設定からゲートウェイの値を確認」で控えておいたゲートウェイの値を指定します。

6. 完了

お疲れ様でした。
あとはデバック実行する際にモードをdebug-dev-isLocalにすればAndroidのエミュレータでhttp通信を行うことが可能です。

終わりに

いかがだったでしょうか。
今回の実装を行う上でさまざまな記事を見たのですがなかなか上手くできませんでした。
最終的には先輩に教えて頂いた記事を参考になんとか実装することができました。
初学者にとってはなかなか内容が小難しいのですが、理解してしまえば割と簡単に実装できます。

この記事が誰かのお役に立てれば幸いです。

参考記事

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2