目录
[TOC]
Bluetooth Low Energy
- 简介:
- 与传统蓝牙相比,低功耗蓝牙的设计对电量消耗更低。
- 只支持Android 4.3以上的系统版本,即 API Level>=18。
蓝牙开发对象
-
BluetoothManager
-
获取对象:
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
注意:BluetoothManager仅在Android4.3以上的系统版本支持,即 API Level>=18。
-
-
BluetoothAdapter
-
获取对象:
BluetoothAdapter mBluetoothAdapter = BluetoothManager.getAdapter(); // 或者 BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
- 注意:一个Android系统只有一个BluetoothAdapter。
-
方法描述:
- 蓝牙状态
- isEnabled()
- 判断系统蓝牙是否打开
- disable()
- 隐式关闭系统蓝牙
- enable()
- 隐式打开系统蓝牙
- isEnabled()
- 蓝牙设备搜索
- startDiscovery()/cancelDiscovery()
- 开始/取消搜索设备(经典蓝牙 和 低功耗蓝牙)
- 执行过程(耗时12秒):
- 系统发送 BluetoothAdapter.ACTIOIN_DISCOVERY_STARTED 的广播
- 搜索蓝牙设备...
- 只要找到一个设备就发送一个 BluetoothDevice.ACTION_FOUND 的广播
- 从广播接收器中就可以得到这个BluetoothDevice对象
- 系统发送 BluetoothAdapter.ACTION_FINISHED 的广播
- startLeScan()/stopLeScan()
- 开始/取消搜索设备(低功耗蓝牙)
- 注意:
- 在API Level-21以上被标记废弃使用
- startDiscovery()/cancelDiscovery()
- 蓝牙状态
-
-
BluetoothLeScanner
-
获取对象:
BluetoothLeScanner mBluetoothLeScanner= BluetoothAdapter.getBluetoothLeScanner();
-
方法描述:
- startScan()/stopScan()
- 开始/取消搜索设备(低功耗蓝牙)
- 注意:
- 在API Level-21以上使用
- startScan()/stopScan()
-
-
BluetoothDevice
- 代表了一个远程的蓝牙设备, 通过这个类可以查询远程设备的物理地址, 名称, 连接状态等信息,
- 获取对象:
-
物理地址对应的Device:
BluetoothAdapter.getRemoteDevice(address);
-
已经配对的Device集合:
BluetoothAdapter.getBoundedDevices();
-
扫描结果回调中的Device:
BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { } };
-
-
BluetoothGatt
- BluetoothGatt继承BluetoothProfile,
- 通过BluetoothGatt可以连接设备(connect),发现服务(discoverServices),并把相应地属性返回到 BluetoothGattCallback,
- 获取对象:
- BluetoothGattCallback回调方法中获取。
-
BluetoothProfile
- 一个通用的规范,按照这个规范来收发数据。
连接成功后,我们首先需要获得服务,然后是该服务所包含的特征,最后是特征的描述符。
-
服务(Service):
- BluetoothGattService
- 一个 Service 可以包含多个 Characteristic,
- 获取对象:
-
通过指定的 UUID 从 BluetoothGatt 实例中获得:
BluetoothGattService service = BluetoothGatt.getService(UUID.fromString(BLE_SERVICE));
-
- BluetoothGattService
-
特征(Characteristic):
- BluetoothGattCharacteristic
- 一个 Characteristic 包含一个 Value 和多个 Descriptor,
- 相当于一个数据类型,它包括一个value和0~n个value的描述(Descriptor),
- 获取对象:
-
通过指定的 UUID 从 BluetoothGattService 中得到:
BluetoothGattCharacteristic characteristic = BluetoothGattService.getCharacteristic(UUID.fromString(BLE_CHARACTERISTIC))
-
- BluetoothGattCharacteristic
-
描述符(Descriptor):
- BluetoothGattDescriptor
- 一个 Descriptor 包含一个 Value,
- 对 Characteristic 的描述,包括范围、计量单位等,
- 获取对象:
-
通过指定的 UUID 从 BluetoothGattCharacteristic 对象中获得:
List<BluetoothGattDescriptor> descriptorList = BluetoothGattCharacteristic.getDescriptors(); // 或者 BluetoothGattDescriptor descriptor = BluetoothGattCharacteristic.getDescriptor(UUID.fromString("BLE_DESCRIPTOR"));
-
- BluetoothGattDescriptor
低功耗蓝牙开发基本流程
-
申请权限
-
基础权限:
<!-- 执行所有的蓝牙通信,如请求连接,接受连接和传输数据 --> <uses-permission android:name="android.permission.BLUETOOTH"/> <!-- 初始化设备发现或者操纵蓝牙设置 --> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
-
注意:
- 如果应用仅支持低功耗蓝牙
-
在 AndroidManifest.xml 添加以下声明:
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
-
动态判断:
if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, "该设备不支持低功耗蓝牙", Toast.LENGTH_SHORT).show(); }
-
-
在 Android 6.0 及以上的系统版本,需动态申请位置权限。
如果应用没有位置权限,蓝牙扫描功能不能使用(其它蓝牙操作例如连接蓝牙设备和写入数据不受影响)。-
在 AndroidManifest.xml 添加以下声明:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> 或 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
-
动态申请:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION); } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case PERMISSION_REQUEST_COARSE_LOCATION: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // 权限申请成功,处理业务逻辑 } break; default: break; } }
-
- 如果应用仅支持低功耗蓝牙
-
-
是否支持蓝牙
BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); if (bluetoothManager.getAdapter() == null) { Toast.makeText(Context, "没有发现蓝牙模块", Toast.LENGTH_SHORT).show(); }
-
开启/关闭蓝牙
-
检查蓝牙是否开启
BluetoothAdapter.isEnabled();
-
开启
-
隐式开启
BluetoothAdapter.enable();
- 注意:
-
需要注册权限:
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
在 Android 6.0 及以上的系统版本,隐式开启依旧会提示用户。
-
- 注意:
-
显示开启
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUESTCODE_BLUETOOTH);
-
确认结果:
-
方法一:注册广播
IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);//蓝牙状态 intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);// 扫描开始 intentFilter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);// 扫描结束 registerReceiver(new BluetoothReceiver(), intentFilter); private class BluetoothReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) { switch (BluetoothAdapter.getDefaultAdapter().getState()) { case BluetoothAdapter.STATE_ON:// 打开 break; case BluetoothAdapter.STATE_OFF:// 关闭 break; case BluetoothAdapter.STATE_TURNING_OFF:// 蓝牙处于关闭过程中 break; case BluetoothAdapter.STATE_TURNING_ON:// 蓝牙处于打开过程中 break; default: break; } } } }
-
方法二:重写onActivityResult()
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) {//蓝牙开启成功 switch (requestCode) { case REQUESTCODE_BLUETOOTH: break; default: break; } } else if (resultCode == RESULT_CANCELED) {//蓝牙开启失败 ToastUtils.showShort("蓝牙开启失败,请手动开启蓝牙"); } }
-
-
前往系统设置界面
startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
-
-
-
关闭
-
隐式关闭
BluetoothAdapter.disable();
-
前往系统设置界面
startActivity(new Intent(Settings.ACTION_BLUETOOTH_SETTINGS));
-
-
-
扫描蓝牙设备
- 开启/关闭扫描设备
-
开启
-
扫描全部蓝牙设备
BluetoothAdapter.startLeScan(BluetoothAdapter.LeScanCallback callback)
-
只扫描含有特定 UUID Service 的蓝牙设备
BluetoothAdapter.startLeScan(UUID[] serviceUuids, BluetoothAdapter.LeScanCallback callback)
-
-
关闭
BluetoothAdapter.stopLeScan(BluetoothAdapter.LeScanCallback callback)
-
- 开启/关闭扫描设备
-
连接设备
BluetoothGatt BluetoothDevice.connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) {}
- autoConnect:表示是否需要自动连接。
- 设置为 true 表示如果设备断开了,会不断的尝试自动连接。
- 设置为 false 表示只进行一次连接尝试。
- BluetoothGattCallback:表示连接后进行的一系列操作的回调,共计9个回调方法,以下列举常用的5个。
-
连接状态变化
void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {}
-
执行BluetoothGatt.discoverServices();后回调,发现服务
void onServicesDiscovered(BluetoothGatt gatt, int status) {}
-
执行BluetoothGatt.writeCharacteristic();后回调,写入数据执行结果
void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {}
-
执行BluetoothGatt.setCharacteristicNotification();后回调,Characteristic值发生改变
void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {}
-
执行BluetoothGatt.writeDescriptor();后回调
void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {}
-
- autoConnect:表示是否需要自动连接。
-
发现服务
-
在onConnectionStateChange()中,判断连接状态,连接成功,搜索连接设备所支持的service
@Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); if (newState == BluetoothGatt.STATE_CONNECTED) {//连接成功 gatt.discoverServices();//搜索连接设备所支持的service } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {//连接断开 } }
-
discoverServices()被执行后,在onServicesDiscovered()中,获取指定UUID Service,存下BluetoothGatt对象
@Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); BluetoothGattService service = gatt.getService(UUID.fromString(BLE_SERVICE)); if (service != null) { mBluetoothGatt = gatt; } }
-
-
读写数据
- 写:
获取指定 UUID Serivce 的 BluetoothGattService 对象,
从而得到指定 UUID Characteristic 的 BluetoothGattCharacteristic 对象,将数据设置进去,
-
最后用 BluetoothGatt 对象向蓝牙设备写入数据
public void writeCharacteristic() { byte[] data = {0x00};//封包数据,根据硬件协议填写 BluetoothGattCharacteristic characteristic = mBluetoothGatt.getService(UUID.fromString(BLE_SERVICE)).getCharacteristic(UUID.fromString(BLE_WRITE)); characteristic.setValue(data);//设置数据 mBluetoothGatt.writeCharacteristic(characteristic);//写入设备 }
- 读:
在 writeCharacteristic() 调用后,
会走 onCharacteristicChanged() 回调,
在 BluetoothGattCharacteristic 对象中获取蓝牙设备传回的数据,
-
通过蓝牙硬件协议判断并做出相应处理。
@Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { super.onCharacteristicChanged(gatt, characteristic); byte[] value = characteristic.getValue(); switch (value[0]) {//判断协议,对应处理 case 0x00: break; default: break; } }
- 写:
-
断开连接
BluetoothGatt.disconnect(); BluetoothGatt.close();