[この記事は Rich Hyndman、Android デベロッパー アドボケートによる Android Developers Blog の記事 "Connecting your App to a Wi-Fi Device" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。]

IoT の成長に伴い、Android アプリケーションを Wi-Fi 対応デバイスに接続することがますます一般的になっています。ビュー ファインダーのアプリを構築している場合でも、ネットワークに接続された電球を準備しようとしている場合でも、あるいはクアッドコプターを操作しようとしている場合でも、そういったデバイスが Wi-Fi ベースであれば、インターネットにはつながっていないアクセス ポイントに接続する必要があります。

Lollipop 以降、Android OS は少し賢くなり、複数のネットワークに接続してインターネットにつながっていないネットワークにはデータをルーティングしないようになっています。この便利な機能によって、インターネットにつながっていない ポータルがある Wi-Fi の近くでも接続が失われなくなります。デベロッパーはデータ ルーティング API を利用して、適切なアプリのトラフィックだけを Wi-Fi 接続を介して外部デバイスにルーティングできます。

この API を理解するために、3 種類のネットワークの一覧が利用できることを知っておくとよいでしょう。
  • WiFiManager#startScan は、利用可能な Wi-Fi ネットワークの一覧を返します。ネットワークは、主に SSID で区別します。
  • WiFiManager#getConfiguredNetworks は、現在利用可能でないものも含め、端末に設定されている Wi-Fi ネットワークの一覧を返します。このリストも SSID で識別できます。
  • ConnectivityManager#getAllNetworks は、携帯端末がデータをやり取りしているネットワークの一覧を返します。Lollipop 以降、端末は Wi-Fi、LTE、Bluetooth などの複数のネットワークに同時に接続されている可能性があるため、この機能が必要になります。それぞれのネットワークの現在の状態は、ConnectivityManager#getNetworkInfo を呼び出すとわかります。これらはネットワーク ID で識別します。
Android のすべてのバージョンで、WiFiManager#startScan を使って利用可能な Wi-Fi ネットワークのスキャンを開始し、ScanResults に対して反復処理を行って目的の外部 Wi-Fi デバイスの SSID を探すことができます。目的の SSID を見つけたら、WifiManager#getConfiguredNetworks から返された WifiConfigurations に対して反復処理を行い、SSID を照合して設定済みのネットワークかどうかを確認します。その際に、設定済みのネットワークの SSID はダブルクォートでくくられていますが、ScanResults で返される SSID にはダブルクォートがついていない点に注意してください。

ネットワークが設定済みの場合は、WifiConfiguration オブジェクトからネットワーク ID を取得できます。そうでない場合は、WifiManager#addNetwork を使って設定を行い、返されるネットワーク ID を覚えておくようにします。

Wi-Fi ネットワークに接続するには、WifiManager.NETWORK_STATE_CHANGED_ACTION を待ち受ける BroadcastReceiver を登録し、ネットワーク ID を渡して WifiManager.enableNetwork (int netId, boolean disableOthers) を呼び出します。enableNetwork を呼び出すと、次のスキャンの準備のために他の Wi-Fi アクセス ポイントはすべて無効になり、リクエストしたアクセス ポイントが検索されてそこに接続されます。ネットワーク ブロードキャストを受信すると、WifiManager#getConnectionInfo を使って正しいネットワークにうまく接続できたかを確認できます。ただし、Lollipop 以降では、そのネットワークにインターネット接続がない場合、リクエストはルーティングされません。

ネットワーク リクエストのルーティング

アプリからのすべてのネットワーク リクエストを外部 Wi-Fi デバイスに向けるには、Lollipop 端末では ConnectivityManager#setProcessDefaultNetwork を呼び出します。Marshmallow 端末では、後継 API である ConnectivityManager#bindProcessToNetwork を呼び出します。これらの呼び出しには、android.permission.INTERNET が必要です。このパーミッションがない場合は、false が返されるだけです。

アプリのトラフィックの一部だけを Wi-Fi デバイスにルーティングし、その他をモバイル ネットワーク経由でインターネットにルーティングしたい場合は、次のようにします。

本記事で説明した方法を使うと、ユーザーがあなたの画期的な Wi-Fi 対応製品を利用する際にインターネット接続を維持したままでのユーザー体験を提供することができます。

Posted by Takeshi Hagikura - Developer Relations Team