当前位置:   article > 正文

蓝牙开发(二)扫描设备_setreportdelay

setreportdelay

一、申请位置权限

在Android6.0以后要扫描蓝牙设备,还需要请求位置权限:

  1. <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  2. <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

位置权限属于危险权限,因此需要动态获取:

  1. //判断是否有权限
  2. if (ContextCompat.checkSelfPermission(this,
  3. Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
  4. //请求权限
  5. ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},MY_PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION);
  6. //判断是否需要 向用户解释,为什么要申请该权限
  7. if(ActivityCompat.shouldShowRequestPermissionRationale(this,
  8. Manifest.permission.READ_CONTACTS)) {
  9. Toast.makeText(this,"shouldShowRequestPermissionRationale",
  10. Toast.LENGTH_SHORT).show();
  11. }
  12. }
  13. //权限申请结果
  14. @Override
  15. public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[]
  16. grantResults) {
  17. super.onRequestPermissionsResult(requestCode, permissions, grantResults);
  18. }

在实际开发的过程中你也可以设置只有支持蓝牙的设备才能运行该APP:

  1. <uses-feature
  2. android:name="android.hardware.bluetooth_le"
  3. android:required="true" />

这里设置required为true就是只有在支持蓝牙的设备上才能运行,但是如果想让你的app提供给那些不支持BLE的设备,需要在manifest中包括上面代码并设置required="false",然后在运行时可以通过使用PackageManager.hasSystemFeature()确定BLE的可用性。

  1. // 使用此检查确定BLE是否支持在设备上,然后你可以有选择性禁用BLE相关的功能
  2. if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
  3. Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
  4. finish();
  5. }

二、扫描方式

Android官方提供的蓝牙扫描方式有三种,分别是:

  1. BluetoothAdapter.startDiscovery()//可以扫描经典蓝牙和ble蓝牙两种
  2. BluetoothAdapter.startLeScan()//扫描低功耗蓝牙,在api21已经弃用,不过还是可以使用
  3. BluetoothLeScanner.startScan()//新的ble扫描方法

startDiscovery()方法在大多数手机上是可以同时发现经典蓝牙和低功耗蓝牙(BLE)的,但是startDiscovery()的回调无法返回BLE的广播,所以无法通过广播识别设备,而且startDiscovery()扫描BLE效率比startLeScan()低很多。因此需要根据具体的需求去做适配,才能更高效的搜寻蓝牙。PS: startLeScan()和startScan()有重载方法可以指定规则,参数去搜索。

市面上的蓝牙设备,现在一般都是低功耗的蓝牙设备,因此只需要用下面两种扫描方式就OK了

2.1.startLeScan方式

官方提供的事例代码正是使用了这种方式,startLeScan方法有两个:

public boolean startLeScan(LeScanCallback callback)
public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback)

查看源码会发现一个参数的方法是调用了两个参数的方法,只是serviceuuid[]传入为null,也就是过滤条件为空。这里我使用的是没有过滤条件的方法:

  1. // Stops scanning after 10 seconds.
  2. private static final long SCAN_PERIOD = 10000;
  3. ...
  4. private void scanLeDevice(final boolean enable) {
  5. if (enable) {
  6. // Stops scanning after a pre-defined scan period.
  7. mHandler.postDelayed(new Runnable() {
  8. @Override
  9. public void run() {
  10. mScanning = false;
  11. mBluetoothAdapter.stopLeScan(mLeScanCallback);
  12. }
  13. }, SCAN_PERIOD);
  14. mScanning = true;
  15. mBluetoothAdapter.startLeScan(mLeScanCallback);
  16. } else {
  17. mScanning = false;
  18. mBluetoothAdapter.stopLeScan(mLeScanCallback);
  19. }
  20. ...
  21. }
  22. // Device scan callback.
  23. private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
  24. @Override
  25. public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
  26. //扫描到的设备信息,将字符数组转成16进制字符串
  27. String scanRecordStr = SysConvert.bytesToHex(scanRecord);
  28. //在这里可以做一下简单的操作,避免多操作造成性能问题
  29. }
  30. };

因为在扫描蓝牙是一个非常非常耗能的操作,因此一定要扫描一段时间就关闭,如果需要循环扫描,可以通过定时器实现扫描的开关操作

注意:打开和关闭所使用的回调必须是同一个,虽然关闭一个没有打开的回调没有错误返回。

2.2.startScan方式

我在项目中是使用startScan()扫描的,因为可以通过设置一些参数来灵活控制扫描的频率等。

同样的有三个重载方法:

public void startScan(final ScanCallback callback)

public void startScan(List<ScanFilter> filters, ScanSettings settings,final ScanCallback callback) 

public int startScan(@Nullable List<ScanFilter> filters, @Nullable ScanSettings settings,
        @NonNull PendingIntent callbackIntent) 

这里我以第二种为例:

  1. /**
  2. * 扫描设备
  3. */
  4. public void scanDevices() {
  5. mHandler.postDelayed(new Runnable() {
  6. @Override
  7. public void run() {
  8. mProgressDialog.dismiss();
  9. if (mBluetoothLeScanner != null) {
  10. mBluetoothLeScanner.stopScan(scanCallback);
  11. }
  12. }
  13. }, 1000);
  14. mBluetoothLeScanner.startScan(null, createScanSetting(), scanCallback);
  15. }
  16. /**
  17. * 扫描广播数据设置
  18. *
  19. * @return
  20. */
  21. public ScanSettings createScanSetting() {
  22. ScanSettings.Builder builder = new ScanSettings.Builder();
  23. builder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
  24. //builder.setReportDelay(100);//设置延迟返回时间
  25. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
  26. builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
  27. }
  28. return builder.build();
  29. }
  30. /**
  31. * 回调
  32. */
  33. private ScanCallback scanCallback=new ScanCallback() {
  34. @Override
  35. public void onScanResult(int callbackType, ScanResult result) {
  36. byte[] scanData=result.getScanRecord().getBytes();
  37. //把byte数组转成16进制字符串,方便查看
  38. }
  39. @Override
  40. public void onBatchScanResults(List<ScanResult> results) {
  41. super.onBatchScanResults(results);
  42. }
  43. @Override
  44. public void onScanFailed(int errorCode) {
  45. super.onScanFailed(errorCode);
  46. }
  47. };

ScanSettings :

setScanMode:有三种模式分别是

SCAN_MODE_LOW_POWER--------耗电最少,扫描时间间隔最短

SCAN_MODE_BALANCED---------平衡模式,耗电适中,扫描时间间隔一般,我使用这种模式来更新设备状态

SCAN_MODE_LOW_LATENCY---------最耗电,扫描延迟时间短,打开扫描需要立马返回结果可以使用

setReportDelay:设置扫描返回延迟时间,一般是大于零的毫秒值

如果设置了该属性,扫描结果会以list形式在onBatchScanResults方法返回,在onScanResult中没有返回,如果不设置则在onScanResult中返回,返回的信息包含在result中,可以通过getBytes返回每一个设备信息的字符数组,getDevice获取BluetoothDevice设备,在通过字符数组和蓝牙设备对象获取你想要的信息

 

本人也是一个蓝牙开发新手,如果上面有什么地方有问题,请指出,共同探讨,共同进步,不胜感激!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/192433
推荐阅读
相关标签
  

闽ICP备14008679号