API Android per connettersi alla rete Wi-Fi

Sep 14 2020

Sono completamente perso nelle versioni delle API WiFi. Voglio connettermi a una rete WiFi configurata in modo programmatico. Come descritto in questa domanda: connettersi alla rete Wi-Fi Android in modo programmatico

Sviluppo su Android 10 e voglio scrivere un codice compatibile anche con le versioni precedenti di Android.

Sul mio Android 10 il codice descritto non funziona. Di quale codice ho bisogno per implementare la funzionalità su Android 10?

Cosa devo fare per scrivere un'applicazione che gira anche sull'altro mio telefono Android 9?

Saluti Jürgen

Risposte

matdev Sep 14 2020 at 13:06

Ecco una soluzione che funziona da Android 6 (livello API 23)

String AP_SSID = "YourWifiNetworkSSID";
String AP_PASSWORD = "YourWifiNetworkPassword";
wifiManager = (WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE);

WifiConfiguration conf = new WifiConfiguration();
conf.SSID = "\"" + AP_SSID + "\"";   // Please note the quotes. String should contain ssid in quotes

conf.preSharedKey = "\"" + AP_PASSWORD + "\"";

wifiManager.addNetwork(conf);

try {
    List<WifiConfiguration> list = wifiManager.getConfiguredNetworks();

    for (WifiConfiguration i : list) {
        if (i.SSID != null && i.SSID.equals("\"" + AP_SSID + "\"")) {
            wifiManager.disconnect();
            wifiManager.enableNetwork(i.networkId, true);
            wifiManager.reconnect();

            break;
        }
    }
 } catch (SecurityException e) {
     Log.e(TAG, e.getMessage()); 
 }
MdImtiazHossain Nov 18 2020 at 09:17

Da Android Q, la connessione alla rete Wifi ha subito molti cambiamenti.

Prima di tutto il codice che stai utilizzando o @matdev menzionato usa l'API public int addNetwork (WifiConfiguration config)di WifiManagerAndroid 10 è deprecato e restituirà -1 come networkID.

Da Android Q, vengono suggerite due classi per la connessione Wifi. Ma ognuno di loro ha i suoi vantaggi e svantaggi.

1. WifiNetworkSpecifier

Un esempio di codice da WifiUtil Library

WifiNetworkSpecifier.Builder wifiNetworkSpecifierBuilder = new WifiNetworkSpecifier.Builder()
            .setSsid(scanResult.SSID)
            .setBssid(MacAddress.fromString(scanResult.BSSID));

    final String security = ConfigSecurities.getSecurity(scanResult);

    ConfigSecurities.setupWifiNetworkSpecifierSecurities(wifiNetworkSpecifierBuilder, security, password);


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

    // not sure, if this is needed
    if (networkCallback != null) {
        connectivityManager.unregisterNetworkCallback(networkCallback);
    }

    networkCallback = new ConnectivityManager.NetworkCallback() {
        @Override
        public void onAvailable(@NonNull Network network) {
            super.onAvailable(network);

            wifiLog("AndroidQ+ connected to wifi ");

            // bind so all api calls are performed over this new network
            connectivityManager.bindProcessToNetwork(network);
        }

        @Override
        public void onUnavailable() {
            super.onUnavailable();

            wifiLog("AndroidQ+ could not connect to wifi");
        }
    };

    connectivityManager.requestNetwork(networkRequest, networkCallback);

La mia osservazione con questa implementazione è: è più simile alla comunicazione P2P e in questo momento altre applicazioni dello stesso dispositivo non possono utilizzare Internet dalla rete WiFi connessa

2. WifiNetworkSuggestion 

Un esempio di codice da developer.android.com

final WifiNetworkSuggestion suggestion1 =
  new WifiNetworkSuggestion.Builder()
  .setSsid("test111111")
  .setIsAppInteractionRequired(true) // Optional (Needs location permission)
  .build();

final WifiNetworkSuggestion suggestion2 =
  new WifiNetworkSuggestion.Builder()
  .setSsid("test222222")
  .setWpa2Passphrase("test123456")
  .setIsAppInteractionRequired(true) // Optional (Needs location permission)
  .build();

final WifiNetworkSuggestion suggestion3 =
  new WifiNetworkSuggestion.Builder()
  .setSsid("test333333")
  .setWpa3Passphrase("test6789")
  .setIsAppInteractionRequired(true) // Optional (Needs location permission)
  .build();

final PasspointConfiguration passpointConfig = new PasspointConfiguration();
// configure passpointConfig to include a valid Passpoint configuration

final WifiNetworkSuggestion suggestion4 =
  new WifiNetworkSuggestion.Builder()
  .setPasspointConfig(passpointConfig)
  .setIsAppInteractionRequired(true) // Optional (Needs location permission)
  .build();

final List<WifiNetworkSuggestion> suggestionsList =
  new ArrayList<WifiNetworkSuggestion> {{
    add(suggestion1);
    add(suggestion2);
    add(suggestion3);
    add(suggestion4);
  }};

final WifiManager wifiManager =
  (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

final int status = wifiManager.addNetworkSuggestions(suggestionsList);
if (status != WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS) {
// do error handling here…
}

// Optional (Wait for post connection broadcast to one of your suggestions)
final IntentFilter intentFilter =
  new IntentFilter(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION);

final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
  @Override
  public void onReceive(Context context, Intent intent) {
    if (!intent.getAction().equals(
      WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) {
      return;
    }
    // do post connect processing here...
  }
};
context.registerReceiver(broadcastReceiver, intentFilter);

La mia osservazione con l'implementazione sopra menzionata è che quando chiami wifiManager.addNetworkSuggestionsrestituisce successo e mostri all'utente una notifica per la connessione. Se l'utente accetta, il dispositivo si connette alla rete WiFi e altre app possono utilizzare Internet. Ma se l'utente si disconnette dalla rete e si chiama di wifiManager.addNetworkSuggestionsnuovo, verrà restituito un WifiManager.STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATEerrore.

Sembra che questa API fornisca solo un elenco di suggerimenti di reti in cui il dispositivo può connettersi automaticamente. Ma la connessione sarà determinata dal sistema operativo.

Ma se hai davvero bisogno di una soluzione, un modo non documentato utilizza lo scanner di codici QR Wifi predefinito da Android Source in grado di rilevare sia gli schemi di codice QR Zxing che DPP.

ecco un esempio di codice:

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if(requestCode == REQUEST_CODE_WIFI_QR_SCANNER && resultCode == RESULT_OK)
    {
        //WIFI Connection is Successful
    }
    else
    {
        //.......
    }
}

@RequiresApi(api = Build.VERSION_CODES.Q)
private void startWifiQRCodeScanner(Context context)
{
    final String INTENT_ACTION_WIFI_QR_SCANNER = "android.settings.WIFI_DPP_ENROLLEE_QR_CODE_SCANNER";
    WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

    if(wifiManager.isEasyConnectSupported())
    {
        final Intent intent = new Intent(INTENT_ACTION_WIFI_QR_SCANNER);
        startActivityForResult(intent, REQUEST_CODE_WIFI_QR_SCANNER);
    }
}