No response received in startscan method at WifiMa

2019-03-29 08:27发布

问题:

According to official Android documentation, the method startScan at WifiManager is deprecated in API level P. However I am trying to use this method in API level 26 (previous to P) without success. I have developped an app which requires the scanning of the WiFi networks, if the user agree with the required permissions, and this behaviour is paramount for the appropriate functioning of the app. However I do not receive any response when calling the startScan method. ¿Can anyone help me to solve this problem or find an alternative solution?

This is a link to the documentation. https://developer.android.com/reference/android/net/wifi/WifiManager.html#startScan()

Cheers

EDIT:

This is the code to start de scannig process:

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

And this is the BroadcastReceiver that receives the result of the scan. It works except in Android 8 with 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); // Never called in Android 8 and 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<>();
      }
   }
}

In the Manifest we use the followint permissins and the BroadcastReceiver declared:

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

The location permission is required in runtime so I'm sure it is allowed. I'm also true that location is active (GPS level).

The BroadcastReceiver works fine because compiling with targetSdkVersion = 25 or less every works as expected and scans are received. I have also tested with android:exported="true" , but it doesn't have influence on the results.

I will grateful with your help.

回答1:

In Android 8 or higher the implicit BroadcastReceivers declared via Manifest are no longer send nor received due to performance reasons (this is an optimization introduced in Android 8 which limits background execution). There are some exceptions which are listed here, but android.net.wifi.SCAN_RESULTS action isn't an exception, so in Android 8+ you can't register a android.net.wifi.SCAN_RESULTS action to wait for ScanResults in the Manifest (actually you can, but you'll receive nothing).

This happens if your targetSdkVersion is 26 (Android 8 Oreo) or higher, but if you declare in your Gradle file a targetSdkVersion 25 or lower this optimization will not run for your app and your implicit Intents registered through Manifest will work as expected.

To get it work in Android 8 Oreo with a targetSdkVersion 26+ you have to register it through your Application Context.

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

But be aware, this kind of registration requires the app being running, so when your app is stopped you will not receive this BroadcastReceiver.

P.S: Your code is correct, but you didn't keep in mind this Android 8 limitation.