android4.3 nei内置了ble并为上层app提供相应的接口来使用BLE功能。
BLE主要涉及的协议及术语:
GenericAttribute Profile (GATT)
BLE上层的协议都是基于GATT,它是一个通用的规范,通过BLE连接发送/接收属性值。
bluetoothSIG定义了很多的ble协议。
AttributeProtocol (ATT)
GATT是建立在ATT之上。也被称为GATT/ATT。
ATT运行在ble设备上,所以被优化,尽可能的占用较少的字节。
每一个属性被指定一个UUID,通过ATT传输的属性被格式化位特性(characteristics)或服务(services)。
Characteristic
一个特性包含一个单一的值和0-n个描述符(Descriptor)来描述这个特性值。一个特性可以被看作一个类型。
Descriptor
描述符被定义为属性,这些属性用来描述特性的值。
例如:规定特性值的取值范围,特性值的单位等
Service
服务是一组特性的集合。例如:“心率检测”服务包含“心速测量”的特性。
角色和职责
中心与外围:被应用于BLE连接本身,中心角色设备扫描/寻找广播,外围设备角色发出广播。
GATTserver vs. GATT client:
这个决定了两个设备在建立连接之后如何交互。
android手机和BLE设备的区别:手机支持中心角色(centralrole),BLE设备支持peripheralrole。
一旦建立连接,他们就开始相互传输gatt数据,根据传输的数据的种类其中的一个可能作为服务器。
如果BLE设备想报告数据给手机,它可能让BLE设备的传感器作为服务器。如果BLE设备准备接收来自手机的数据,手机的传感器就作为服务端。
以上例子说明:androidapp 是GATT client,GATTclient 从GATT server 获取数据。也可以设计android app 作为GATTserver。
BLE权限:
|
如果想把app提供给不支持BLE的设备需要设置android:required="fasle",然后在运行时进行判断:
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); finish(); } |
设置BLE
1:获取BluetoothAdapter
BluetoothAdapter是所有蓝牙功能所必需的,整个系统只有一个BluetoothAdapter,获取BluetoothAdapter之后就可以进行各种蓝牙的操作了。
// Initializes Bluetooth adapter. final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); |
2:启动蓝牙
通过isEnabled()判断是否启动,如果没有启动,通过下面的方式启动:
private BluetoothAdapter mBluetoothAdapter; ... // Ensures Bluetooth is available on the device and it is enabled. If not, // displays a dialog requesting user permission to enable Bluetooth. if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } |
3:查找BLE设备
通过startLeScan查找LE设备,并实现LeScanCallback作为参数。
注意事项:1:一旦找到所查找的设备,立即停止扫描
2:设置扫描超时,避免循环扫描。
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); } ... } ... } |
如果需要查找特定类型的LE设备,需要使用startLeScan(UUID[],BluetoothAdapter.LeScanCallback()),提供一个你的设备支持的服务的UUID数组。
LeScanCallback
的实现:
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(); } }); } }; |
注意:要么搜索经典蓝牙,要么搜索BLE,两者不能同时搜索。
连接GATTserver
使用connectGatt连接到BLE设备的GATT server,
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
|
将会返回一个BluetoothGatt实例,通过这个实例可以进行Gattclient的各种操作。调用者(androidapp)是Gattclient。GattCallback用来提供结果给客户端。
读取BLE的属性
如果androidapp已经连接了Gatt server并且发现了服务,就能够进行属性的读写了。
收取Gatt的通知
通常BLEapp需要被通知,如果BLE设备的特性发生了改变。
使用setCharacteristicNotification方法为一个特性设置通知:
private BluetoothGatt mBluetoothGatt; BluetoothGattCharacteristic characteristic; boolean enabled; ... mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); ... BluetoothGattDescriptor descriptor = characteristic.getDescriptor( UUID.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG)); descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); mBluetoothGatt.writeDescriptor(descriptor); |
一旦一个特性被设置为通知可用,远端设备的特性发生改变就会触发onCharacteristicChanged
回调。
@Override // Characteristic notification public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic); } |
关闭clientapp
结束和BLE设备的通讯后,需要释放资源:
public void close() { if (mBluetoothGatt == null) { return; } mBluetoothGatt.close(); mBluetoothGatt = null; } |