欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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);
        }
    };