【Android】Android 10以降で特定のWi-Fiに自動接続する(WifiNetworkSpecifierの実装)

Android

普段、M5StackをWi-Fiルーター(アクセスポイント)として実験を行っています。毎回設定画面からWi-Fiを切り替えるのは手間なので、アプリ内から指定のSSIDへ自動接続する機能を実装しました。

必要なパーミッション

Android 10以降でWi-Fi接続を制御するには、位置情報の権限が必要です。AndroidManifest.xmlに以下を追記します。

<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>

Wi-Fi接続の実装

Android 10 (API 29) から導入された WifiNetworkSpecifier を使用します。これにより、OSのWi-Fi設定を汚さずに、アプリが動作している間だけ特定のWi-Fiを利用することが可能です。

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.wifi.WifiNetworkSpecifier;
import android.net.ConnectivityManager;
import android.os.Build;
import android.os.Bundle;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;

@RequiresApi(api = Build.VERSION_CODES.Q)
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, 1);
        } else {
            connectToWifi("yourSSID", "yourPassword");
        }
    }

    private void connectToWifi(String ssid, String password) {
        WifiNetworkSpecifier wifiNetworkSpecifier = new WifiNetworkSpecifier.Builder()
                .setSsid(ssid)
                .setWpa2Passphrase(password)
                .build();

        NetworkRequest networkRequest = new NetworkRequest.Builder()
                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
                .setNetworkSpecifier(wifiNetworkSpecifier)
                .build();

        ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        connectivityManager.requestNetwork(networkRequest, new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(android.net.Network network) {
                super.onAvailable(network);
                connectivityManager.bindProcessToNetwork(network);
                runOnUiThread(() -> Toast.makeText(MainActivity.this, "Connected to " + ssid, Toast.LENGTH_SHORT).show());
            }

            @Override
            public void onUnavailable() {
                super.onUnavailable();
                runOnUiThread(() -> Toast.makeText(MainActivity.this, "Failed to connect to " + ssid, Toast.LENGTH_SHORT).show());
            }
        });
    }
}

このコードでは、WifiNetworkSpecifierを使用してWiFiネットワークに接続し、ConnectivityManagerを使用して接続を管理します。onAvailableメソッドとonUnavailableメソッドをオーバーライドして、接続が成功したかどうかを確認できます。

実装のポイント

  • WifiNetworkSpecifier: SSIDとパスワードを指定して「このネットワークを使いたい」というリクエストを作成します。
  • requestNetwork: 実行すると、OS標準の接続確認ダイアログが表示されます。ユーザーが許可すると接続が開始されます。
  • bindProcessToNetwork: ここが重要です。 これを行うことで、アプリ内のHTTPリクエストなどが強制的にこのWi-Fiを経由するようになります。

コメント