Android 6.0发布近一年之后,我们遇到了第一个Android 6.0的兼容性问题,getScanResults在Android6.0上返回了一个空列表,纳尼,你是在逗我么?去看了下Android 6.0某个分支下的getScanResult源码:
public List<ScanResult> getScanResults(String callingPackage) {
enforceAccessPermission();
int userId = UserHandle.getCallingUserId();
int uid = Binder.getCallingUid();
boolean canReadPeerMacAddresses = checkPeersMacAddress();
boolean isActiveNetworkScorer =
NetworkScorerAppManager.isCallerActiveScorer(mContext, uid);
boolean hasInteractUsersFull = checkInteractAcrossUsersFull();
long ident = Binder.clearCallingIdentity();
try {
if (!canReadPeerMacAddresses && !isActiveNetworkScorer
&& !isLocationEnabled()) {
return new ArrayList<ScanResult>();
}
if (!canReadPeerMacAddresses && !isActiveNetworkScorer
&& !checkCallerCanAccessScanResults(callingPackage, uid)) {
return new ArrayList<ScanResult>();
}
if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
!= AppOpsManager.MODE_ALLOWED) {
return new ArrayList<ScanResult>();
}
if (!isCurrentProfile(userId) && !hasInteractUsersFull) {
return new ArrayList<ScanResult>();
}
return mWifiStateMachine.syncGetScanResultsList();
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private boolean isLocationEnabled() {
return Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.LOCATION_MODE,
Settings.Secure.LOCATION_MODE_OFF) != Settings.Secure.LOCATION_MODE_OFF;
}
重点在:
if (!canReadPeerMacAddresses && !isActiveNetworkScorer
&& !isLocationEnabled()) {
return new ArrayList<ScanResult>();
}
可以看到如果定位关闭,那么将直接返回一个空的列表,当我去打开定位时,果然就正常的返回了WiFi列表,于是解决方案就是在6.0以上系统中,帮用户打开GPS开关:
if (Build.VERSION.SDK_INT >= 23 && !AppUtil.isGpsOPen(this)) {
Settings.Secure.putInt(getContentResolver(),Settings.Secure.LOCATION_MODE, 1);
}
当然,这里还需要用到一些权限:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
如果App不是system app,那么是获取不到WRITE_SECURE_SETTINGS权限的,此时就要引导用户去手动打开GPS开关,用户心里应该是会骂娘的:为何扫描个WiFi也需要打开GPS。
======================跳转到GPS代码==============================
2.跳转GPS设置界面
相关字符串
<string name="notifyTitle">提示</string> <string name="notifyMsg">当前应用缺少必要权限。\n\n请点击\"设置\"-\"权限\"-打开所需权限。</string> <string name="gpsNotifyMsg">当前应用需要打开定位功能。\n\n请点击\"设置\"-\"定位服务\"-打开定位功能。</string> <string name="setting">设置</string> <string name="cancel">取消</string>
java代码
private int GPS_REQUEST_CODE = 10; /** * 检测GPS是否打开 * * @return */ private boolean checkGPSIsOpen() { boolean isOpen; LocationManager locationManager = (LocationManager) this .getSystemService(Context.LOCATION_SERVICE); isOpen = locationManager.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER); return isOpen; } /** * 跳转GPS设置 */ private void openGPSSettings() { if (checkGPSIsOpen()) { initLocation(); //自己写的定位方法 } else { //没有打开则弹出对话框 new AlertDialog.Builder(this) .setTitle(R.string.notifyTitle) .setMessage(R.string.gpsNotifyMsg) // 拒绝, 退出应用 .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { finish(); } }) .setPositiveButton(R.string.setting, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { //跳转GPS设置界面 Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS); startActivityForResult(intent, GPS_REQUEST_CODE); } }) .setCancelable(false) .show(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == GPS_REQUEST_CODE) { //做需要做的事情,比如再次检测是否打开GPS了 或者定位 openGPSSettings(); } }
最后在需要的地方调用 openGPSSettings()方法。