Android 蓝牙监听与扫描

2019-09-27  本文已影响0人  未子涵

基础知识

蓝牙操作主要有四项任务:设置蓝牙、查找局部区域内的配对设备或可用设备、连接设备,以及在设备间传输数据。

蓝牙的分类

传统蓝牙(Classic Bluetooth)
低功耗蓝牙(Bluetooth LE)
双模蓝牙

使用方法可以参考以下官方文档:

传统蓝牙

低功耗蓝牙

以及简书:

android蓝牙BLE扫描实现方法

对于蓝牙扫描的说明

Android中两种蓝牙API的选择

传统蓝牙的电池使用强度较大,Android 4.3(API 18)中引入了面向低功耗蓝牙(BLe)的API支持。但这并不是说,4.3以上的设备就一定搭载了低功耗蓝牙。反而是更多地搭载“经典蓝牙”或“双模蓝牙”,毕竟要传输音频。

从测试结果来看,传统蓝牙API 可以同时扫描出 传统蓝牙低功耗蓝牙 ,而低功耗蓝牙API 则只能用于扫描 低功耗蓝牙

所以,千万别以为4.3以上的设备就应该用BLE API开发蓝牙功能,除非你的业务需求是针对BLE设备的,如果你需要扫描车载蓝牙或各种使用蓝牙连接的外设,那么建议使用传统蓝牙API,不然基本上扫不到设备。

功能讲解

查找已配对设备列表

权限

注:对于定位权限的依赖区分系统版本,较老版本(大概是6.0以前)中不需要定位权限,新版本(大概是6.0至9.0)需要任意一个定位权限,而从Q开始,必须拥有精确定位权限(具体的版本界限需要测试得出)。

其他要求

注:如果设备已开启蓝牙,可以静默获取数据,但若是要通过代码开启蓝牙,则需要 BLUETOOTH_ADMIN 权限,系统会在执行 开启蓝牙 操作时,向用户显示一个弹框,等待用户授权。

可获取的数据
来自BluetoothDevice对象的数据
获取方法

蓝牙开启的情况下,同步获取

