Android Bluetooth BLE receives broadcast data such as ibeacon

Directly on the code
BtParseInfo.java

package com.benew.testm;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.List;
import java.util.UUID;

/**
 * 保存蓝牙广播数据
 */
public class BtParseInfo {
    
    

    private byte flags;
    private List<UUID> uuids;
    private String localName;
    private Short manufacturer;

    BtParseInfo(byte[] advData) {
    
    
        // 5.0以下版本, 由BluetoothAdapter.LeScanCallback回调得到advData
        ByteBuffer buffer = ByteBuffer.wrap(advData).order(ByteOrder.LITTLE_ENDIAN);
        while (buffer.remaining() > 2) {
    
    
            byte length = buffer.get();
            if (length == 0)
                break;

            byte type = buffer.get();
            length -= 1;
            switch (type) {
    
    
                case 0x01: // Flags
                    /**
                     * bit 0: LE 有限发现模式
                     * bit 1: LE 普通发现模式
                     * bit 2: 不支持 BR/EDR
                     * bit 3: 对 Same Device Capable(Controller) 同时支持 BLE 和 BR/EDR
                     * bit 4: 对 Same Device Capable(Host) 同时支持 BLE 和 BR/EDR
                     * bit 5..7: 预留
                     */
                    this.flags = buffer.get();
                    length--;
                    break;
                case 0x02: // Partial list of 16-bit UUIDs
                case 0x03: // Complete list of 16-bit UUIDs
                case 0x14: // List of 16-bit Service Solicitation UUIDs
                    /**
                     * 非完整的 16 bit UUID 列表: TYPE = 0x02;
                     * 完整的 16 bit UUID 列表: TYPE = 0x03;
                     * 非完整的 32 bit UUID 列表: TYPE = 0x04;
                     * 完整的 32 bit UUID 列表: TYPE = 0x05;
                     * 非完整的 128 bit UUID 列表: TYPE = 0x06;
                     * 完整的 128 bit UUID 列表: TYPE = 0x07;
                     * 16 bit UUID 列表: TYPE = 0x14
                     * 32 bit UUID 列表: TYPE = 0x??
                     * 128 bit UUID 列表: TYPE = 0x15
                     */
                    while (length >= 2) {
    
    
                        this.uuids.add(UUID.fromString(String.format(
                                "%08x-0000-1000-8000-00805f9b34fb", buffer.getShort())));
                        length -= 2;
                    }
                    break;
                case 0x04: // Partial list of 32 bit service UUIDs
                case 0x05: // Complete list of 32 bit service UUIDs
                    while (length >= 4) {
    
    
                        this.uuids.add(UUID.fromString(String.format(
                                "%08x-0000-1000-8000-00805f9b34fb", buffer.getInt())));
                        length -= 4;
                    }
                    break;
                case 0x06: // Partial list of 128-bit UUIDs
                case 0x07: // Complete list of 128-bit UUIDs
                case 0x15: // List of 128-bit Service Solicitation UUIDs
                    while (length >= 16) {
    
    
                        long lsb = buffer.getLong();
                        long msb = buffer.getLong();
                        this.uuids.add(new UUID(msb, lsb));
                        length -= 16;
                    }
                    break;
                case 0x08: // Short local device name
                case 0x09: // Complete local device name
                    /**
                     * 设备全名: TYPE = 0x08
                     * 设备简称: TYPE = 0x09
                     */
                    byte sb[] = new byte[length];
                    buffer.get(sb, 0, length);
                    length = 0;
                    this.localName = new String(sb).trim();
                    break;
                case (byte) 0xFF: // Manufacturer Specific Data
                    /**
                     * 厂商自定义数据: TYPE = 0xFF
                     * 厂商自定义的数据中,前两个字节表示厂商 ID,剩下的是厂商自己按照需求添加,里面的数据内容自己定义
                     */
                    this.manufacturer = buffer.getShort();
                    length -= 2;
                    break;
                default: // skip
                    break;
            }
            if (length > 0) {
    
    
                buffer.position(buffer.position() + length);
            }
        }
    }

    public byte getFlags() {
    
    
        return flags;
    }

    public List<UUID> getUuids() {
    
    
        return uuids;
    }

    public String getLocalName() {
    
    
        return localName;
    }

    public Short getManufacturer() {
    
    
        return manufacturer;
    }
}

BluetoothHelper.java

package com.benew.testm;

import static android.bluetooth.le.ScanSettings.SCAN_MODE_LOW_LATENCY;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.Log;

import java.util.List;

public class BluetoothHelper {
    
    

    private static final String TAG = "BluetoothHelper";
    private BluetoothAdapter mBluetoothAdapter;
    private BluetoothLeScanner mBLEScanner;
    private ScanSettings mScanSettings;

    // 不同版本回调写法不一样
    private BluetoothAdapter.LeScanCallback mLeScanCallback;
    private ScanCallback mScanCallback;
    private boolean mScanning = false;

    BluetoothHelper() {
    
    
        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    }

    /**
     * 打开蓝牙
     * @return
     */
    public boolean open(){
    
    
        return mBluetoothAdapter != null &&  mBluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF && mBluetoothAdapter.enable();
    }

