# Android BLE
**Repository Path**: leesonzhong/android-ble
## Basic Information
- **Project Name**: Android BLE
- **Description**: android平台上连接ble(蓝牙低功耗设备)的demo,包含打开、扫描蓝牙、连接、通信、断开连接各种功能。
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 5
- **Forks**: 4
- **Created**: 2021-04-22
- **Last Updated**: 2024-08-11
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 一、蓝牙BLE
- 蓝牙是一种短距的无线通讯技术,可实现固定设备、移动设备之间的数据交换。一般将蓝牙3.0之前的BR/EDR蓝牙称为传统蓝牙,而将蓝牙4.0规范下的LE蓝牙称为低功耗蓝牙(BLE)。
- 蓝牙4.0标准包括传统蓝牙模块部分和低功耗蓝牙模块部分,是一个双模标准。低功耗蓝牙也是建立在传统蓝牙基础之上发展起来的,并区别于传统模块,最大的特点就是成本和功耗降低,应用于实时性要求比较高。
- 在BLE协议中,有两个角色,周边(Periphery)和中央(Central);周边是数据提供者,中央是数据使用/处理者,一个中央可以同时连接多个周边,但是一个周边某一时刻只能连接一个中央。
首先使用蓝牙就不得不说BluetoothGatt和BluetoothGattCallback这两个类,该类继承自BluetoothProfile,BluetoothGatt作为中央来使用和处理数据,通过BluetoothGatt可以连接设备(connect),发现服务(discoverServices),并把相应地属性返回到BluetoothGattCallback,BluetoothGattCallback返回中央的状态和周边提供的数据。
# 二、开发BLE安卓应用
- 参考网址https://www.jianshu.com/p/2dba7f067372,android蓝牙BLE(一) —— 扫描
- 新建工程。在工程的AndroidManifest添加蓝牙权限
```
```
在Activity也要动态申请权限,添加下面代码,在启动蓝牙功能前调用initPermission方法申请权限。
```
//申请多个权限
//1、首先声明一个数组permissions,将需要的权限都放在里面
String[] permissions = new String[]{Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION};
//2、创建一个mPermissionList,逐个判断哪些权限未授予,未授予的权限存储到mPerrrmissionList中
List mPermissionList = new ArrayList<>();
private final int mRequestCode = 200;//权限请求码
//权限判断和申请
private void initPermission() {
mPermissionList.clear();//清空没有通过的权限
//逐个判断你要的权限是否已经通过
for (int i = 0; i < permissions.length; i++) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission( permissions[i]) != PackageManager.PERMISSION_GRANTED) {
mPermissionList.add(permissions[i]);//添加还未授予的权限
}
}
}
//申请权限
if (mPermissionList.size() > 0) {//有权限没有通过,需要申请
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(permissions, mRequestCode);
}
}
}
@Override
public void onRequestPermissionsResult(int permsRequestCode, String[] permissions, int[] grantResults) {
switch (permsRequestCode) {
case 200:{
initPermission();
}break;
}
}
```
- 获取BluetoothManager和BluetoothAdapt,BluetoothAdapt具备启动蓝牙和扫描蓝牙列表的功能。
```
//首先获取BluetoothManager
BluetoothManager bluetoothManager=(BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
//获取BluetoothAdapter
BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
```
- 判断蓝牙是否开启,蓝牙开启后开始扫描。
```
if (!mBluetoothAdapter.isEnabled()) {
boolean enable = mBluetoothAdapter.enable(); //返回值表示 是否成功打开了蓝牙功能
if (enable){
return;
}
}
if(android.os.Build.VERSION.SDK_INT >= 21) {
//标记当前的为扫描状态
mScanning = true;
//获取5.0新添的扫描类
if (mBLEScanner == null){
//mBLEScanner是5.0新添加的扫描类,通过BluetoothAdapter实例获取。
mBLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
}
//开始扫描
//mScanCallback是ScanCallback实例。
mBLEScanner.startScan(mScanCallback);
} else {
//标记当前的为扫描状态
mScanning = true;
//5.0以下 开始扫描
//mLeScanCallback是BluetoothAdapter.LeScanCallback实例
mBluetoothAdapter.startLeScan(mLeScanCallback);
}
//超过SCAN_TIME时间后停止搜索
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
//停止扫描设备
if(android.os.Build.VERSION.SDK_INT >= 21) {
//标记当前的为未扫描状态
mScanning = false;
mBLEScanner.stopScan(mScanCallback);
} else {
//标记当前的为未扫描状态
mScanning = false;
//5.0以下 停止扫描
mBluetoothAdapter.stopLeScan(mLeScanCallback);
}
}
}, SCAN_TIME);
```
- 扫描的方法需要提供对应的callback,callback类里面的函数里面可以得到扫描得到的蓝牙列表。可以用个列表数组添加扫描得到的设备,记得在开始扫描蓝牙前把列表数组清空。
```
/**
* 搜索蓝牙的结果
*/
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
//在这里可以把搜索到的设备保存起来
//device.getName();获取蓝牙设备名字
//device.getAddress();获取蓝牙设备mac地址
//这里的rssi即信号强度,即手机与设备之间的信号强度。
if(device.getName()==null){
return;
}
for(int i=0; i results) {
super.onBatchScanResults(results);
}
//当扫描不能开启时回调
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
//扫描太频繁会返回ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED,表示app无法注册,无法开始扫描。
//android 7.0后不能在30秒内扫描次数超过5次
}
};
```
- 得到蓝牙设备的列表数据后,一般是让用户选择好要连接的设备名称,根据对应的地址获取蓝牙设备BluetoothDevice后,调用连接connectGatt方法进行连接,并获得返回的BluetoothGatt。
```
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
mBluetoothGatt = device.connectGatt(getActivity(), false, mGattCallback);//真正的连接。这个方法需要三个参数:一个Context对象,自动连接(boolean值,表示只要BLE设备可用是否自动连接到它)
```
- 连接蓝牙设备时需要提供对应的callback,callback类提供了各种连接状态和结果的回调方法。onConnectionStateChange可以得到蓝牙设备连接的状态,可以判断对应蓝牙设备是连接还是断开,连接成功后调用discoverServices方法。onServicesDiscovered可以得到发现的service和service包含的Characteristic,需要调用mBluetoothGatt.discoverServices()。蓝牙发送和接收数据是对Characteristic进行操作,如果没有确定的service和characteristic的UUID,就遍历characteristic获得可写和可读的characteristic存储起来,如果有确定的UUID就只存储对应的characteristic。onCharacteristicWrite可以知道写入到蓝牙外设的特征值是否成功,需要调用mBluetoothGatt.writeCharacteristic。onCharacteristicRead可以得到蓝牙外设发送的特征值,需要调用mBluetoothGatt.readCharacteristic。但是由于不知道蓝牙外设什么时候发送特征值,所以一般不会使用mBluetoothGatt.readCharacteristic方法,而是对Characteristic进行监听。onCharacteristicChanged可以监听到蓝牙外设有发送特征值并得到对应特征值,需要调用mBluetoothGatt.setCharacteristicNotification和mBluetoothGatt.writeDescriptor启动监听,前提是该Characteristic具有NOTIFY属性
```
//定义蓝牙Gatt回调类
public class daqiBluetoothGattCallback extends BluetoothGattCallback{
//连接状态回调
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
// status 用于返回操作是否成功,会返回异常码。
// newState 返回连接状态,如BluetoothProfile#STATE_DISCONNECTED、BluetoothProfile#STATE_CONNECTED
//操作成功的情况下
if (status == BluetoothGatt.GATT_SUCCESS){
//判断是否连接码
if (newState == BluetoothProfile.STATE_CONNECTED) {
}else if(newState == BluetoothProfile.STATE_DISCONNECTED){
//判断是否断开连接码
}
}else{
//异常码
}
}
//服务发现回调
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
}
//特征写入回调
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
}
//外设特征值改变回调
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
}
//描述写入回调
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
}
//特征读取回调
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
}
}
```
- 对Characteristic设置监听,当特征值改变时,接收到蓝牙外设发送的值,onCharacteristicChanged方法会回调
```
for (int i=0; i gattDescriptors = characteristic.getDescriptors();
for (BluetoothGattDescriptor gattDescriptor : gattDescriptors) {
gattDescriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(gattDescriptor);
}
}
```
- 发送给蓝牙外设数据
```
for (int i=0; i> fourWriteCharacteristicArrayList = new ArrayList<>();
private List> fourReadCharacteristicArrayList = new ArrayList<>();
private List> fourNotifyCharacteristicArrayList = new ArrayList<>();
```