API de sugerencias de Wi-Fi para la conectividad a Internet

Los dispositivos que ejecutan Android 10 (nivel de API 29) y versiones posteriores permiten que tu app agregue credenciales de red para que un dispositivo se conecte automáticamente a un punto de acceso Wi-Fi. Puedes proporcionar sugerencias a qué red conectarte mediante WifiNetworkSuggestion. En última instancia, la plataforma elige qué punto de acceso aceptar en función de la entrada de tu app y de otras.

En Android 11 (nivel de API 30) y versiones posteriores, haz lo siguiente:

  • La API de sugerencias admite el aprovisionamiento de un PasspointConfiguration. En versiones anteriores a Android 11, para aprovisionar un PasspointConfiguration, se requiere el uso de la API de addOrUpdatePasspointConfiguration().
  • El framework aplica de manera forzosa los requisitos de seguridad de las sugerencias empresariales basadas en TLS (EAP-TLS, EAP-TTLS y EAP-PEAP); las sugerencias para esas redes deben establecer un Root CA certificate y un server domain name.
  • El framework aplica de manera forzosa los requisitos de propiedad para las sugerencias empresariales basadas en EAP-SIM (EAP-SIM, EAP-AKA, EAP-AKA-PRIME); solo las apps firmadas por el proveedor permiten estas sugerencias.
  • Para las sugerencias que proporciona una app firmada por el proveedor, el framework les asigna automáticamente un ID del operador que corresponde a la firma del proveedor de la app. Esas sugerencias se inhabilitan automáticamente si se quita la SIM correspondiente del dispositivo.

En Android 12 (nivel de API 31) y versiones posteriores, haz lo siguiente:

  • Se puede habilitar privacidad adicional mediante la aleatorización de MAC no persistente, que vuelve a aleatorizar periódicamente la dirección MAC aleatoria. Usa setMacRandomizationSetting para especificar el nivel de aleatorización de tu red.

  • isPasspointTermsAndConditionsSupported():Términos y condiciones es una función de Passpoint que permite que las implementaciones de redes reemplacen portales cautivos no seguros, que usan redes abiertas, por una red segura de Passpoint. Se le muestra una notificación al usuario cuando debe aceptar términos y condiciones. Las apps que sugieren redes de Passpoint que están restringidas por términos y condiciones deben llamar primero a esta API para asegurarse de que el dispositivo admita la función. Si el dispositivo no la admite, no podrá conectarse a esta red, y se sugerirá una red alternativa o heredada.

  • isDecoratedIdentitySupported(): Cuando te autenticas en redes extendidas con un prefijo, el prefijo con identidad extendido permite que los operadores de red actualicen el identificador de acceso a la red (NAI) para realizar el enrutamiento explícito a través de varios proxies dentro de una red AAA (consulta RFC 7542 para obtener más información al respecto).

    Android 12 implementa esta función a fin de cumplir con la especificación de WBA para extensiones PPS-MO. Las apps que sugieren redes de Passpoint que requieren una identidad extendida deben llamar primero a esta API para asegurarse de que el dispositivo admita la función. Si el dispositivo no la admite, la identidad no se extenderá, y es posible que falle la autenticación en la red.

Para crear una sugerencia de Passpoint, las apps deben usar las clases PasspointConfiguration, Credential y HomeSp. Estas clases describen el perfil de Passpoint, que se define en la especificación de Passpoint de Wi-Fi Alliance.

En la siguiente muestra de código, se indica cómo proporcionar credenciales para una red abierta, una WPA2, una WPA3 y una de Passpoint:

Kotlin

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

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

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

val passpointConfig = PasspointConfiguration(); // configure passpointConfig to include a valid Passpoint configuration
val suggestion4 = WifiNetworkSuggestion.Builder()
        .setPasspointConfig(passpointConfig)
        .setIsAppInteractionRequired(true) // Optional (Needs location permission)
        .build();

val suggestionsList = listOf(suggestion1, suggestion2, suggestion3, suggestion4);

val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager;

val 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)
val intentFilter = IntentFilter(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION);

val broadcastReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (!intent.action.equals(WifiManager.ACTION_WIFI_NETWORK_SUGGESTION_POST_CONNECTION)) {
            return;
        }
        // do post connect processing here
    }
};
context.registerReceiver(broadcastReceiver, intentFilter);

Java

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);

Inmediatamente después de que la app realiza una sugerencia por primera vez, se notifica al usuario. El tipo de notificación depende de la versión de Android que se ejecute en el dispositivo:

  • En Android 11 (nivel de API 30) y versiones posteriores, el usuario ve un diálogo si la app se está ejecutando en primer plano y una notificación si se está ejecutando en segundo plano.
  • En Android 10 (nivel de API 29), el usuario ve una notificación, independientemente de si la app se ejecuta en primer o segundo plano.

Cuando la plataforma se conecta a una de las sugerencias de red, la configuración muestra un texto que atribuye la conexión de red a la app que realizó la sugerencia correspondiente.

Cómo administrar desconexiones del usuario

Si el usuario utiliza el selector de Wi-Fi para desconectarse explícitamente de una de las sugerencias de red cuando se conecta a ella, se ignora esa red cuando aún está dentro del alcance. Durante este período, no se considerará esa red para la conexión automática, incluso si la app quita y vuelve a agregar la sugerencia de red correspondiente. Si el usuario usa el selector de Wi-Fi para conectarse de forma explícita a una red que se desconectó previamente, se considerará esa red para la conexión automática de inmediato.

Cómo cambiar el estado de autorización para una app

Un usuario que rechaza la notificación de sugerencia de red quita el permiso CHANGE_WIFI_STATE de la app. El usuario puede otorgar esta aprobación más adelante desde el menú de control de Wi-Fi (Configuración > Apps y notificaciones > Acceso especial de apps > Control de Wi-Fi > App name).