核心代码
    public static BluetoothAdapter getBAdapter(Context context) {
        BluetoothAdapter mBluetoothAdapter = null;
        try {
            if (Build.VERSION.SDK_INT >= 18) {
                BluetoothManager manager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
                mBluetoothAdapter = manager.getAdapter();

            } else {
                mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
        return mBluetoothAdapter;
    }
    
    /**
     * 查询已配对的蓝牙设备
     *
     * @param mBluetoothAdapter
     */
    public static ArrayList<HashMap<String, Object>> getBondedDevice(BluetoothAdapter mBluetoothAdapter) {
        ArrayList<HashMap<String, Object>> result = new ArrayList<>();
        try {
            if (DeviceUtils.getInstance(context).checkPermission("android.permission.BLUETOOTH")) {
                Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
                // If there are paired devices
                if (pairedDevices.size() > 0) {
                    for (BluetoothDevice device : pairedDevices) {
                        HashMap<String, Object> deviceInfo = parseBtDevice2Map(device);
                        deviceInfo.put("__currConnected", (isConnectedBtDevice(device) ? 1 : 0));
                        result.add(deviceInfo);
                    }
                }
            }
        } catch (Throwable t) {
            t.printStackTrace();
        }
        return result;
    }

        @SuppressLint("MissingPermission")
    private static HashMap<String, Object> parseDevice2Map(BluetoothDevice device) {
        HashMap<String, Object> map = new HashMap<>();
        if (device != null) {
            try {
                map.put("name", device.getName());
                map.put("address", device.getAddress());
                map.put("bondState", device.getBondState());

                BluetoothClass btClass = device.getBluetoothClass();
                int majorClass = btClass.getMajorDeviceClass();
                int deviceClass = btClass.getDeviceClass();
                map.put("majorClass", majorClass);
                map.put("deviceClass", deviceClass);

                if (Build.VERSION.SDK_INT >= 18) {
                    map.put("type", device.getType());
                }
                // 已配对的设备,同时获取其uuids
                if (Build.VERSION.SDK_INT >= 15 && device.getBondState() == 12) {
                    ArrayList<String> uuids = new ArrayList<>();
                    ParcelUuid[] parcelUuids = device.getUuids();
                    if (parcelUuids != null && parcelUuids.length > 0) {
                        for (ParcelUuid parcelUuid : parcelUuids) {
                            if (parcelUuid != null && parcelUuid.getUuid() != null) {
                                uuids.add(parcelUuid.getUuid().toString());
                            }
                        }
                    }
                    map.put("uuids", uuids);
                }
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
        return map;
    }

获取当前连接的设备

方法一

先获取已匹配设备列表,再利用API返回的BluetoothDevice对象,反射调用其中的 isConnected 实例方法。

核心代码:

    public static boolean isConnectedDevice(BluetoothDevice device) {
        boolean isConnected = false;
        if (device != null) {
            try {
                if (DeviceUtils.getInstance(context).checkPermission("android.permission.BLUETOOTH")) {
                                        // isConnected方法只能反射调用
                    Boolean result = ReflectUtils.invokeInstanceMethod(device, "isConnected");
                    if (result != null) {
                        isConnected = result.booleanValue();
                    }
                }
            } catch (Throwable t) {
                t.printStackTrace();
            }
        }
        return isConnected;
    }
方法二

广播监听,向系统注册 BluetoothDevice.ACTION_ACL_CONNECTED 广播,可以监听蓝牙状态,每次有远程设备连接至本机时,会收到广播。不过该方式只能监听广播注册之后的蓝牙连接,注册之前已经连接的设备当然获取不到。

使用时需要注意:

  1. 用完后别忘了注销广播接收器。
  2. 广播接收器的 onReceive() 方法是在S 主线程 触发的,所以不要在其中处理耗时操作,如果使用了callback返回蓝牙操作的相关结果给外界,那么在callback中同样不能做耗时操作。

核心代码:

/**
 * 注册广播接收器,用于接收蓝牙相关操作的结果
 */
public static void registerBOperationReceiver() {
    if (btOperationReceiver == null) {
        try {
            btOperationReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    try {
                        String action = intent.getAction();
                        // 蓝牙开关状态变化
                        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
                            //获取蓝牙广播中的蓝牙新状态
                            int blueNewState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
                            //获取蓝牙广播中的蓝牙旧状态
                            int blueOldState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, 0);
                            switch (blueNewState) {
                                //正在打开蓝牙
                                case BluetoothAdapter.STATE_TURNING_ON: {
                                    Toast.makeText(context, "STATE_TURNING_ON", Toast.LENGTH_SHORT).show();
                                    break;
                                }
                                //蓝牙已打开
                                case BluetoothAdapter.STATE_ON: {
                                    Toast.makeText(context, "STATE_ON", Toast.LENGTH_SHORT).show();
                                    break;
                                }
                                //正在关闭蓝牙
                                case BluetoothAdapter.STATE_TURNING_OFF: {
                                    Toast.makeText(context, "STATE_TURNING_OFF", Toast.LENGTH_SHORT).show();
                                    break;
                                }
                                //蓝牙已关闭
                                case BluetoothAdapter.STATE_OFF: {
                                    Toast.makeText(context, "STATE_OFF", Toast.LENGTH_SHORT).show();
                                    break;
                                }
                            }
                        }
                        /*
                         * 本机的蓝牙连接状态发生变化
                         *
                         * 特指“无任何连接”→“连接任意远程设备”,以及“连接任一或多个远程设备”→“无任何连接”的状态变化,
                         * 即“连接第一个远程设备”与“断开最后一个远程设备”时才会触发该Action
                         */
                        else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
                            //获取蓝牙广播中的蓝牙连接新状态
                            int newConnState = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, 0);
                            //获取蓝牙广播中的蓝牙连接旧状态
                            int oldConnState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE, 0);
                            // 当前远程蓝牙设备
                            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                            HashMap<String, Object> map = parseBtDevice2Map(device);
                            switch (newConnState) {
                                //蓝牙连接中
                                case BluetoothAdapter.STATE_CONNECTING: {
                                    Log.d(TAG, "STATE_CONNECTING, " + map.get("name"));
                                    Toast.makeText(context, "STATE_CONNECTING", Toast.LENGTH_SHORT).show();
                                    break;
                                }
                                //蓝牙已连接
                                case BluetoothAdapter.STATE_CONNECTED: {
                                    Log.d(TAG, "STATE_CONNECTED, " + map.get("name"));
                                    Toast.makeText(context, "STATE_CONNECTED", Toast.LENGTH_SHORT).show();
                                    break;
                                }
                                //蓝牙断开连接中
                                case BluetoothAdapter.STATE_DISCONNECTING: {
                                    Log.d(TAG, "STATE_DISCONNECTING, " + map.get("name"));
                                    Toast.makeText(context, "STATE_DISCONNECTING", Toast.LENGTH_SHORT).show();
                                    break;
                                }
                                //蓝牙已断开连接
                                case BluetoothAdapter.STATE_DISCONNECTED: {
                                    Log.d(TAG, "STATE_DISCONNECTED, " + map.get("name"));
                                    Toast.makeText(context, "STATE_DISCONNECTED", Toast.LENGTH_SHORT).show();
                                    break;
                                }
                            }
                        }
                        // 有远程设备成功连接至本机
                        else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
                            // 当前远程蓝牙设备
                            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                            HashMap<String, Object> map = parseBtDevice2Map(device);
                            Log.d(TAG, "ACTION_ACL_CONNECTED, " + map.get("name"));
                            Toast.makeText(context, "ACTION_ACL_CONNECTED", Toast.LENGTH_SHORT).show();
                        }
                        // 有远程设备断开连接
                        else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
                            // 当前远程蓝牙设备
                            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                            HashMap<String, Object> map = parseBtDevice2Map(device);
                            Log.d(TAG, "ACTION_ACL_DISCONNECTED, " + map.get("name"));
                            Toast.makeText(context, "ACTION_ACL_DISCONNECTED", Toast.LENGTH_SHORT).show();
                        }
                    } catch (Throwable t) {
                        t.printStacktrace();
                    }
                }
            };
        } catch (Throwable t) {
            t.printStacktrace();
        }
        IntentFilter filter = new IntentFilter();
        // 蓝牙开关状态
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        // 本机的蓝牙连接状态发生变化(连接第一个远程设备与断开最后一个远程设备才触发)
        filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
        // 有远程设备成功连接至本机(每个远程设备都会触发)
        filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
        // 有远程设备断开连接(每个远程设备都会触发)
        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
        try {
            context.registerReceiver(btOperationReceiver, filter);
        } catch (Throwable t) {}
    }
}

蓝牙状态广播可根据业务需求,选择使用以下ACTION:

  • BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED
    • 本机的蓝牙连接状态发生变化时触发。特指“无任何连接”→“连接任意远程设备”,以及“连接任一或多个远程设备”→“无任何连接”的状态变化,即“连接第一个远程设备”与“断开最后一个远程设备”时才会触发该Action。
  • BluetoothDevice.ACTION_ACL_CONNECTED / BluetoothDevice.ACTION_ACL_DISCONNECTED
    • 每个远程设备的连接与断开都会触发

发现设备

权限

注:对于定位权限的依赖区分系统版本,较老版本(大概是6.0以前)中不需要定位权限,新版本(大概是6.0至9.0)需要任意一个定位权限,而从Q开始,必须拥有精确定位权限(具体的版本界限需要测试得出)。

