Android 蓝牙(4.0)BLE开发 扫描IBeacon
程序员文章站
2024-03-24 23:01:52
...
一.扫描蓝牙设备
1. 在程序manifest文件中添加声明蓝牙权限的代码。
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
如果想让程序只能在支持BLE设备上运行的,可将下面的代码添加到manifest文件中去:
<uses-featue android:name=”android.hardwoare.bletooth_le”android:required=”ture”/>
2. 获取运行时权限
int permission = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION); if (permission == PackageManager.PERMISSION_GRANTED) { //执行开始扫描 }else { //申请权限 ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION, 1}); }
3. 扫描蓝牙
扫描蓝呀设备主要用到BluetoothManager和BluetoothAdapter两个类。首先获取蓝牙服务,然后获通过蓝牙服务获取蓝牙适配器,最后在通过蓝牙适配器来开启蓝牙扫描。扫描到蓝牙设备后就调用回调接口,回掉接口有两种分别是LeScanCallback和ScanCallback; 其中LeScanCallback现在已经废弃(仍然能使用)。
代码:
第一种扫描://获取蓝牙adapter BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
bluetoothAdapter.startLeScan(callback); // 开始扫描 bluetoothAdapter.stopLeScan(callback); // 停止扫描
蓝牙扫描回调
private BluetoothAdapter.LeScanCallback callback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { /** * device:BluetoothDevice类对象,通过该对象可以得到MAC地址、设备名称等信息 * rssi:蓝牙设备场强值 * scanRecord - 这里内容比较丰富,像UUID、Major、Minor都在这里 */ IBeaconRecord record = new IBeaconRecord(); if (fromScanData(scanRecord, record)) { String address = device.getAddress(); // 获取Mac地址 String name = device.getName(); // 获取设备名称 record.address = address; // Mac地址 record.rssi = rssi; // 场强 if (mapBltScanResult.containsKey(key)) { mapBltScanResult.get(key).add(record); } else { ArrayList<IBeaconRecord> list = new ArrayList<>(); list.add(record); mapBltScanResult.put(key, list); } } } }; /** * 解析蓝牙信息数据流 (此段代码来源于网络) * @param 设备蓝牙扫描到的字节数组 * @param record 用来保存解析出来的蓝牙数据 * @return Boolean */ private boolean fromScanData(byte[] scanData, IBeaconRecord record) { int startByte = 2; boolean patternFound = false; while (startByte <= 5) { if (((int) scanData[startByte + 2] & 0xff) == 0x02 && ((int) scanData[startByte + 3] & 0xff) == 0x15) { // yes! This is an iBeacon patternFound = true; break; } else if (((int) scanData[startByte] & 0xff) == 0x2d && ((int) scanData[startByte + 1] & 0xff) == 0x24 && ((int) scanData[startByte + 2] & 0xff) == 0xbf && ((int) scanData[startByte + 3] & 0xff) == 0x16) { return false; } else if (((int) scanData[startByte] & 0xff) == 0xad && ((int) scanData[startByte + 1] & 0xff) == 0x77 && ((int) scanData[startByte + 2] & 0xff) == 0x00 && ((int) scanData[startByte + 3] & 0xff) == 0xc6) { return false; } startByte++; } if (patternFound == false) { // This is not an iBeacon return false; } // 获得Major属性 record.major = (scanData[startByte + 20] & 0xff) * 0x100 + (scanData[startByte + 21] & 0xff); record.txPower = (int)scanData[startByte+24]; // 获得Minor属性 record.minor = (scanData[startByte + 22] & 0xff) * 0x100 + (scanData[startByte + 23] & 0xff); // record.tx_power = (int) scanData[startByte + 24]; // this one is try { byte[] proximityUuidBytes = new byte[16]; System.arraycopy(scanData, startByte + 4, proximityUuidBytes, 0, 16); String hexString = bytesToHex(proximityUuidBytes); StringBuilder sb = new StringBuilder(); sb.append(hexString.substring(0, 8)); sb.append("-"); sb.append(hexString.substring(8, 12)); sb.append("-"); sb.append(hexString.substring(12, 16)); sb.append("-"); sb.append(hexString.substring(16, 20)); sb.append("-"); sb.append(hexString.substring(20, 32)); // beacon.put("proximity_uuid", sb.toString()); // 获得UUID属性 record.uuid = sb.toString(); } catch (Exception e) { e.printStackTrace(); } return true; } private char[] hexArray = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; private String bytesToHex(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; int v; for (int j = 0; j < bytes.length; j++) { v = bytes[j] & 0xFF; hexChars[j * 2] = hexArray[v >>> 4]; hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } return new String(hexChars); }
第二种扫描:
由于此方式仅支持Android 5.0以上的系统,所以在使用时需判断当前系统版本
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { mBluetoothAdapter.getBluetoothLeScanner().startScan(callback); // 开始扫描 mBluetoothAdapter.getBluetoothLeScanner().stopScan(callback); // 停止扫描 }
ScanCallback callback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { super.onScanResult(callbackType, result); result.getRssi(); // 场强 result.getTxPower(); // 距离设备1米的时候的信号强度 result.getDevice().getAddress(); // 设备MAC地址 result.getDevice().getName(); // 设备名 } @Override public void onBatchScanResults(List<ScanResult> results) { super.onBatchScanResults(results); } @Override public void onScanFailed(int errorCode) { super.onScanFailed(errorCode); } };