SCAN_RESULTS_AVAILABLE_ACTION 在 Android 6.0 中返回空列表

Posted

技术标签:

【中文标题】SCAN_RESULTS_AVAILABLE_ACTION 在 Android 6.0 中返回空列表【英文标题】:SCAN_RESULTS_AVAILABLE_ACTION return empty list in Android 6.0 【发布时间】:2015-11-16 01:33:03 【问题描述】:

昨天我的 Nexus 5 收到了从 android MNC 到版本 6.0 - Marshmallow 的更新。 从那时起,扫描设备中可用网络的操作停止接收列表,在这种情况下,结果列表的大小为 0,即使 Wifi 系统设置中列出了 10 多个 Wifi 网络。

这个代码是通常的:注册SCAN_RESULTS_AVAILABLE_ACTION并在接收器中等待事件,像这样:

// 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<ScanResult> results = wifiManager.getScanResults();
// the result.size() is 0 after update to Android v6.0, same code working in older devices.

我在changes of the API 主题中搜索了关于此的内容,但我没有看到此功能的任何重大更改。

有人注意到了吗? API 中有什么新东西还是只是一个孤立的案例?

【问题讨论】:

您的 N5 是否启用了允许 Wi-Fi 扫描选项?消灭嫌疑人。 Wifi &gt; Advanced我只看到Network NotificationKeep Wifi...选项,出现在这两个之间的Scanning选项似乎在这个版本中没有了。 当它第一次到达该代码以授予位置服务权限时,您是否看到弹出一个对话框?我打赌 M,你应该会看到这样的对话框。见developer.android.com/reference/android/app/…, int) 是的!在另一个应用程序中,我曾经调用此对话框来强制激活位置设置,通常当我使用地图时,当然,当我将位置用于地图和类似的东西时,这是相同的用例,即使没有一张地图。该对话框不是自动的,它需要从播放服务响应中调用,这让我完全忘记了它。请用这个特别的建议回答这个问题。 @debihiga 你看到这个“重复”的日期了吗?我在 6 个月前发布了这个问题。 【参考方案1】:

从 Android 6.0 开始,权限行为已更改为运行时。要使用需要权限的功能,应首先检查之前是否已授予权限。使用checkSelfPermission(permissionString)method返回结果,权限为PERMISSION_GRANTEDPERMISSION_DENIED

如果未授予许可或这是第一次,则应提出许可请求。为用户提供授予或拒绝的选项。

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

如果您的代码在 M 之前的设备上运行,您继续执行您的代码,使用旧方法授予权限。

一旦请求权限,对话框将显示给用户。他/她的回复将是:

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

之后,您可以使用LocationServices.SettingsApi 检查定位服务是否已开启,并在此选项被禁用时请求用户启用。这可以通过 Play Services LocationSettingsStatusCodes.RESOLUTION_REQUIRED 回调实现。

【讨论】:

谢谢!我意识到这将在权限关闭时显示对话框,但要启用我认为我需要调用播放服务并显示启用位置的选项。 恕我直言,检查位置和 wifi 是否已启用(和启用)应该先于请求使用这些功能的权限。 我尝试在带有 android m 的虚拟设备上运行它,结果是没有对话框询问权限,而是 onRequestPermission 立即返回权限被拒绝 M 上 7.5% 的用户,这意味着其余的人应该接受“访问位置”权限,这对他们来说完全没用。很可能它会吓跑他们 - 从未使用(也不应该使用)位置的应用程序开始要求额外的许可。有没有办法只为 M 添加权限? @surlac 恕我直言,您的评论应该是一个单独的问题。【参考方案2】:

我在 AOSP 问题跟踪器问题185370 WifiManager#getScanResults() 中找到相关问题,如果 GPS 关闭,则返回一个空数组列表。

#1提到的问题,手机必须开启定位服务才能获取手机的wifi列表。

来自#18,Android 项目成员声称开发团队已修复您报告的问题,并将在未来的版本中提供。

APP在targetSdkVersion 23,按照上面的解决方案检查运行时权限。强制启用位置服务问题将在 Android 未来版本中修复。

【讨论】:

这个问题还没解决吧?我正在运行 6.0 的联想手机上对其进行测试,但仍然遇到此问题。 code.google.com/p/android/issues/detail?id=185370#c70回复的问题指出,到目前为止Android N(预览版)似乎仍然有相同的行为。 @fantasy 非常感谢您的回答。但这是一个烦人的问题,因为我已经允许授予我的应用程序的位置权限,但我的设备 GPS 关闭仍然无法正常工作。现在,如果用户没有明确打开 GPS,这种情况就没有用了。我不明白wifi扫描真的需要GPS的帮助。 在 7.1.1 中仍然存在 wtf 正在进行中 @FantasyFang 非常感谢你,我浪费了 1 天......你是我的上帝,非常感谢 +1【参考方案3】:

除非您打开 GPS,否则这将不起作用。很奇怪,但这是我获得 wifi 列表的唯一方法:-(。

【讨论】:

你在这里救了一条命【参考方案4】:

编辑

所以,问题似乎出在新的权限处理上。在继续使用 wifi 代码之前,您必须获得许可。这是一个例子:

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

此检查必须在 Activity 中完成。

原始示例代码在here 可用,根据本主题讨论的问题进行修改。

原创

根据链接的changes of the API,您的应用程序必须具有位置权限之一。引用:

WifiManager.getScanResults():您的应用必须具有 ACCESS_FINE_LOCATION 或 ACCESS_COARSE_LOCATION 权限。

另请注意,您的 BroadcastReceiver 在SCAN_RESULTS_AVAILABLE_ACTION 操作:EXTRA_RESULTS_UPDATED 上收到了一个new boolean key。这显示扫描是否完成,您可以通过调用wifiManager.getScanResults() 访问结果。

【讨论】:

嗨@Gergely Kőrössy,感谢您的回答。由于我的应用具有位置功能,因此当前在应用中启用了这些权限。 &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /&gt; &lt;uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /&gt; @DeividiCavarzan,请注意广播接收器收到的捆绑包中有一个新的额外内容:developer.android.com/reference/android/net/wifi/… 是的,我查了一下,按预期返回true,说明有可用网络。返回的Wifi状态也是3,WIFI_STATE_ENABLED 如更新中所述,intent.getBooleanExtra("resultsUpdated", false); 在这种情况下返回 true。 是否从 AppCompatActivity 中删除了 onRequestPermissionsResult?在这个版本中它没有这个方法可以覆盖......【参考方案5】:

除了给定的响应;您还可以使用 checkSelfPermissionContextCompat 来向后兼容较低的 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

【讨论】:

以上是关于SCAN_RESULTS_AVAILABLE_ACTION 在 Android 6.0 中返回空列表的主要内容,如果未能解决你的问题,请参考以下文章