其他要求
可获取的数据
来自BluetoothDevice对象的数据
蓝牙发现功能特有的数据
获取方法
说明
传统蓝牙API实现扫描的核心代码
    /**
     * 查找蓝牙,包括传统蓝牙和低功耗蓝牙
     *
     * 注:
     * 1.该方式在查找低功耗蓝牙上效率较低
     * 2.若只需要查找低功耗蓝牙,应该使用“低功耗蓝牙API”,即 findBluetoothLE() 方法
     *
     * @param scanInterval 扫描时长,单位:秒
     * @param bluetoothAdapter
     * @param btScanCallback 扫描结果回调
     */
    public static void findBluetoothLEAndClassic(int scanInterval, final BluetoothAdapter bluetoothAdapter, final BtScanCallback btScanCallback) {
        try {
            if (DeviceUtils.getInstance(context).checkPermission("android.permission.BLUETOOTH")
            && DeviceUtils.getInstance(context).checkPermission("android.permission.BLUETOOTH_ADMIN")) {
                if (!bluetoothAdapter.isEnabled()) {
                    // 若蓝牙未打开,直接返回
                    btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
                    return;
                }
                if (mScanning) {
                    // 正在扫描中,直接返回
                    btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
                    return;
                }
                // 默认扫描6秒,若scanInterval不合法,则使用默认值
                final int defaultInterval = 6;
                if (scanInterval <= 0) {
                    scanInterval = defaultInterval;
                }

                // 通过bluetoothAdapter.startDiscovery()实现的扫描,系统会在扫描结束(通常是12秒)后自动停止,
                // 而cancelDiscovery()可以提前终止扫描。 所以这里的控制逻辑,相当于设置一个最大时间,限制扫描不得超出这个时间,
                // 但是很可能提前完成扫描(比如scanInterval > 12秒)
                // 设置一段时间后停止扫描(以防系统未正常停止扫描)
                final Handler handler = HandlerThread.newHandler(new Handler.Callback() {
                    @Override
                    public boolean handleMessage(Message msg) {
                        Log.d(TAG, "Cancel bluetooth scan");
                        // 若已经停止扫描(系统扫描结束/通过cancelDiscovery取消扫描),则再次调用该方法不会触发ACTION_DISCOVERY_FINISHED
                        bluetoothAdapter.cancelDiscovery();
                        return false;
                    }
                });
                handler.sendEmptyMessageDelayed(0, scanInterval * 1000);

                // 准备开始扫描
                final ArrayList<HashMap<String, Object>> scanResult = new ArrayList<>();
                btScanReceiver = new BroadcastReceiver() {
                    public void onReceive(Context context, Intent intent) {
                        String action = intent.getAction();

                        if (action.equals(BluetoothDevice.ACTION_FOUND)) { //found device
                            BluetoothDevice device = intent
                                    .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                            HashMap<String, Object> map = parseBtDevice2Map(device);
                            // 该extra取值与BluetoothDevice对象中getName()取值一致,因此不需要通过它获取name
//                          String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
                            short defaultValue = 0;
                            short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, defaultValue);
                            map.put("rssi", rssi);
                            scanResult.add(map);
                            Log.d(TAG, "onScanResult: " + device.getAddress() + ", " + device.getName());
                        } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)) {
                            Log.d(TAG, "正在扫描");
                        } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
                            Log.d(TAG, "扫描完成");
                            mScanning = false;
                            btScanCallback.onScan(scanResult);
                            // 若系统先扫描完,不需要再通过代码主动停止扫描
                            handler.removeMessages(0);
                            // 注销接收器
                            unRegisterBtScanReceiver();
                        }
                    }
                };
                IntentFilter filter = new IntentFilter();
                // 用BroadcastReceiver来取得搜索结果
                filter.addAction(BluetoothDevice.ACTION_FOUND);
                filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
                // 两种情况会触发ACTION_DISCOVERY_FINISHED:1.系统结束扫描(约12秒);2.调用cancelDiscovery()方法主动结束扫描
                filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
                context.registerReceiver(btScanReceiver, filter);

                // 开始扫描
                mScanning = true;
                bluetoothAdapter.startDiscovery();
            } else {
                // 缺少权限,直接返回
                btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
            }
        } catch (Throwable t) {
            t.printStackTrace();
            btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
        }
    }

    public static void unRegisterBtScanReceiver() {
        if (btScanReceiver != null) {
            context.unregisterReceiver(btScanReceiver);
            btScanReceiver = null;
        }
    }
    
    public interface BtScanCallback {
        void onScan(ArrayList<HashMap<String, Object>> result);
    }
