问题描述:
转载请注明出处,from
fang_fang_story
近期做一个扫描附近低功耗蓝牙设备获取到rssi并进行一系列的相对的定位的功能。在开发前期一直使用低版本(Android6.0以下)的手机进行测试,没有任何问题。在运行到Android6.0的手机上后,出了一个问题。
每当扫描到附近ble设备并进行回调时都会报错,根本获取不了扫描的结果,报错如下:
- D/BluetoothLeScanner: onClientRegistered() - status=0 clientIf=5
- W/Binder: Caught a RuntimeException from the binder stub implementation.
- java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get
- scan results
- at android.os.Parcel.readException(Parcel.java:1620)
- at android.os.Parcel.readException(Parcel.java:1573)
- at android.bluetooth.IBluetoothGatt$Stub$Proxy.startScan(IBluetoothGatt.java:772)
- at android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper.onClientRegistered(BluetoothLeScanner.java:324)
- at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:56)
- at android.os.Binder.execTransact(Binder.java:453)
问题分析解决:
从log中可以看到一个解决方案,那就是Need ......permission to get scan results : 获取扫描结果需要位置权限,
i>,接下来就是往Androidmanifest.xml配置文件中添加权限
- <uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>
- <uses-permission-sdk-23 android:name="android.permission.ACCESS_FINE_LOCATION"/>
但是就算是添加了权限,在获取扫描结果时依旧会提示Need...permission...的问题,这是为什么呢?因为Android6.0中的一些权限需要在代码中动态申请
ii>,于是需要在代码中动态申请所需要的权限
-
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
- != PackageManager.PERMISSION_GRANTED) {
-
- ActivityCompat.requestPermissions(this,
- new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION},
- IntentCons.REQUEST_LOCATION_PERMISSION);
- if (ActivityCompat.shouldShowRequestPermissionRationale(this,
- Manifest.permission.ACCESS_COARSE_LOCATION)) {
-
- DialogUtils.shortT(getApplicationContext(), "需要蓝牙权限");
- }
- }
运行一下,果然应用会询问权限是否允许,效果如图
是不是觉得程序没有问题了?博主也是这么认为滴,允许权限之后发现,虽然不再报异常,但依旧刷新不出来结果(如果你的位置信息功能是开启的则就另说了,具体原因看第三条分析)
iii>,你目前只是有了使用设备的位置信息的权限,但是你还没有打开位置信息,所以就算有了权限也没办法使用。你可以验证一下----
验证不需要在代码中验证,你在做完第二步并且同意了访问位置信息的权限后,打开手机的位置信息功能。
打开方式一:进入设置打开位置信息
打开方式二:手机下拉导航栏的快捷设置中快捷设置
打开之后是不是发现应用可以获取扫描结果了呢?哈哈,博主已测过,没有问题。
解决方案:
综上分析,可以确定完美解决方案:
要想获取扫描结果,一是保证位置信息已经打开,二是保证应用已经动态申请了所需要的权限
第一步,保证位置信息打开:
-
-
-
-
-
- public static boolean isLocationOpen(final Context context){
- LocationManager manager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
-
- boolean isGpsProvider = manager.isProviderEnabled(LocationManager.GPS_PROVIDER);
-
- boolean isNetWorkProvider = manager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
- return isGpsProvider|| isNetWorkProvider;
- }
首先是判断位置信息是否开启,若未开启则开启:
-
- if (Build.VERSION.SDK_INT >= 23 && !NetUtils.isLocationOpen(getApplicationContext())) {
- Intent enableLocate = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
- startActivityForResult(enableLocate, IntentCons.REQUEST_LOCATION_PERMISSION);
- }
在这里判断了一下Android版本,因为只有6.0以上才需要这么做。
并且在该activity中重写onActivityResult方法,在位置开启成功后去申请权限,当然除了在代码中申请在清单配置文件中也是需要写的,如果未开启位置信息则进行其他处理
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == IntentCons.REQUEST_LOCATION_PERMISSION) {
- if (NetUtils.isLocationOpen(getApplicationContext())) {
- Log.i("fang", " request location permission success");
-
- if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION)
- != PackageManager.PERMISSION_GRANTED) {
-
- ActivityCompat.requestPermissions(this,
- new String[]{Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION},
- IntentCons.REQUEST_LOCATION_PERMISSION);
- if (ActivityCompat.shouldShowRequestPermissionRationale(this,
- Manifest.permission.ACCESS_COARSE_LOCATION)) {
-
- DialogUtils.shortT(getApplicationContext(), "需要蓝牙权限");
- }
- }
-
- } else {
-
- finish();
- }
- }
-
- super.onActivityResult(requestCode, resultCode, data);
-
- }
效果如下
哈哈,perfect,问题完美解决,有用的话留个爪儿吧