SCAN_RESULTS_AVAILABLE_ACTION return lista vacía en Android 6.0

Ayer mi Nexus 5 recibió la actualización de Android MNC a la versión 6.0 - Marshmallow . Desde entonces, la acción de escanear las redes disponibles en el dispositivo deja de recibir la lista, en este caso la lista de resultados tiene un tamaño de 0, incluso con más de 10 redes Wifi enumeradas en la configuración del sistema Wifi.

El código para esto es el habitual: SCAN_RESULTS_AVAILABLE_ACTION y espere el evento en el receptor, así:

 // Register the Receiver in some part os fragment... getActivity().registerReceiver(wifiListener, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); WifiManager wifiManager = (WifiManager) getActivity().getSystemService(Context.WIFI_SERVICE); wifiManager.startScan(); // Inside the receiver: WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); List results = wifiManager.getScanResults(); // the result.size() is 0 after update to Android v6.0, same code working in older devices. 

Busqué en los cambios del tema API sobre esto, pero no vi ningún cambio importante para esta funcionalidad.

¿Alguien notó esto? ¿Hay algo nuevo en la API o solo un caso aislado?

A partir de Android 6.0, el comportamiento de permisos ha cambiado a tiempo de ejecución. Para usar una característica que requiere un permiso, primero debe verificar si el permiso se otorgó previamente. Con el checkSelfPermission(permissionString) se devuelve un resultado, ya sea que el permiso se PERMISSION_GRANTED o PERMISSION_DENIED .

Si no se concede permiso o es la primera vez, se debe realizar una solicitud de permiso. Dar a un usuario una opción para otorgar o denegar.

 if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){ requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION); //After this point you wait for callback in onRequestPermissionsResult(int, String[], int[]) overriden method }else{ getScanningResults(); //do something, permission was previously granted; or legacy device } 

Si su código se está ejecutando en el dispositivo antes de M, proceda con su código, el permiso fue otorgado usando el método heredado.

Una vez solicitado el permiso, el diálogo se mostrará al usuario. Su respuesta será entregada como:

 @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == PERMISSIONS_REQUEST_CODE_ACCESS_COARSE_LOCATION && grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Do something with granted permission mWifiListener.getScanningResults(); } } 

Después de eso, puede verificar si los Servicios de Ubicación están en ON, usando LocationServices.SettingsApi y solicite al usuario que lo habilite si esta opción está deshabilitada. Esto es posible con Play Services LocationSettingsStatusCodes.RESOLUTION_REQUIRED callback.

Encuentro un problema relacionado en el problema del rastreador de problemas AOSP 185370 WifiManager # getScanResults () devuelve una lista de arreglos vacía si el GPS está apagado.

El problema se menciona en el n . ° 1 : El móvil debe abrir el servicio de ubicación para obtener la lista wifi del móvil.

Y a partir del n . ° 18 , el miembro del proyecto de Android afirma que el equipo de desarrollo ha resuelto el problema que ha informado y que estará disponible en una comstackción futura.

La aplicación está en targetSdkVersion 23, simplemente siga la solución anterior para verificar el permiso de tiempo de ejecución. Aplicar para habilitar el problema de los servicios de localización se solucionará en la futura versión de Android.

Editar

Entonces, el problema parece ser con el nuevo manejo de permisos. Tienes que pedir permiso antes de seguir con el código wifi. Aquí hay un ejemplo:

 // call this method only if you are on 6.0 and up, otherwise call doGetWifi() private void getWifi() { if (checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 0x12345); } else { doGetWifi(); // the actual wifi scanning } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { if (requestCode == 0x12345) { for (int grantResult : grantResults) { if (grantResult != PackageManager.PERMISSION_GRANTED) { return; } } getWifi(); } } 

Esta verificación debe hacerse en una Actividad.

El código de muestra original está disponible aquí , modificado de acuerdo con el problema discutido en este tema.

Original

De acuerdo con los cambios vinculados de la API , su aplicación debe tener uno de los permisos de ubicación. Citar:

WifiManager.getScanResults (): su aplicación debe tener el permiso ACCESS_FINE_LOCATION o ACCESS_COARSE_LOCATION.

También tenga en cuenta que hay una nueva clave booleana recibida por su BroadcastReceiver en la acción EXTRA_RESULTS_UPDATED : EXTRA_RESULTS_UPDATED . Esto muestra si el escaneo está completo y puede acceder a los resultados llamando a wifiManager.getScanResults() .

Además de las respuestas dadas; también puede usar checkSelfPermission de ContextCompat para permitir la compatibilidad con versiones anteriores de Android:

 if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_CODE_ACCESS_FINE_LOCATION); // Get the result in onRequestPermissionsResult(int, String[], int[]) } else { // Permission was granted, do your stuff here }