Android 8 Oreo 中 WifiManager 的 startscan 方法未收到响应
No response received in startscan method at WifiManager in Android 8 Oreo
根据官方 Android 文档,WifiManager 的 startScan 方法在 API 级别 P 中已弃用。但是我试图在 API 级别 26(之前P) 没有成功。我开发了一个应用程序,如果用户同意所需的权限,则需要扫描 WiFi 网络,并且此行为对于应用程序的正常运行至关重要。但是,调用 startScan 方法时我没有收到任何响应。 ¿谁能帮我解决这个问题或找到替代解决方案?
这是对文档的 link。
https://developer.android.com/reference/android/net/wifi/WifiManager.html#startScan()
干杯
编辑:
这是启动反扫描过程的代码:
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;
}
这是接收扫描结果的BroadcastReceiver。它适用于 Android 8 和 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<>();
}
}
}
在 Manifest 中我们使用 followint permissins 和声明的 BroadcastReceiver:
<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>
运行时需要位置权限,所以我确定它是允许的。我也确信位置处于活动状态(GPS 级别)。
BroadcastReceiver 工作正常,因为使用 targetSdkVersion = 25 或更低进行编译时,每次都按预期工作并收到扫描。我也用 android:exported="true" 测试过,但它对结果没有影响。
感谢您的帮助。
在 Android 8 或更高版本中,由于性能原因,不再发送或接收通过 Manifest
声明的隐式 BroadcastReceivers
(这是 Android 8
中引入的优化)这限制了 background execution). There are some exceptions which are listed here,但是 android.net.wifi.SCAN_RESULTS
操作也不例外,所以在 Android 8+ 中你不能注册一个 android.net.wifi.SCAN_RESULTS
操作来等待 ScanResults
在 Manifest
(实际上你可以,但你什么也得不到)。
如果您的 targetSdkVersion
为 26 (Android 8 Oreo
) 或更高,则会发生这种情况,但如果您在 Gradle
文件中声明 targetSdkVersion
25 或更低,则此优化将不是 运行 对于您的应用程序,您通过 Manifest
注册的隐式 Intents
将按预期工作。
要在 Android 8 Oreo
中使用 targetSdkVersion
26+,您必须通过 Application Context
.
注册它
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.wifi.SCAN_RESULTS");
context.registerReceiver(new InOutWifiScanResultsReceiver(), intentFilter);
但是请注意,这种注册需要应用程序处于 运行ning 状态,因此当您的应用程序停止时,您将不会收到此 BroadcastReceiver
.
P.S: 你的代码是正确的,但是你没有记住这个Android 8
限制。
根据官方 Android 文档,WifiManager 的 startScan 方法在 API 级别 P 中已弃用。但是我试图在 API 级别 26(之前P) 没有成功。我开发了一个应用程序,如果用户同意所需的权限,则需要扫描 WiFi 网络,并且此行为对于应用程序的正常运行至关重要。但是,调用 startScan 方法时我没有收到任何响应。 ¿谁能帮我解决这个问题或找到替代解决方案?
这是对文档的 link。 https://developer.android.com/reference/android/net/wifi/WifiManager.html#startScan()
干杯
编辑:
这是启动反扫描过程的代码:
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;
}
这是接收扫描结果的BroadcastReceiver。它适用于 Android 8 和 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<>();
}
}
}
在 Manifest 中我们使用 followint permissins 和声明的 BroadcastReceiver:
<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>
运行时需要位置权限,所以我确定它是允许的。我也确信位置处于活动状态(GPS 级别)。
BroadcastReceiver 工作正常,因为使用 targetSdkVersion = 25 或更低进行编译时,每次都按预期工作并收到扫描。我也用 android:exported="true" 测试过,但它对结果没有影响。
感谢您的帮助。
在 Android 8 或更高版本中,由于性能原因,不再发送或接收通过 Manifest
声明的隐式 BroadcastReceivers
(这是 Android 8
中引入的优化)这限制了 background execution). There are some exceptions which are listed here,但是 android.net.wifi.SCAN_RESULTS
操作也不例外,所以在 Android 8+ 中你不能注册一个 android.net.wifi.SCAN_RESULTS
操作来等待 ScanResults
在 Manifest
(实际上你可以,但你什么也得不到)。
如果您的 targetSdkVersion
为 26 (Android 8 Oreo
) 或更高,则会发生这种情况,但如果您在 Gradle
文件中声明 targetSdkVersion
25 或更低,则此优化将不是 运行 对于您的应用程序,您通过 Manifest
注册的隐式 Intents
将按预期工作。
要在 Android 8 Oreo
中使用 targetSdkVersion
26+,您必须通过 Application Context
.
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.wifi.SCAN_RESULTS");
context.registerReceiver(new InOutWifiScanResultsReceiver(), intentFilter);
但是请注意,这种注册需要应用程序处于 运行ning 状态,因此当您的应用程序停止时,您将不会收到此 BroadcastReceiver
.
P.S: 你的代码是正确的,但是你没有记住这个Android 8
限制。