BLE API实现扫描的核心代码
    /**
     * 查找低功耗蓝牙,该方法在4.3(API 18)以上,无法查找“传统蓝牙”
     *
     * @param scanInterval 扫描时长,单位:秒
     * @param bluetoothAdapter
     * @param btScanCallback 扫描结果回调
     */
    public static void findBluetoothLE(int scanInterval, final BluetoothAdapter bluetoothAdapter, final BtScanCallback btScanCallback) {
        try {
            if (DeviceUtils.getInstance(context).checkPermission("android.permission.BLUETOOTH")
                    && DeviceUtils.getInstance(context).checkPermission("android.permission.BLUETOOTH_ADMIN")) {
                if (!bluetoothAdapter.isEnabled()) {
                    // 若蓝牙未打开,直接返回
                    btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
                    return;
                }
                if (mScanning) {
                    // 正在扫描中,直接返回
                    btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
                    return;
                }
                // 默认扫描6秒,若scanInterval不合法,则使用默认值
                final int defaultInterval = 6;
                if (scanInterval <= 0) {
                    scanInterval = defaultInterval;
                }
                // 4.3的低功耗蓝牙API
                if (Build.VERSION.SDK_INT >= 18) {
                    final ArrayList<HashMap<String, Object>> scanResult = new ArrayList<>();
                    // 5.0又引入了新的蓝牙API(4.3版本的API仍然可用)
                    if (Build.VERSION.SDK_INT < 21) {
                        // 定义扫描结果回调
                        final BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
                            /**
                             *
                             * @param device 扫描到的设备实例,可从实例中获取到相应的信息。如:名称,mac地址
                             * @param rssi 可理解成设备的信号值。该数值是一个负数,越大则信号越强
                             * @param scanRecord 远程设备提供的广播数据的内容
                             */
                            @Override
                            public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
                                HashMap<String, Object> map = parseBtDevice2Map(device);
                                map.put("rssi", rssi);
//                      map.put("scanRecord", Data.byteToHex(scanRecord));
                                scanResult.add(map);
                            }
                        };

                        // 开始扫描
                        mScanning = true;
                        bluetoothAdapter.startLeScan(leScanCallback);

                        // 设置一段时间后停止扫描
                        Handler handler = HandlerThread.newHandler(new Handler.Callback() {
                            @Override
                            public boolean handleMessage(Message msg) {
                                mScanning = false;
                                bluetoothAdapter.stopLeScan(leScanCallback);
                                btScanCallback.onScan(scanResult);
                                return false;
                            }
                        });
                        handler.sendEmptyMessageDelayed(0, scanInterval * 1000);
                    } else {
                        // 定义扫描结果回调
                        final ScanCallback mScanCallback = new ScanCallback() {
                            //当一个蓝牙ble广播被发现时回调
                            @Override
                            public void onScanResult(int callbackType, ScanResult result) {
                                Log.d(TAG, "onScanResult: " + result.getDevice().getAddress() + ", " + result.getDevice().getName());
                                super.onScanResult(callbackType, result);
                                //扫描类型有开始扫描时传入的ScanSettings相关
                                //对扫描到的设备进行操作。如:获取设备信息。
                                if (result != null) {
                                    HashMap<String, Object> map = new HashMap<>();
                                    BluetoothDevice device = result.getDevice();
                                    if (device != null) {
                                        map = parseBtDevice2Map(device);
                                    }
                                    map.put("rssi", result.getRssi());
                                    ScanRecord scanRecord = result.getScanRecord();
                                    scanResult.add(map);
                                }
                            }

                            // 批量返回扫描结果。一般蓝牙设备对象都是通过onScanResult(int,ScanResult)返回,
                            // 而不会在onBatchScanResults(List)方法中返回,除非手机支持批量扫描模式并且开启了批量扫描模式。
                            // 批处理的开启请查看ScanSettings。
                            //@param results 以前扫描到的扫描结果列表。
                            @Override
                            public void onBatchScanResults(List<ScanResult> results) {
                                super.onBatchScanResults(results);
                                Log.d(TAG, "onBatchScanResults");

                            }

                            //当扫描不能开启时回调
                            @Override
                            public void onScanFailed(int errorCode) {
                                super.onScanFailed(errorCode);
                                //扫描太频繁会返回ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED,表示app无法注册,无法开始扫描。
                                Log.d(TAG, "onScanFailed. errorCode: " + errorCode);
                            }
                        };
                        //开始扫描
                        final BluetoothLeScanner mBLEScanner = bluetoothAdapter.getBluetoothLeScanner();
                        mScanning = true;
/** 也可指定过滤条件和扫描配置
                         //创建ScanSettings的build对象用于设置参数
                         ScanSettings.Builder builder = new ScanSettings.Builder()
                         //设置高功耗模式
                         .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
                         //android 6.0添加设置回调类型、匹配模式等
                         if(android.os.Build.VERSION.SDK_INT >= 23) {
                         //定义回调类型
                         builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
                         //设置蓝牙LE扫描滤波器硬件匹配的匹配模式
                         builder.setMatchMode(ScanSettings.MATCH_MODE_STICKY);
                         }
                         // 若设备支持批处理扫描,可以选择使用批处理,但此时扫描结果仅触发onBatchScanResults()
                         //             if (bluetoothAdapter.isOffloadedScanBatchingSupported()) {
                         //                 //设置蓝牙LE扫描的报告延迟的时间(以毫秒为单位)
                         //                 //设置为0以立即通知结果
                         //                 builder.setReportDelay(0L);
                         //             }
                         ScanSettings scanSettings = builder.build();
                         //可设置过滤条件,在第一个参数传入,但一般不设置过滤。
                         mBLEScanner.startScan(null, scanSettings, mScanCallback);
 */
                        mBLEScanner.startScan(mScanCallback);
                        // 设置一段时间后停止扫描
                        Handler handler = HandlerThread.newHandler(new Handler.Callback() {
                            @Override
                            public boolean handleMessage(Message msg) {
                                mScanning = false;
                                mBLEScanner.stopScan((mScanCallback));
                                btScanCallback.onScan(scanResult);
                                return false;
                            }
                        });
                        handler.sendEmptyMessageDelayed(0, scanInterval * 1000);
                    }
                } else {
                    findBluetoothLEAndClassic(scanInterval, bluetoothAdapter, btScanCallback);
                }
            } else {
                // 缺少权限,直接返回
                btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
            }
        } catch (Throwable t) {
            t.printStackTrace();
            btScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
        }
    }
Demo验证获取结果说明

对于以上结果,怀疑的问题点:

蓝牙相关字段说明

绑定状态(bondState)
蓝牙类型(type)(API 18开始)
远程设备支持的功能(uuids)(API 15开始)
该蓝牙所属设备类型大分类(majorClass)
该蓝牙所属设备类型小分类(deviceClass)

实现一个蓝牙工具类

