3

Estoy trabajando en una aplicación que utiliza los escaneos WiFi para funcionar. Utilizo el método startScan() de la clase WifiManager y tengo programado un BroadcastReceiver para que se me notifique cuando el escaneo ha terminado y ya se pueden recoger los resultados.

El código que tengo funciona perfectamente en Android 7 e inferiores, e incluso funciona en Android 8 si configuro el targetSdkVersion a 25 (Android 7) o inferior.

El problema surge cuando subo el targetSdkVersion a 26 y ejecuto la aplicación en Android 8 (concretamente en un Nexus 5X), y es que los escaneos WiFi dejan de ser recibidos. Por mucho que yo ejecute startScan() nunca obtengo resultados. Repito, si bajo el targetSdkVersiona 25, vuelvo a recibir los resultados sin problemas.

Leyendo la documentación oficial de Android, indica que a partir de Android 8 los esacneos se ejecutarán con mucha menos frecuencia, pero se entiende que deben funcionar de igual manera. Incluso en Android P esta llamada está obsoleta.

Entiendo que en Android P no podré utilizar este método, pero en Android 8 sí, y sin embargo no funciona.

Dejo la documentación de startScan() por si hiciera falta: Documentación

Alguien sabe el porqué de este comportamiento o a alguien le pasa lo mismo?

EDITO:

Este es el código que inicia los escaneos:

public boolean startScan() {
   WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
   if (!wm.isWifiEnabled()) {
     try {
       wm.setWifiEnabled(true);
     } catch (SecurityException e) {
       Log.w(LOG_TAG, "Error enabling wifi", e);
       return false;
     }
   }
   boolean started = wm.startScan();
   Log.d(LOG_TAG, "Scan started? " + started);
   return started;
}

Este es el BroadcastReceiver que recibe el resultado de los escaneos (y funciona excepto en Android 8 con targetSdkVersion 26+):

public class InOutWifiScanResultsReceiver extends BroadcastReceiver {
   private static final String LOG_TAG = "ScanResults";

   @Override
   public void onReceive(Context context, Intent intent) {
     super.onReceive(context, intent); // Nunca entra aquí con Android 8 y targetSdkVersion 26+
     List<ScanResult> results = getWifiResults(context);
     Log.d(LOG_TAG, "Received results (" +  results.size() + " AP's)");
   }

   private static List<ScanResult> getWifiResults(Context context) {
      WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
      try {
        return wm.getScanResults();
      } catch (SecurityException e) {
        return new ArrayList<>();
      }
   }
}

En el Manifest tengo los siguientes permisos y el BroadcastReceiver declarado:

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

 <receiver
    android:name=".InOutWifiScanResultsReceiver"
    android:exported="false">
    <intent-filter>
        <action android:name="android.net.wifi.SCAN_RESULTS"/>
    </intent-filter>
 </receiver>

El permiso de localización se pide en runtime por lo que estoy seguro de que se permite, ya que soy yo el que hace los tests. También me he asegurado de que la localización esté activada (está en máxima precisión (gps + netword)).

El BroadcastReceiver parece que está declarado porque funciona si el targetSdkVersion es 25 o inferior. También he probado ponerle android:exported="true" por si tuviera algo que ver, pero parece ser que no.

Agradezco toda ayuda.

Marc Estrada
  • 135
  • 5
  • Por otra parte, me hubiera gustado poner las etiquetas android-wifi, android-8 y android-wifimanager – Marc Estrada May 21 '18 at 12:05
  • Cual es el código que estas tratando, porqu eno lo agregas? @MarcEstrada – Jorgesys May 21 '18 at 17:01
  • No lo he agregado porque es código básico extraído de la documentación y que funciona en todos los dispositivos excepto en Android 8. Al llegar a casa os lo pongo, a ver si veis algo que yo no esté viendo. Gracias por la ayuda – Marc Estrada May 21 '18 at 18:05
  • ¿Tienes los permisos de geolocalización activados en ese dispositivo? https://es.stackoverflow.com/questions/70824/problema-al-escanear-redes-wifi-en-android/70841#70841 – Jorgesys May 21 '18 at 18:49
  • Sí, los tengo, activados y concedidos, porque la app se basa en la localización. También tengo la Ubicación del móvil activada como sugieren otras respuestas de SO, pero tampoco funciona. – Marc Estrada May 22 '18 at 06:25
  • @Jorgesys nadie tiene idea de esto? – Marc Estrada May 28 '18 at 07:57

1 Answers1

3

En Android 8 o superior los BroadcastRecivers implícitos declarados vía Manifest no envían ni reciben información por motivos de rendimiento y consumo de batería, se trata de una optiización introducida en Android 8 y que intenta limitar los trabajos que se ejecutan en segundo plano.

Hay algunas excepciones a esto (excecpciones), pero la acción android.net.wifi.SCAN_RESULTS por desgracia no es una de esas excepciones, así que en Android 8+ no se pueden registrar el android.net.wifi.SCAN_RESULTS vía Manifest ya que no se recibirá nada.

Esto ocurre cuando usamos targetSdkVersion=26 (Android 8 Oreo) o superior,pero si declarar en Gradle un targetSdkVersion=25 o inferior la optimización no se aplicaría y la app funcionaría como era esperado hasta hoy en día .

Para hacer que esta funcionalidad devuelva los resultados esperados en Android 8 con targetSdkVersion 26+ hay que registrar la acción en el contexto de la aplicación.

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.wifi.SCAN_RESULTS");
context.registerReceiver(new InOutWifiScanResultsReceiver(), intentFilter);

Lo único es que hay que ser cuidadosos con esto, ya que sólo funciona cuando la app está en primer plano y no cuando está detenida.

Saludos,

Marc Estrada
  • 135
  • 5
Antonio
  • 46
  • 3