/** * 查找低功耗蓝牙,该方法在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>>()); } } |