最后附上一个完整的蓝牙操作工具类:

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanRecord;
import android.bluetooth.le.ScanResult;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.ParcelUuid;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class BHelper {
    private static final String TAG = "BHelper";
    private static BHelper instance;
    private Context context;
    private boolean mScanning = false;
    // 蓝牙开关/连接接收器
    private BroadcastReceiver bOperationReceiver;
    private boolean bOperationRegistered = false;
    // 蓝牙扫描接收器
    private BroadcastReceiver bScanReceiver;
    private boolean bScanRegistered = false;
    private Map<String, BOperationCallback> bOperationCallbackMap;

    private BHelper(Context context) {
        this.context = context.getApplicationContext();
    }
    
    public static BHelper getInstance(Context context) {
        if (instance == null) {
            synchronized (BHelper.class) {
                if (instance == null) {
                    instance = new BHelper(context);
                }
            }
        }
        return instance;
    }
    
    // 根据id注销指定的监听器
    public void unRegisterBOperationReceiver(String id) {
        try {
            if (bOperationCallbackMap != null && !bOperationCallbackMap.containsKey(id)) {
                bOperationCallbackMap.remove(id);
            }
            // 当前没有任何运行中的监听器时,才需要注销广播接收器
            if (bOperationCallbackMap.isEmpty()) {
                if (bOperationReceiver != null && bOperationRegistered) {
                    context.unregisterReceiver(bOperationReceiver);
                    bOperationRegistered = false;
                    bOperationReceiver = null;
                }
            }
        } catch (Throwable t) {
            Log.d(TAG, t.getMessage() + "", t);
        }
    }

    /**
     * 注册广播接收器,用于接收蓝牙相关操作的结果
     * 参数中增加id,目的是支持同时注册多个监听器,否则后注册的监听器会覆盖前面的监听器,导致同一时间只能有一个地方使用蓝牙工具类
     */
    public void registerBOperationReceiver(String id, final BOperationCallback bOperationCallback) {
        if (bOperationCallback != null) {
            if (bOperationCallbackMap == null) {
                bOperationCallbackMap = new HashMap<String, BOperationCallback>();
            }
            bOperationCallbackMap.put(id, bOperationCallback);

            if (bOperationReceiver == null) {
                try {
                    bOperationReceiver = new BroadcastReceiver() {
                        @Override
                        public void onReceive(Context context, Intent intent) {
                            try {
                                String action = intent.getAction();
                                // 蓝牙开关状态变化
                                if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
                                    //获取蓝牙广播中的蓝牙新状态
                                    int bNewState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
                                    //获取蓝牙广播中的蓝牙旧状态
                                    int bOldState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, 0);
                                    switch (bNewState) {
                                        //正在打开蓝牙
                                        case BluetoothAdapter.STATE_TURNING_ON: {
                                            // no need to monitor this action
                                            break;
                                        }
                                        //蓝牙已打开
                                        case BluetoothAdapter.STATE_ON: {
                                            if (bOperationCallbackMap != null && !bOperationCallbackMap.isEmpty()) {
                                                for (Map.Entry<String, BOperationCallback> entry : bOperationCallbackMap.entrySet()) {
                                                    BOperationCallback callback = entry.getValue();
                                                    if (callback != null) {
                                                        callback.onEnabled();
                                                    }
                                                }
                                            }
                                            break;
                                        }
                                        //正在关闭蓝牙
                                        case BluetoothAdapter.STATE_TURNING_OFF: {
                                            // no need to monitor this action
                                            break;
                                        }
                                        //蓝牙已关闭
                                        case BluetoothAdapter.STATE_OFF: {
                                            if (bOperationCallbackMap != null && !bOperationCallbackMap.isEmpty()) {
                                                for (Map.Entry<String, BOperationCallback> entry : bOperationCallbackMap.entrySet()) {
                                                    BOperationCallback callback = entry.getValue();
                                                    if (callback != null) {
                                                        callback.onDisabled();
                                                    }
                                                }
                                            }
                                            break;
                                        }
                                    }
                                }
                                /*
                                 * 本机的蓝牙连接状态发生变化
                                 *
                                 * 特指“无任何连接”→“连接任意远程设备”,以及“连接任一或多个远程设备”→“无任何连接”的状态变化,
                                 * 即“连接第一个远程设备”与“断开最后一个远程设备”时才会触发该Action
                                 */
                                else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
                                    //获取蓝牙广播中的蓝牙连接新状态
                                    int newConnState = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, 0);
                                    //获取蓝牙广播中的蓝牙连接旧状态
                                    int oldConnState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_CONNECTION_STATE, 0);
                                    // 当前远程蓝牙设备
                                    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                                    HashMap<String, Object> map = parseDevice2Map(device);
                                    switch (newConnState) {
                                        //蓝牙连接中
                                        case BluetoothAdapter.STATE_CONNECTING: {
                                            // no need to monitor this action
                                            break;
                                        }
                                        //蓝牙已连接
                                        case BluetoothAdapter.STATE_CONNECTED: {
                                            if (bOperationCallbackMap != null && !bOperationCallbackMap.isEmpty()) {
                                                for (Map.Entry<String, BOperationCallback> entry : bOperationCallbackMap.entrySet()) {
                                                    BOperationCallback callback = entry.getValue();
                                                    if (callback != null) {
                                                        callback.onConnectionChanged(true, map);
                                                    }
                                                }
                                            }
                                            break;
                                        }
                                        //蓝牙断开连接中
                                        case BluetoothAdapter.STATE_DISCONNECTING: {
                                            // no need to monitor this action
                                            break;
                                        }
                                        //蓝牙已断开连接
                                        case BluetoothAdapter.STATE_DISCONNECTED: {
                                            if (bOperationCallbackMap != null && !bOperationCallbackMap.isEmpty()) {
                                                for (Map.Entry<String, BOperationCallback> entry : bOperationCallbackMap.entrySet()) {
                                                    BOperationCallback callback = entry.getValue();
                                                    if (callback != null) {
                                                        callback.onConnectionChanged(false, map);
                                                    }
                                                }
                                            }
                                            break;
                                        }
                                    }
                                }
                                // 有远程设备成功连接至本机
                                else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
                                    // 当前远程蓝牙设备
                                    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                                    HashMap<String, Object> map = parseDevice2Map(device);
                                    if (bOperationCallbackMap != null && !bOperationCallbackMap.isEmpty()) {
                                        for (Map.Entry<String, BOperationCallback> entry : bOperationCallbackMap.entrySet()) {
                                            BOperationCallback callback = entry.getValue();
                                            if (callback != null) {
                                                callback.onDeviceConnected(map);
                                            }
                                        }
                                    }
                                }
                                // 有远程设备断开连接(连接至一个蓝牙设备时,若关闭蓝牙,则只会触发STATE_DISCONNECTED,不会触发ACTION_ACL_DISCONNECTED)
                                else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
                                    // 当前远程蓝牙设备
                                    BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                                    HashMap<String, Object> map = parseDevice2Map(device);
                                    if (bOperationCallbackMap != null && !bOperationCallbackMap.isEmpty()) {
                                        for (Map.Entry<String, BOperationCallback> entry : bOperationCallbackMap.entrySet()) {
                                            BOperationCallback callback = entry.getValue();
                                            if (callback != null) {
                                                callback.onDeviceDisconnected(map);
                                            }
                                        }
                                    }
                                }
                            } catch (Throwable t) {
                                Log.d(TAG, t.getMessage() + "", t);
                            }
                        }
                    };
                    IntentFilter filter = new IntentFilter();
                    // 蓝牙开关状态
                    filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
                    // 本机的蓝牙连接状态发生变化(连接第一个远程设备与断开最后一个远程设备才触发)
                    filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
                    // 有远程设备成功连接至本机(每个远程设备都会触发)
                    filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
                    // 有远程设备断开连接(每个远程设备都会触发)
                    filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
                    context.registerReceiver(bOperationReceiver, filter);
                    bOperationRegistered = true;
                } catch (Throwable t) {
                    Log.d(TAG, t.getMessage() + "", t);
                }
            }
        }
    }

    /**
     * 打开蓝牙
     *
     */
    @SuppressLint("MissingPermission")
    public void open() {
        try {
            if (DeviceHelper.getInstance(context).checkPermission("android.permission.BLUETOOTH")
                    && DeviceHelper.getInstance(context).checkPermission("android.permission.BLUETOOTH_ADMIN")) {
                //方式一:请求打开蓝牙
//              Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
//              activity.startActivityForResult(intent, 1);
                //方式二:半静默打开蓝牙
                //低版本android会静默打开蓝牙,高版本android会请求打开蓝牙
                BluetoothAdapter adapter = getBAdapter();
                adapter.enable();
            }
        } catch (Throwable t) {
            Log.d(TAG, t.getMessage() + "", t);
        }
    }

    /**
     * 判断蓝牙是否已打开
     *
     * @return
     */
    @SuppressLint("MissingPermission")
    public boolean isEnabled() {
        boolean enabled = false;
        try {
            if (DeviceHelper.getInstance(context).checkPermission("android.permission.BLUETOOTH")) {
                BluetoothAdapter adapter = getBAdapter();
                if (adapter != null) {
                    //判断蓝牙是否开启
                    if (adapter.isEnabled()) {
                        enabled = true;
                    }
                } else {
                    // Device does not support Bluetooth
                }
            }
        } catch (Throwable t) {
            Log.d(TAG, t.getMessage() + "", t);
        }
        return enabled;
    }

    /**
     * 查询已配对的蓝牙设备
     */
    @SuppressLint("MissingPermission")
    public ArrayList<HashMap<String, Object>> getBondedDevice() {
        ArrayList<HashMap<String, Object>> result = new ArrayList<HashMap<String, Object>>();
        try {
            if (DeviceHelper.getInstance(context).checkPermission("android.permission.BLUETOOTH")) {
                BluetoothAdapter adapter = getBAdapter();
                Set<BluetoothDevice> pairedDevices = adapter.getBondedDevices();
                // If there are paired devices
                if (pairedDevices.size() > 0) {
                    for (BluetoothDevice device : pairedDevices) {
                        HashMap<String, Object> deviceInfo = parseDevice2Map(device);
                        deviceInfo.put("__currConnected", (isConnectedDevice(device) ? 1 : 0));
                        result.add(deviceInfo);
                    }
                }
            }
        } catch (Throwable t) {
            Log.d(TAG, t.getMessage() + "", t);
        }
        return result;
    }

    public boolean isConnectedDevice(BluetoothDevice device) {
        boolean isConnected = false;
        if (device != null) {
            try {
                if (DeviceHelper.getInstance(context).checkPermission("android.permission.BLUETOOTH")) {
                    //#if def{debuggable}
                    Boolean result = ReflectHelper.invokeInstanceMethod(device, "isConnected");
                    //#else
                    //#=Boolean result = ReflectHelper.invokeInstanceMethod(device, Strings.getString(115));
                    //#endif
                    if (result != null) {
                        isConnected = result.booleanValue();
                    }
                }
            } catch (Throwable t) {
                Log.d(TAG, t.getMessage() + "", t);
            }
        }
        return isConnected;
    }

    /**
     * 查找蓝牙,包括传统蓝牙和低功耗蓝牙
     *
     * 注:
     * 1.该方式在查找低功耗蓝牙上效率较低
     * 2.若只需要查找低功耗蓝牙,应该使用“低功耗蓝牙API”,即 findLE() 方法
     * 3.为防止非正常终止扫描造成的内存泄漏,使用该方法后,需在适当的时机,主动调用一次unRegisterBtScanReceiver(),以注销接收器
     *
     * @param scanInterval 扫描时长,单位:秒,建议取值范围(0,12]
     * @param bScanCallback 扫描结果回调
     */
    @SuppressLint("MissingPermission")
    public void findLEAndClassic(int scanInterval, final BScanCallback bScanCallback) {
        try {
            if (DeviceHelper.getInstance(context).checkPermission("android.permission.BLUETOOTH")
            && DeviceHelper.getInstance(context).checkPermission("android.permission.BLUETOOTH_ADMIN")) {
                final BluetoothAdapter adapter = getBAdapter();
                if (!adapter.isEnabled()) {
                    // 若蓝牙未打开,直接返回
                    bScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
                    return;
                }
                if (mScanning) {
                    // 正在扫描中,直接返回
                    bScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
                    return;
                }
                // 默认扫描6秒,若scanInterval不合法,则使用默认值
                final int defaultInterval = 6;
                if (scanInterval <= 0) {
                    scanInterval = defaultInterval;
                }

                // 通过bluetoothAdapter.startDiscovery()实现的扫描,系统会在扫描结束(通常是12秒)后自动停止,
                // 而cancelDiscovery()可以提前终止扫描。 所以这里的控制逻辑,相当于设置一个最大时间,限制扫描不得超出这个时间,
                // 但是很可能提前完成扫描(比如scanInterval > 12秒)
                // 设置一段时间后停止扫描(以防系统未正常停止扫描)
                final Handler handler = HandlerThread.newHandler(new Handler.Callback() {
                    @Override
                    public boolean handleMessage(Message msg) {
                        // 若已经停止扫描(系统扫描结束/通过cancelDiscovery取消扫描),则再次调用该方法不会触发ACTION_DISCOVERY_FINISHED
                        adapter.cancelDiscovery();
                        return false;
                    }
                });
                handler.sendEmptyMessageDelayed(0, scanInterval * 1000);

                // 准备开始扫描
                final ArrayList<HashMap<String, Object>> scanResult = new ArrayList<HashMap<String, Object>>();
                bScanReceiver = new BroadcastReceiver() {
                    public void onReceive(Context context, Intent intent) {
                        try {
                            String action = intent.getAction();

                            if (action.equals(BluetoothDevice.ACTION_FOUND)) { //found device
                                BluetoothDevice device = intent
                                        .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                                HashMap<String, Object> map = parseDevice2Map(device);
                                // 该extra取值与BluetoothDevice对象中getName()取值一致,因此不需要通过它获取name
//                          String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
                                short defaultValue = 0;
                                short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, defaultValue);
                                map.put("rssi", rssi);
                                scanResult.add(map);
                            } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_STARTED)) {
                                Log.d(TAG, "started");
                            } else if (action.equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) {
                                Log.d(TAG, "done");
                                mScanning = false;
                                bScanCallback.onScan(scanResult);
                                // 若系统先扫描完,不需要再通过代码主动停止扫描
                                handler.removeMessages(0);
                                // 注销接收器
                                unRegisterBScanReceiver();
                            }
                        } catch (Throwable t) {
                            Log.d(TAG, t.getMessage() + "", t);
                        }
                    }
                };
                IntentFilter filter = new IntentFilter();
                // 用BroadcastReceiver来取得搜索结果
                filter.addAction(BluetoothDevice.ACTION_FOUND);
                filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
                // 两种情况会触发ACTION_DISCOVERY_FINISHED:1.系统结束扫描(约12秒);2.调用cancelDiscovery()方法主动结束扫描
                filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
                context.registerReceiver(bScanReceiver, filter);
                bScanRegistered = true;

                // 开始扫描
                mScanning = true;
                adapter.startDiscovery();
            } else {
                // 缺少权限,直接返回
                bScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
            }
        } catch (Throwable t) {
            Log.d(TAG, t.getMessage() + "", t);
            bScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
        }
    }

    public void unRegisterBScanReceiver() {
        try {
            if (bScanReceiver != null && bScanRegistered) {
                context.unregisterReceiver(bScanReceiver);
                bScanRegistered = false;
                bScanReceiver = null;
            }
        } catch (Throwable t) {
            Log.d(TAG, t.getMessage() + "", t);
        }
    }

    /**
     * 查找低功耗蓝牙,该方法在4.3(API 18)以上,无法查找“传统蓝牙”
     *
     * @param scanInterval 扫描时长,单位:秒
     * @param adapter
     * @param bScanCallback 扫描结果回调
     */
    @SuppressLint("MissingPermission")
    public void findLE(int scanInterval, final BluetoothAdapter adapter, final BScanCallback bScanCallback) {
        try {
            if (DeviceHelper.getInstance(context).checkPermission("android.permission.BLUETOOTH")
                    && DeviceHelper.getInstance(context).checkPermission("android.permission.BLUETOOTH_ADMIN")) {
                if (!adapter.isEnabled()) {
                    // 若蓝牙未打开,直接返回
                    bScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
                    return;
                }
                if (mScanning) {
                    // 正在扫描中,直接返回
                    bScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
                    return;
                }
                // 默认扫描6秒,若scanInterval不合法,则使用默认值
                final int defaultInterval = 6;
                if (scanInterval <= 0) {
                    scanInterval = defaultInterval;
                }
                // 4.3的低功耗蓝牙API
                if (Build.VERSION.SDK_INT >= 18) {
                    final ArrayList<HashMap<String, Object>> scanResult = new ArrayList<HashMap<String, Object>>();
                    // 5.0又引入了新的蓝牙API(4.3版本的API仍然可用)
                    if (Build.VERSION.SDK_INT < 21) {
                        // 定义扫描结果回调
                        final BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
                            /**
                             *
                             * @param device 扫描到的设备实例,可从实例中获取到相应的信息。如:名称,mac地址
                             * @param rssi 可理解成设备的信号值。该数值是一个负数,越大则信号越强
                             * @param scanRecord 远程设备提供的广播数据的内容
                             */
                            @Override
                            public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
                                try {
                                    HashMap<String, Object> map = parseDevice2Map(device);
                                    map.put("rssi", rssi);
//                                  map.put("scanRecord", Data.byteToHex(scanRecord));
                                    scanResult.add(map);
                                } catch (Throwable t) {
                                    Log.d(TAG, t.getMessage() + "", t);
                                }
                            }
                        };

                        // 开始扫描
                        mScanning = true;
                        adapter.startLeScan(leScanCallback);

                        // 设置一段时间后停止扫描
                        Handler handler = HandlerThread.newHandler(new Handler.Callback() {
                            @Override
                            public boolean handleMessage(Message msg) {
                                mScanning = false;
                                adapter.stopLeScan(leScanCallback);
                                bScanCallback.onScan(scanResult);
                                return false;
                            }
                        });
                        handler.sendEmptyMessageDelayed(0, scanInterval * 1000);
                    } else {
                        // 定义扫描结果回调
                        final ScanCallback mScanCallback = new ScanCallback() {
                            //当一个蓝牙ble广播被发现时回调
                            @Override
                            public void onScanResult(int callbackType, ScanResult result) {
                                super.onScanResult(callbackType, result);
                                //扫描类型有开始扫描时传入的ScanSettings相关
                                //对扫描到的设备进行操作。如:获取设备信息。
                                if (result != null) {
                                    HashMap<String, Object> map = new HashMap<String, Object>();
                                    BluetoothDevice device = result.getDevice();
                                    if (device != null) {
                                        map = parseDevice2Map(device);
                                    }
                                    map.put("rssi", result.getRssi());
                                    ScanRecord scanRecord = result.getScanRecord();
                                    scanResult.add(map);
                                }
                            }

                            // 批量返回扫描结果。一般蓝牙设备对象都是通过onScanResult(int,ScanResult)返回,
                            // 而不会在onBatchScanResults(List)方法中返回,除非手机支持批量扫描模式并且开启了批量扫描模式。
                            // 批处理的开启请查看ScanSettings。
                            //@param results 以前扫描到的扫描结果列表。
                            @Override
                            public void onBatchScanResults(List<ScanResult> results) {
                                super.onBatchScanResults(results);
                            }

                            //当扫描不能开启时回调
                            @Override
                            public void onScanFailed(int errorCode) {
                                super.onScanFailed(errorCode);
                                //扫描太频繁会返回ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED,表示app无法注册,无法开始扫描。
                            }
                        };
                        //开始扫描
                        final BluetoothLeScanner mBLEScanner = adapter.getBluetoothLeScanner();
                        mScanning = true;
/** 也可指定过滤条件和扫描配置
                         //创建ScanSettings的build对象用于设置参数
                         ScanSettings.Builder builder = new ScanSettings.Builder()
                         //设置高功耗模式
                         .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
                         //android 6.0添加设置回调类型、匹配模式等
                         if(android.os.Build.VERSION.SDK_INT >= 23) {
                         //定义回调类型
                         builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
                         //设置蓝牙LE扫描滤波器硬件匹配的匹配模式
                         builder.setMatchMode(ScanSettings.MATCH_MODE_STICKY);
                         }
                         // 若设备支持批处理扫描,可以选择使用批处理,但此时扫描结果仅触发onBatchScanResults()
                         //             if (bluetoothAdapter.isOffloadedScanBatchingSupported()) {
                         //                 //设置蓝牙LE扫描的报告延迟的时间(以毫秒为单位)
                         //                 //设置为0以立即通知结果
                         //                 builder.setReportDelay(0L);
                         //             }
                         ScanSettings scanSettings = builder.build();
                         //可设置过滤条件,在第一个参数传入,但一般不设置过滤。
                         mBLEScanner.startScan(null, scanSettings, mScanCallback);
 */
                        mBLEScanner.startScan(mScanCallback);
                        // 设置一段时间后停止扫描
                        Handler handler = HandlerThread.newHandler(new Handler.Callback() {
                            @Override
                            public boolean handleMessage(Message msg) {
                                mScanning = false;
                                mBLEScanner.stopScan((mScanCallback));
                                bScanCallback.onScan(scanResult);
                                return false;
                            }
                        });
                        handler.sendEmptyMessageDelayed(0, scanInterval * 1000);
                    }
                } else {
                    findLEAndClassic(scanInterval, bScanCallback);
                }
            } else {
                // 缺少权限,直接返回
                bScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
            }
        } catch (Throwable t) {
            Log.d(TAG, t.getMessage() + "", t);
            bScanCallback.onScan(new ArrayList<HashMap<String, Object>>());
        }
    }

    private BluetoothAdapter getBAdapter() {
        BluetoothAdapter adapter = null;
        try {
            if (Build.VERSION.SDK_INT >= 18) {
                BluetoothManager manager = (BluetoothManager) DeviceHelper.getInstance(context).getSystemServiceSafe(Context.BLUETOOTH_SERVICE);
                adapter = manager.getAdapter();

            } else {
                adapter = BluetoothAdapter.getDefaultAdapter();
            }
        } catch (Throwable t) {
            Log.d(TAG, t.getMessage() + "", t);
        }
        return adapter;
    }

    @SuppressLint("MissingPermission")
    private HashMap<String, Object> parseDevice2Map(BluetoothDevice device) {
        HashMap<String, Object> map = new HashMap<String, Object>();
        if (device != null) {
            try {
                map.put("name", device.getName());
                map.put("address", device.getAddress());
                map.put("bondState", device.getBondState());

                BluetoothClass btClass = device.getBluetoothClass();
                int majorClass = btClass.getMajorDeviceClass();
                int deviceClass = btClass.getDeviceClass();
                map.put("majorClass", majorClass);
                map.put("deviceClass", deviceClass);

                if (Build.VERSION.SDK_INT >= 18) {
                    map.put("type", device.getType());
                }
                // 已配对的设备,同时获取其uuids
                if (Build.VERSION.SDK_INT >= 15 && device.getBondState() == 12) {
                    ArrayList<String> uuids = new ArrayList<String>();
                    ParcelUuid[] parcelUuids = device.getUuids();
                    if (parcelUuids != null && parcelUuids.length > 0) {
                        for (ParcelUuid parcelUuid : parcelUuids) {
                            if (parcelUuid != null && parcelUuid.getUuid() != null) {
                                uuids.add(parcelUuid.getUuid().toString());
                            }
                        }
                    }
                    map.put("uuids", uuids);
                }
            } catch (Throwable t) {
                Log.d(TAG, t.getMessage() + "", t);
            }
        }
        return map;
    }

    public static class BOperationCallback {
        /**
         * 打开蓝牙
         */
        protected void onEnabled() {}

        /**
         * 断开蓝牙
         */
        protected void onDisabled() {}

        /**
         * 蓝颜连接状态变化
         *
         * @param connect true:连接到第一个设备,false:断开最后一个设备
         * @param btDevice 当前设备
         */
        protected void onConnectionChanged(boolean connect, HashMap<String, Object> btDevice) {}

        /**
         * 有远程设备成功连接
         *
         * @param btDevice
         */
        protected void onDeviceConnected(HashMap<String, Object> btDevice) {}

        /**
         * 有远程设备断开连接
         *
         * @param btDevice
         */
        protected void onDeviceDisconnected(HashMap<String, Object> btDevice) {}
    }

    public interface BScanCallback {
        void onScan(ArrayList<HashMap<String, Object>> result);
    }
}

上一篇 下一篇

猜你喜欢

热点阅读