最近项目中使用到蓝牙打印机,通过蓝牙连接蓝牙打印机进行打印功能。在此对蓝牙知识进行归纳输出一波,达到巩固之效果。
蓝牙开发《基础篇一》
蓝牙开发《基础篇二》
BLE 蓝牙开发
英文: Bluetooth Low Energy.
版本要求:Android 18 之前 Android4.3版本以上才支持
官方文档:Bluetooth Low Energy
用处
可用于 Android 设备与智能设备间进行蓝牙通讯。
与经典的蓝牙对比
BLE 是低功耗型的,专门适用于 Android 设备与那些对电源有显著要求的 ble 设备,例如一些传感器之类的。
基本概念
Generic Attribute Profile (GATT)
Attribute Protocol (ATT) 属性协议,ATT 是经过优化了,可运行在 BLE 设备上,每一个属性都会有一个有一个 UUID(128bit) 保证唯一性。通过 ATT 传输的属性被格式为为 Characteristic 和 service
Characteristic 包含一个值 value 和 0-n 个 descriptor ,该 descriptor 是用于描述 value 。
Descriptor 被用于描述特征值的,可以指定一个描述,一个特征值的范围,或者特征值的度量单位
service 特征值的集合。
角色和职责
在 Android 设备和 BLE 设备进行交互时的角色和职责
角色:
中央角色 Central
外设角色 peripheral
两个相同角色的设备是不能进行相互通讯的
client
接收数据端
运行 android 程序的一端就是 GATT client
server
发送数据端
GATT server 端(BLE设备)
也可以让手机设备作为 GATT server 端
权限设置
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
注意:android:required="true"当你想将app必须运行在支持BLE的设备,否则应该设置为false
当 android:required="false" 时,表示应用可以运行在非 BLE 设备上,可以通过相关的代码进行检测。
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show();
finish();
}
BLE 设置-准备工作
-
检测设备是否支持 BLE 特性
必须在 manifest 的 android:required="false"
如果支持 BLE 但是没开启,那么就要通过 intent 的方式开启
获取 BluetoothAdapter
private BluetoothAdapter mBluetoothAdapter;
...
// Initializes Bluetooth adapter.
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
- 检测蓝牙是否可用(前提支持BLE)
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
查找 BLE 设备
通过 BluetoothAdapter.startLeScan 方法进行扫描,并且扫描结果会回调到 BluetoothAdapter.LeScanCallback 中
BluetoothAdapter.startLeScan(BluetoothAdapter.LeScanCallback )
public class DeviceScanActivity extends ListActivity {
private BluetoothAdapter mBluetoothAdapter;
private boolean mScanning;
private Handler mHandler;
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;
...
private void scanLeDevice(final boolean enable) {
if (enable) {
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}, SCAN_PERIOD);
mScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
} else {
mScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
...
}
...
}
private LeDeviceListAdapter mLeDeviceListAdapter;
...
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
} };
注意:
当扫描到指定的设备时应该停止扫描。
因为 startLeScan 是比较耗电的一个过程,需要设置一个扫描的时间限制。
不能同时扫描 BLE 和 经典蓝牙设备。
连接 GATT Server
由 GATT client 去调用 connectGatt 方法进行和 GATT Server 进行连接。
this 表示上下文
false 表示是否自动连接
-
mGattCallback 用于传输结果给客户端,例如连接的状态,客户端的一些操作
BluetoothGatt bluetoothGatt = device.connectGatt(this, false, mGattCallback); mGattCallback public void onConnectionStateChange(BluetoothGatt gatt, int status,int newState) //远程servier,characteristics,descriptor有更新时 public void onServicesDiscovered(BluetoothGatt gatt, int status) //通知一个特征值读的结果 public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,int status) // public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status)
总结
开发中遇到的问题
c语言与java语言出现数据的大小端问题。
数据超过20字节需要分包发送,20个字节是有head和data组成的。
每一子包的发送间隔在20ms。