简介
蓝牙发展至今经历了9个版本的更新。1.1、1.2、2.0、2.1、3.0、4.0、4.1、4.2、5.0。那么在1.x~3.0之间的我们称之为传统蓝牙,4.x开始的蓝牙我们称之为低功耗蓝牙也就是蓝牙ble,当然4.x版本的蓝牙也是向下兼容的。android手机必须系统版本4.3及以上才支持BLE API。蓝牙4.0较传统蓝牙也有很大大差别:
随着蓝牙技术由手机、游戏、耳机、便携电脑和汽车等传统应用领域向物联网、医疗等新领域的扩展,对低功耗的要求会越来越高。蓝牙4.0这种低功耗版本很快会占主导。
使用
今天我就单独写个demo来介绍下android里面的BLE怎么来进行数据传输的。(如果不了解传统蓝牙BT的开发 操作请看https://blog.csdn.net/weixin_35959554/article/details/85277269)
1.开启蓝牙权限
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
//6.0以上需要加上
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
//required设置为true 表示只能在支持BLE的安卓设备上安装运行该APP
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
2.判断手机是否支持ble
如果上面设置权限的时候required="false",那么就可能有设备不支持ble,所以得在进入activity时判断手机是否支持,不支持则退出程序。
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, "当前设备不支持蓝牙BLE,即将退出程序", Toast.LENGTH_SHORT).show();
finish();
}
3.获取蓝牙管理以及蓝牙适配器
如果不确定蓝牙是否打开,那么在初始化时请求打开蓝牙。
//context activity传递的上下文
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
context.startActivity(intent);
蓝牙打开后,开始获取适配器
BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
4.搜索蓝牙设备
BluetoothAdapter.LeScanCallback leScanCallback;
//搜索到设备后 会回调LeScanCallback接口
leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
//把获取到的设备保存到设备集合,用于后面显示和连接
if (!devices.contains(device)){
devices.add(device);
}
}
};
//开始搜索设备
bluetoothAdapter.startLeScan(leScanCallback);
//停止搜索设备
//bluetoothAdapter.stopLeScan(leScanCallback);
}
5.连接蓝牙设备
//_device为已选择了的设备 创建BluetoothDevice实例
BluetoothDevice remoteDevice = bluetoothAdapter.getRemoteDevice(_device.getAddress());
//开始打开device bluetoothGattCallback为连接后的回调
BluetoothGatt bluetoothGatt = remoteDevice.connectGatt(context, false, bluetoothGattCallback);
接口回调里面包含了很多操作,数据接收,连接反馈,获取服务等。
6.获取服务
/**
* 服务的UUID
*/
public static final String SERVICE_UUID ="6e400001-b5a3-f393-e0a9-e50e24dcca9e";
/**
* 订阅通知的UUID
*/
public static final String NOTIFY_UUID = "6e400003-b5a3-f393-e0a9-e50e24dcca9e";
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
gattService = gatt.getService(UUID.fromString(SERVICE_UUID));// 获取到服务的通道
bluetoothGatt = gatt;
//获取到Notify的Characteristic通道 这个根据协议来定 如果设备厂家给的协议不是Notify的话 就不用做以下操作了
BluetoothGattCharacteristic notifyCharacteristic = gattService.getCharacteristic(UUID.fromString(NOTIFY_UUID));
enableNotification(gatt, true, notifyCharacteristic);//注册Notify通知
}
/**
* 是否开启蓝牙的通知
*
* @param enable
* @param characteristic
* @return
*/
public static boolean enableNotification(BluetoothGatt bluetoothGatt, boolean enable, BluetoothGattCharacteristic characteristic) {
if (bluetoothGatt == null || characteristic == null) {
return false;
}
if (!bluetoothGatt.setCharacteristicNotification(characteristic, enable)) {
return false;
}
//获取到Notify当中的Descriptor通道 然后再进行注册
BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(UUID.fromString(NOTIFY_DESCRIPTOR));
if (clientConfig == null) {
return false;
}
if (enable) {
clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
} else {
clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
}
return bluetoothGatt.writeDescriptor(clientConfig);
}
这些UUID可能会不相同,一般硬件哥哥会提供,也可以自己使用工具软件查看UUID。
7.连接状态反馈
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
switch (newState) {//对蓝牙反馈的状态进行判断
case BluetoothProfile.STATE_CONNECTED://已链接
sentConMsg("蓝牙连接成功");
gatt.discoverServices();
break;
case BluetoothProfile.STATE_DISCONNECTED://已断开
sentConMsg("蓝牙已断开");
break;
}
}
连接状态通过sentConMsg回调接口反馈给UI显示。
8.接收数据
连接成功后,如果硬件有发送数据,不出意外的话,onCharacteristicChanged中将持续接收硬件发送的数据。
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
//接收到的byte数组
byte[] value = characteristic.getValue();
//实时传递数据给数据接口,供程序使用
}
9.发送数据
/**
* 写出数据的UUID
*/
public static final String WRITE_UUID = "00006a02-0000-1000-8000-00805f9b34fb";
/**
* 向蓝牙写入数据
* @param data
*/
public boolean writeBuletoothData(String data) {
BluetoothGattCharacteristic writeCharact = gattService.getCharacteristic(UUID.fromString(WRITE_UUID));
bluetoothGatt.setCharacteristicNotification(writeCharact, true); // 设置监听
// 当数据传递到蓝牙之后
// 会回调BluetoothGattCallback里面的write方法
writeCharact.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
// 将需要传递的数据 打碎成16进制
writeCharact.setValue(getHexBytes(data));
return bluetoothGatt.writeCharacteristic(writeCharact);
}
10.关闭连接
bluetoothGatt.close();
完整工具类:
public class Bluetooth4Helper {
//连接的协议
private String MY_UUID = "00001101-0000-1000-8000-00805F9B34FB";
/**
* 服务的UUID
*/
public static final String SERVICE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
/**
* 订阅通知的UUID
*/
public static final String NOTIFY_UUID = "6e400003-b5a3-f393-e0a9-e50e24dcca9e";
/**
* 写出数据的UUID
*/
public static final String WRITE_UUID = "00006a02-0000-1000-8000-00805f9b34fb";
/**
* NOTIFY里面的Descriptor UUID
*/
public static final String NOTIFY_DESCRIPTOR = "00002902-0000-1000-8000-00805f9b34fb";
private static Bluetooth4Helper bluetoothHelper;
private static Context context;
private static BluetoothDevice _device = null;
private Timer _Timer = null;
private int _Datatime = 0;
private Set<BluetoothDevice> devices = new HashSet<>();
private BluetoothAdapter bluetoothAdapter;
private BluetoothManager bluetoothManager;//蓝牙管理者
private BluetoothGattService gattService;//通道服务
private BluetoothGatt bluetoothGatt;
private BluetoothDevice remoteDevice;
public static Bluetooth4Helper getInstance(Context con) {
if (null == bluetoothHelper) {
bluetoothHelper = new Bluetooth4Helper();
context = con;
}
return bluetoothHelper;
}
public void init() {
//系统会显示对话框,允许后直接打开
Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
context.startActivity(intent);
//其次获取到蓝牙的管理类:
bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
}
BluetoothAdapter.LeScanCallback leScanCallback;
public void startLeScan() {
//stopLeScan();防止重复搜索
devices.clear();
//搜索到设备后 会回调LeScanCallback接口
leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if (!devices.contains(device)) {
devices.add(device);
}
}
};
//开始搜索
bluetoothAdapter.startLeScan(leScanCallback);
_Timer = new Timer();
_Timer.schedule(new DataTimer(), 0, 1000);
}
public void stopLeScan() {
//停止扫描
bluetoothAdapter.stopLeScan(leScanCallback);
if (_Timer != null) {
_Timer.cancel();
_Timer = null;
_Datatime = 0;
}
}
public void open(String address) {
//close();
if (bluetoothGatt != null && bluetoothGatt.connect()) {
bluetoothGatt.close();
}
if (devices != null && devices.size() > 0) {
for (BluetoothDevice dev : devices) {
if (address != null && address.equals(dev.getAddress())) {
_device = dev;
break;
} else if (address == null) {
_device = dev;
break;
}
}
}
if (_device != null) {
//创建一个 BluetoothDevice 类实例
remoteDevice = bluetoothAdapter.getRemoteDevice(_device.getAddress());
//开始连接本设备
bluetoothGatt = remoteDevice.connectGatt(context, false, new BluetoothGattCallback() {
@Override
public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
super.onPhyUpdate(gatt, txPhy, rxPhy, status);
}
@Override
public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
super.onPhyRead(gatt, txPhy, rxPhy, status);
}
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
switch (newState) {//对蓝牙反馈的状态进行判断
case BluetoothProfile.STATE_CONNECTED://已连接
sentConMsg("蓝牙连接成功");
gatt.discoverServices();
break;
case BluetoothProfile.STATE_DISCONNECTED://已断开
sentConMsg("蓝牙已断开");
break;
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
gattService = gatt.getService(UUID.fromString(SERVICE_UUID));// 获取到服务的通道
bluetoothGatt = gatt;
//获取到Notify的Characteristic通道 这个根据协议来定 如果设备厂家给的协议不是Notify的话 就不用做以下操作了
BluetoothGattCharacteristic notifyCharacteristic = gattService.getCharacteristic(UUID.fromString(NOTIFY_UUID));
enableNotification(gatt, true, notifyCharacteristic);//注册Notify通知
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
String data = bytesToHexString(characteristic.getValue()); // 将字节转化为String字符串
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
byte[] value = characteristic.getValue();
byte[] temp = new byte[value.length];
System.arraycopy(value, 0, temp, 0, value.length);
sentData(temp);
}
});
}
}
/**
* 向蓝牙写入数据
*
* @param data
*/
public boolean writeBuletoothData(String data) {
BluetoothGattCharacteristic writeCharact = gattService.getCharacteristic(UUID.fromString(WRITE_UUID));
bluetoothGatt.setCharacteristicNotification(writeCharact, true); // 设置监听
// 当数据传递到蓝牙之后
// 会回调BluetoothGattCallback里面的write方法
writeCharact.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
// 将需要传递的数据 打碎成16进制
writeCharact.setValue(getHexBytes(data));
return bluetoothGatt.writeCharacteristic(writeCharact);
}
//得到当前连接蓝牙名称
public String getDeviceName() {
if (_device != null) {
return _device.getName();
}
return "";
}
//得到已配对蓝牙列表
public Set<BluetoothDevice> getDevices() {
if (devices != null) {
return devices;
}
return new HashSet<>();
}
//关闭蓝牙连接
public void close() {
if (_Timer != null) {
_Timer.cancel();
_Timer = null;
_Datatime = 0;
}
if (bluetoothGatt != null)
bluetoothGatt.close();
if (_device != null) {
_device = null;
}
}
//在3秒内持续没有数据 那么判定蓝牙断开
private class DataTimer extends TimerTask {
@Override
public void run() {
_Datatime++;
if (_Datatime > 5) {
stopLeScan();
}
}
}
/**
* 数据传输事件
*/
private List<GetTerminalDataListener> lsDatas;
public void addGetData(GetTerminalDataListener dataListener) {
if (lsDatas == null) {
lsDatas = new ArrayList<>();
}
lsDatas.add(dataListener);
}
public void removeGetData(GetTerminalDataListener dataListener) {
if (lsDatas == null) {
lsDatas = new ArrayList<>();
}
lsDatas.remove(dataListener);
}
private Handler DataHandler = new Handler() {
public void handleMessage(Message msg) {
if (lsDatas == null)
return;
for (GetTerminalDataListener item : lsDatas) {
item.getTerminalData((TerminalLocationInfo) msg.obj);
}
}
};
//发送数据
private void sentData(byte[] data) {
Message message = Message.obtain();
message.obj = data;
DataHandler.sendMessage(message);
}
//发送状态
private void sentConMsg(String msg) {
Message message = Message.obtain();
message.obj = msg;
ConnetHandler.sendMessage(message);
}
/**
* 连接状态事件
*/
private List<ConnectStateListener> lstConnect;
public void addConnectState(ConnectStateListener connectStateListener) {
if (lstConnect == null) {
lstConnect = new ArrayList<>();
}
lstConnect.add(connectStateListener);
}
public void removeConnectState(ConnectStateListener connectStateListener) {
if (lstConnect == null) {
lstConnect = new ArrayList<>();
}
lstConnect.remove(connectStateListener);
}
private Handler ConnetHandler = new Handler() {
public void handleMessage(Message msg) {
if (lstConnect == null)
return;
for (ConnectStateListener item : lstConnect) {
item.ConnectState((String) msg.obj);
}
}
};
/**
* 是否开启蓝牙的通知
*
* @param enable
* @param characteristic
* @return
*/
public static boolean enableNotification(BluetoothGatt bluetoothGatt, boolean enable, BluetoothGattCharacteristic characteristic) {
if (bluetoothGatt == null || characteristic == null) {
return false;
}
if (!bluetoothGatt.setCharacteristicNotification(characteristic, enable)) {
return false;
}
//获取到Notify当中的Descriptor通道 然后再进行注册
BluetoothGattDescriptor clientConfig = characteristic.getDescriptor(UUID.fromString(NOTIFY_DESCRIPTOR));
if (clientConfig == null) {
return false;
}
if (enable) {
clientConfig.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
} else {
clientConfig.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE);
}
return bluetoothGatt.writeDescriptor(clientConfig);
}
/**
* 将字节 转换为字符串
*
* @param src 需要转换的字节数组
* @return 返回转换完之后的数据
*/
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
/**
* 将字符串转化为16进制的字节
*
* @param message 需要被转换的字符
* @return
*/
public static byte[] getHexBytes(String message) {
int len = message.length() / 2;
char[] chars = message.toCharArray();
String[] hexStr = new String[len];
byte[] bytes = new byte[len];
for (int i = 0, j = 0; j < len; i += 2, j++) {
hexStr[j] = "" + chars[i] + chars[i + 1];
bytes[j] = (byte) Integer.parseInt(hexStr[j], 16);
}
return bytes;
}
}
使用实例:
//初始化工具类
Bluetooth4Helper.getInstance(this).init();
//点击按钮开始搜索蓝牙设备 搜索结果通过RecyclerView等展示到界面上
Bluetooth4Helper.getInstance(this).startLeScan();
Set<BluetoothDevice> devices = Bluetooth4Helper.getInstance(this).getDevices();
//选中显示的蓝牙设备 并把设备地址address名传过去
Bluetooth4Helper.getInstance(this).open(address);
//添加得到 蓝牙数据 和 连接状态信息 的事件
Bluetooth4Helper.getInstance(this).addGetData(this);
Bluetooth4Helper.getInstance(this).addConnectState(this);
//退出程序释放全部
Bluetooth4Helper.getInstance(this).removeConnectState(this);
Bluetooth4Helper.getInstance(this).removeGetData(this);
Bluetooth4Helper.getInstance(this).close();
总结
蓝牙4.0到这就介绍完了,主要是介绍下怎么使用,如果有讲错的地方请哥哥些多多包涵,总的来说不管是BT蓝牙还是BLE蓝牙还是其他USB等,连接方式都是那几个套路。当你消化掉其中一种时,加把劲理解其他的东西应该都不是很困难的事。突然发现明天是1024,还是要自己给自己过过节(奖励bug一坨……)。