    /**
     * 关闭蓝牙
     * @return
     */
    public boolean close(){
    
    
        return isOpen() && mBluetoothAdapter.disable();
    }

    /**
     * 是否打开蓝牙
     *
     * @return
     */
    public boolean isOpen() {
    
    
        return mBluetoothAdapter != null && mBluetoothAdapter.isEnabled();
    }

    public void scan() {
    
    
        //如果没打开蓝牙,不进行扫描操作,或请求打开蓝牙。
        if(mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
    
    
            return;
        }
        //处于未扫描的状态
        if (!mScanning){
    
    
            //android 5.0后
            if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    
    
                //标记当前的为扫描状态
                mScanning = true;
                //获取5.0新添的扫描类
                if (mBLEScanner == null){
    
    
                    //mBLEScanner是5.0新添加的扫描类,通过BluetoothAdapter实例获取。
                    mBLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
                }
                mScanSettings = getScanSettings();
                mScanCallback = getScanCallback();
                //开始扫描
                //mScanSettings是ScanSettings实例,mScanCallback是ScanCallback实例,后面进行讲解。
                mBLEScanner.startScan(null, mScanSettings, mScanCallback);
            } else {
    
    
                mLeScanCallback = getLeScanCallback();
                //标记当前的为扫描状态
                mScanning = true;
                //5.0以下  开始扫描
                //mLeScanCallback是BluetoothAdapter.LeScanCallback实例
                mBluetoothAdapter.startLeScan(mLeScanCallback);
            }
        }
    }

    public void stopScan() {
    
    
        //停止扫描设备
        if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    
    
            //标记当前的为未扫描状态
            mScanning = false;
            mBLEScanner.stopScan(mScanCallback);
        } else {
    
    
            //标记当前的为未扫描状态
            mScanning = false;
            //5.0以下  停止扫描
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }
    }

    private BluetoothAdapter.LeScanCallback getLeScanCallback() {
    
    
        if (mLeScanCallback == null) {
    
    
            //5.0以下版本
            mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
    
    
                @Override
                public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
    
    
                    //对扫描到的设备进行操作。如:获取设备信息。
                    BtParseInfo btParseInfo = new BtParseInfo(scanRecord);
                }
            };
        }
        return mLeScanCallback;
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private ScanCallback getScanCallback() {
    
    
        // 5.0及以上版本
        if (mScanCallback == null) {
    
    
            mScanCallback = new ScanCallback() {
    
    
                //当一个蓝牙ble广播被发现时回调
                @Override
                public void onScanResult(int callbackType, ScanResult result) {
    
    
                    super.onScanResult(callbackType, result);
                    //扫描类型有开始扫描时传入的ScanSettings相关
                    //对扫描到的设备进行操作。如:获取设备信息。
                    parseScanResult(result);
                }

                //批量返回扫描结果
                //@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无法注册,无法开始扫描。
                    Log.d("", "onScanFailed:" + errorCode);
                }
            };
        }
        return mScanCallback;
    }

    /**
     * 解析扫描结果
     * @param scanResult
     */
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void parseScanResult(ScanResult scanResult) {
    
    
        BluetoothDevice device = scanResult.getDevice();
        Log.d(TAG, "newDevice:" + device.getAddress() + "  " + device.getName());
        Log.d(TAG, "scanRecord:" + scanResult.getScanRecord().toString());
        Log.d(TAG, "scanRecord getManufacturerSpecificData:" + scanResult.getScanRecord().getManufacturerSpecificData().toString());
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private ScanSettings getScanSettings() {
    
    
        // 5.0及以上版本
        if (mScanSettings == null) {
    
    
            //创建ScanSettings的build对象用于设置参数
            ScanSettings.Builder builder = new ScanSettings.Builder()
                    //设置高功耗模式
                    .setScanMode(SCAN_MODE_LOW_LATENCY);
            //android 6.0添加设置回调类型、匹配模式等
            if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    
    
                //定义回调类型
                builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
                //设置蓝牙LE扫描滤波器硬件匹配的匹配模式
                builder.setMatchMode(ScanSettings.MATCH_MODE_STICKY);
            }
            //芯片组支持批处理芯片上的扫描
            if (mBluetoothAdapter.isOffloadedScanBatchingSupported()) {
    
    
                //设置蓝牙LE扫描的报告延迟的时间(以毫秒为单位)
                //设置为0以立即通知结果
                builder.setReportDelay(0L);
            }
            mScanSettings = builder.build();
        }
        return mScanSettings;
    }

}

use

private BluetoothHelper bluetoothHelper;
bluetoothHelper = new BluetoothHelper();
if (bluetoothHelper.isOpen()) {
    
    
    Log.d("", "bt isOpen");
    bluetoothHelper.scan();
} else {
    
    
    Log.d("", "bt not Open");
}

reference link

https://juejin.cn/post/6844903731796901902
https://www.cnblogs.com/Bytezero/p/16857725.html

Guess you like

Origin blog.csdn.net/zmlovelx/article/details/129856857