直接上代码
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;
}
}
使用
private BluetoothHelper bluetoothHelper;
bluetoothHelper = new BluetoothHelper();
if (bluetoothHelper.isOpen()) {
Log.d("", "bt isOpen");
bluetoothHelper.scan();
} else {
Log.d("", "bt not Open");
}
参考链接
https://juejin.cn/post/6844903731796901902
https://www.cnblogs.com/Bytezero/p/16857725.html