ble分主模式和从模式,android从API 18(4.0)开始支持BLE功能的主模式,但是从API 21(5.0)才开始支持从模式,ble的应用越来越广泛,今天这里我们来讲讲Ble的从模式的开发。
主模式的开发我已经讲过了,需要看到的请移步 Android蓝牙4.0Ble主模式开发
从模式的工作流程大概是这样的:从机打开蓝牙->从机发送带有service和characteristic的广播->主机连接上从机-->主机和从机通过约定好的service下的characteristic进行通讯;
进行ble开发的时候,我们需要有以下的权限
这一步相信很多人都会了,我就直接上打开/关闭蓝牙的代码了
/**
* 打开/关闭蓝牙
*
* @param context:上下文
* @param enable:是否打开 true=打开 false=关闭
* */
private void changeBluetooth(Context context,boolean enable){
//先获取BluetoothManager
BluetoothManager bluetoothManager =
(BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
//通过BluetoothManager获取BluetoothAdapter 通过BluetoothAdapter才能去操作蓝牙
BluetoothAdapter mBluetoothAdapter = bluetoothManager.getAdapter();
if(mBluetoothAdapter != null){
if(enable){
toEnable(mBluetoothAdapter);
}else{
toDisable(mBluetoothAdapter);
}
}
}
/**
* 打开蓝牙
* */
private void toEnable(BluetoothAdapter mBluetoothAdapter){
try {
if(mBluetoothAdapter.isEnabled()){
return ;
}
//使用反射的方法开发蓝牙
for(Method temp:Class.forName(mBluetoothAdapter.getClass().getName()).getMethods()){
if(temp.getName().equals("enableNoAutoConnect")){
temp.invoke(mBluetoothAdapter);
}
}
} catch (Exception e) {
//反射调用失败就启动通过enable()启动;
mBluetoothAdapter.enable();
e.printStackTrace();
}
}
/**
* 关闭蓝牙
* */
private void toDisable(BluetoothAdapter mBluetoothAdapter){
if(mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()){
mBluetoothAdapter.disable();
}
}
这一步分两步走,先开启广播,开启成功后再添加需要的service和characteristic;
/**
* 开启广播的结果callback
* */
private AdvertiseCallback callback = new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
Log.d(TAG, "BLE advertisement added successfully");
}
@Override
public void onStartFailure(int errorCode) {
Log.e(TAG, "Failed to add BLE advertisement, reason: " + errorCode);
}
};
/**
*开启广播
*
*@param bleName:ble设备的名称
* @param serviceData:要放到scanrecord中的数据
*@param parcelUUID:要放到scanrecord中的UUID
*@param mBluetoothAdapter:操作蓝牙用的BluetoothAdapter
* */
public void startBluetoothLeAdvertiser(String bleName,byte[] serviceData, UUID parcelUUID,BluetoothAdapter mBluetoothAdapter) {
//广播设置
AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setConnectable(true) //是否被连接
.setTimeout(0) //超时时间
.build();
//广播数据设置
AdvertiseData advertiseData = new AdvertiseData.Builder()
.setIncludeDeviceName(true) //是否在广播中携带设备的名称
.setIncludeTxPowerLevel(true) //是否在广播中携带信号强度
.build();
//扫描回应的广播设置
AdvertiseData scanResponseData = new AdvertiseData.Builder()
.setIncludeTxPowerLevel(true) //是否在广播中携带设备的名称
.addServiceData(new ParcelUuid(parcelUUID), serviceData) //在scanrecord中添加的数据
.build();
//设置BLE设备的名称
mBluetoothAdapter.setName(bleName);
//开启广播
BluetoothLeAdvertiser bluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
bluetoothLeAdvertiser.startAdvertising(settings, advertiseData, scanResponseData, callback);
}
开启广播调用的是BluetoothLeAdvertiser的startAdvertising方法,他需要传入一个AdvertiseSettings(我们理解为从模式的系统设置)、两个AdvertiseData(我们可以理解为广播内容的配置)、一个AdvertiseCallback。
AdvertiseSettings用来设置ble的一些配置,比如说是否可以被连接(setConnectable)、超时时间(setTimeout)、模式(setAdvertiseMode)、发射功率(setTxPowerLevel)等。
两个AdvertiseData中,advertiseData是用来配置广播中携带的信息,比如说是否携带名称(setIncludeDeviceName),如果不携带名称的话,扫描的时候就不会显示出你设置的名称。scanResponseData用来配置被扫描到的时候返回出去的信息,比如说scanrecord中的数据(addServiceData)。
AdvertiseCallback用来返回开启广播的结果的分别有onStartSuccess(成功时调用)、onStartFailure(失败时调用,并返回错误码)。
这一步一定得是在开启广播的AdvertiseCallback的onStartSuccess被回调了才可以进行,因为添加service和characteristic需要先成功开启广播,如果onStartFailure被回调了,就根据errorCode去查下原因,解决它。
好,先来看下代码
/**
* setvice事件的回调
*/
private BluetoothGattServerCallback bluetoothGattServerCallback = new BluetoothGattServerCallback() {
/**
* 1.连接状态发生变化时
* @param device
* @param status
* @param newState
*/
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
Log.e(TAG, String.format("1.onConnectionStateChange:device name = %s, address = %s", device.getName(), device.getAddress()));
Log.e(TAG, String.format("1.onConnectionStateChange:status = %s, newState =%s ", status, newState));
super.onConnectionStateChange(device, status, newState);
}
@Override
public void onServiceAdded(int status, BluetoothGattService service) {
super.onServiceAdded(status, service);
Log.e(TAG, String.format("onServiceAdded:status = %s", status));
}
@Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
Log.e(TAG, String.format("onCharacteristicReadRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
Log.e(TAG, String.format("onCharacteristicReadRequest:requestId = %s, offset = %s", requestId, offset));
bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
// super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
}
/**
* 3. onCharacteristicWriteRequest,接收具体的字节
* @param device
* @param requestId
* @param characteristic
* @param preparedWrite
* @param responseNeeded
* @param offset
* @param requestBytes
*/
@Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes) {
Log.e(TAG, String.format("3.onCharacteristicWriteRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
Log.e(TAG, String.format("3.onCharacteristicWriteRequest:requestId = %s, preparedWrite=%s, responseNeeded=%s, offset=%s, value=%s", requestId, preparedWrite, responseNeeded, offset, CodeUtil.bytesToString(requestBytes)));
bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, requestBytes);
//4.处理响应内容
onResponseToClient(requestBytes, device, requestId, characteristic);
}
/**
* 2.描述被写入时,在这里执行 bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS... 收,触发 onCharacteristicWriteRequest
* @param device
* @param requestId
* @param descriptor
* @param preparedWrite
* @param responseNeeded
* @param offset
* @param value
*/
@Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
Log.e(TAG, String.format("2.onDescriptorWriteRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
Log.e(TAG, String.format("2.onDescriptorWriteRequest:requestId = %s, preparedWrite = %s, responseNeeded = %s, offset = %s, value = %s,", requestId, preparedWrite, responseNeeded, offset, CodeUtil.bytesToString(value)));
bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
}
/**
* 5.特征被读取。当回复响应成功后,客户端会读取然后触发本方法
* @param device
* @param requestId
* @param offset
* @param descriptor
*/
@Override
public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
Log.e(TAG, String.format("onDescriptorReadRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
Log.e(TAG, String.format("onDescriptorReadRequest:requestId = %s", requestId));
bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null);
}
@Override
public void onNotificationSent(BluetoothDevice device, int status) {
super.onNotificationSent(device, status);
Log.e(TAG, String.format("5.onNotificationSent:device name = %s, address = %s", device.getName(), device.getAddress()));
Log.e(TAG, String.format("5.onNotificationSent:status = %s", status));
}
@Override
public void onMtuChanged(BluetoothDevice device, int mtu) {
super.onMtuChanged(device, mtu);
Log.e(TAG, String.format("onMtuChanged:mtu = %s", mtu));
}
@Override
public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
super.onExecuteWrite(device, requestId, execute);
Log.e(TAG, String.format("onExecuteWrite:requestId = %s", requestId));
}
};
/**
* 添加ble的service
*
*@param serviceInfo:需要添加服务列表
* */
private void addServices(BluetoothGattServiceInfo...serviceInfo) {
BluetoothGattServer bluetoothGattServer = bluetoothManager.openGattServer(context, bluetoothGattServerCallback);
for(BluetoothGattServiceInfo temp : serviceInfo){
BluetoothGattService service_temp = new BluetoothGattService(temp.getUuid(), temp.getServiceType());
for(BluetoothGattCharacteristicInfo temp_CharacteristicInfo : temp.getCharacteristicInfos()){
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(temp_CharacteristicInfo.getUuid(), temp_CharacteristicInfo.getProperties(), temp_CharacteristicInfo.getPermissions());
BluetoothGattDescriptorInfo descriptorInfo = temp_CharacteristicInfo.getBluetoothGattDescriptorInfo();
if(descriptorInfo != null){
if(descriptorInfo != null){
BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(descriptorInfo.getUuid(), descriptorInfo.permissions);
characteristic.addDescriptor(descriptor);
}
}
service_temp.addCharacteristic(characteristic);
}
bluetoothGattServer.addService(service_temp);
}
}
这里用到的BluetoothGattServiceInfo其实我封装好的service的一个实体类,方便添加service。
import java.util.UUID;
/**
* Created by 601042 on 2018/6/28.
*
* ble的service信息
*/
public class BluetoothGattServiceInfo {
//Service的UUID
private UUID uuid;
//服务的类型 SERVICE_TYPE_PRIMARY /SERVICE_TYPE_SECONDARY
private int serviceType;
//该service下的characteristic
private BluetoothGattCharacteristicInfo[] characteristicInfos;
public BluetoothGattServiceInfo(){
}
public BluetoothGattServiceInfo(UUID uuid,int serviceType,BluetoothGattCharacteristicInfo[] characteristicInfos){
this.uuid = uuid;
this.serviceType = serviceType;
this.characteristicInfos = characteristicInfos;
}
public UUID getUuid() {
return uuid;
}
public void setUuid(UUID uuid) {
this.uuid = uuid;
}
public int getServiceType() {
return serviceType;
}
public void setServiceType(int serviceType) {
this.serviceType = serviceType;
}
public BluetoothGattCharacteristicInfo[] getCharacteristicInfos() {
return characteristicInfos;
}
public void setCharacteristicInfos(BluetoothGattCharacteristicInfo[] characteristicInfos) {
this.characteristicInfos = characteristicInfos;
}
}
import java.util.UUID;
/**
* Created by 601042 on 2018/6/28.
*
* ble的service的Characteristic信息
*/
public class BluetoothGattCharacteristicInfo {
//Characteristic的UUID
private UUID uuid;
//Characteristic的属性
private int properties;
//Characteristic的权限
private int permissions;
//该service下的Descriptor
private BluetoothGattDescriptorInfo bluetoothGattDescriptorInfo;
public BluetoothGattCharacteristicInfo(UUID uuid,int properties,int permissions,BluetoothGattDescriptorInfo bluetoothGattDescriptorInfo){
this.uuid = uuid;
this.properties = properties;
this.permissions = permissions;
this.bluetoothGattDescriptorInfo = bluetoothGattDescriptorInfo;
}
public UUID getUuid() {
return uuid;
}
public void setUuid(UUID uuid) {
this.uuid = uuid;
}
public int getProperties() {
return properties;
}
public void setProperties(int properties) {
this.properties = properties;
}
public int getPermissions() {
return permissions;
}
public void setPermissions(int permissions) {
this.permissions = permissions;
}
public BluetoothGattDescriptorInfo getBluetoothGattDescriptorInfo() {
return bluetoothGattDescriptorInfo;
}
public void setBluetoothGattDescriptorInfo(BluetoothGattDescriptorInfo bluetoothGattDescriptorInfo) {
this.bluetoothGattDescriptorInfo = bluetoothGattDescriptorInfo;
}
}
import java.util.UUID;
/**
* Created by 601042 on 2018/6/28.
*
* ble的service的Characteristic的Descriptor信息
*/
public class BluetoothGattDescriptorInfo {
//描述者的UUID
private UUID uuid;
//描述者的权限
int permissions;
public BluetoothGattDescriptorInfo(UUID uuid,int permissions){
this.uuid = uuid;
this.permissions = permissions;
}
public UUID getUuid() {
return uuid;
}
public void setUuid(UUID uuid) {
this.uuid = uuid;
}
public int getPermissions() {
return permissions;
}
public void setPermissions(int permissions) {
this.permissions = permissions;
}
}
characteristic是属于service里面的,所以添加service和characteristic流程是先过去gatt的服务BluetoothGattServer,获取到了之后直接实例化好要添加进去的BluetoothGattService,
实例化的时候构造方法需要传入该service的uuid(自己约定好,这个UUID实际是需要买的,但是国内大家都随便用)和类型(BluetoothGattService.SERVICE_TYPE_PRIMARY / BluetoothGattService.SERVICE_TYPE_SECONDARY 分别是主要服务和次要服务)。
实例化完了BluetoothGattService之后就需要向其中加入characteristic即BluetoothGattCharacteristic。BluetoothGattCharacteristic实例化的时候构造方法需要传入该characteristic的uuid(自己约定好)、属性(properties)和权限(permissions)。属性和权限的具体类型大家直接看API文档吧,太多就不说了,这里我们需要注意的是,属性就是表明这个characteristic是干什么的,权限就是这个characteristic有的权限,所以一般当属性设置他是一个可读的(BluetoothGattCharacteristic.PROPERTY_READ)的时候,权限也要给相应的可读的权限(BluetoothGattCharacteristic.PERMISSION_READ)给他。有一点要注意的就是:当设置的BluetoothGattCharacteristic是BluetoothGattCharacteristic.PROPERTY_NOTIFY是,需要给BluetoothGattCharacteristic添加一个描述者BluetoothGattDescriptor,描述者同样需要知道UUID和权限,调用BluetoothGattCharacteristic的addDescriptor方法添加进入,描述者的UUID现在都在用"00002902-0000-1000-8000-00805f9b34fb".
实例化完了BluetoothGattCharacteristic之后就调用BluetoothGattService的addCharacteristic方法添加到BluetoothGattCharacteristic。实例化完了BluetoothGattService之后就调用BluetoothGattServer的addService方法添加到BluetoothGattServer。
这就完成了添加service和characteristic,现在其他的主机就可以扫描到你的设备了,且设备里面有你添加好的service和characteristic,可以使用这些characteristic进行通讯了。
ble的通讯方式是通过characteristic来进行的, characteristic的属性有三种:可读、可写、可通知。一个characteristic可以同时具备多种属性。现在从机一般都是通过可通知的characteristic,发送数据给主机,这样的好处就是不用主机一直读可读的characteristic。
还记得前面添加service的使用到的BluetoothGattServerCallback吗,当设备状态发送变化时,会回调其中特征的方法,比如说当有主机连接上从机之后,就会调用onConnectionStateChange(BluetoothDevice device, int status, int newState) 这个方法
/**
* 1.连接状态发生变化时
* @param device :连接的设备
* @param status :操作状态(0是成功,其他值为失败)
* @param newState :当前连接状态(2是已连接 0是已断开)
*/
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
Log.e(TAG, String.format("1.onConnectionStateChange:device name = %s, address = %s", device.getName(), device.getAddress()));
Log.e(TAG, String.format("1.onConnectionStateChange:status = %s, newState =%s ", status, newState));
super.onConnectionStateChange(device, status, newState);
}
当主机通过可写的characteristic向从机写出数据的时,会调用onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes)
/**
* 3. onCharacteristicWriteRequest,接收具体的字节
* @param device :连接的设备
* @param requestId :请求的ID(也可以理解为流水号)
* @param characteristic :发送消息使用的characteristic
* @param preparedWrite :是否需要等待后续操作
* @param responseNeeded :是否需要回复
* @param offset : 数据内容偏移
* @param requestBytes :数据内容
*/
@Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes) {
Log.e(TAG, String.format("3.onCharacteristicWriteRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
Log.e(TAG, String.format("3.onCharacteristicWriteRequest:requestId = %s, preparedWrite=%s, responseNeeded=%s, offset=%s, value=%s", requestId, preparedWrite, responseNeeded, offset, CodeUtil.bytesToString(requestBytes)));
}
从机通过通知的方式写数据给主机也很简单,先将需要的发送的通过BluetoothGattCharacteristic的setValue装进BluetoothGattCharacteristic里,然后再调用BluetoothGattServer的notifyCharacteristicChanged方法就能发送出去了。其中
notifyCharacteristicChanged有三个参数,第一个device是要发送的目标主机,第二个characteristic是用来通知用的可通知的characteristic,第三个confirm是要不要等回复确认。
/**
* 发送通知给主机
*
* @param device :发送的目标设备
* @param characteristic :用来通知的characteristic
* @param data :通知的内容
*/
public boolean notify( BluetoothDevice device,BluetoothGattCharacteristic characteristic,byte[] data) {
if(device != null && characteristic != null && data != null){
//设置写操作的类型 WRITE_TYPE_DEFAULT的情况选 底层会自动分包 不用人为分包
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
//把要设置的数据装进characteristic
characteristic.setValue(data);
//发送出去
return bluetoothGattServer.notifyCharacteristicChanged(device,characteristic,false);
}else{
return false;
}
}
好了,ble的从模式基本就讲完了。我把这些操作封装成了一个,方便以后其他地方复用
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.content.Context;
import android.os.ParcelUuid;
import android.util.Log;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* Created by 601042 on 2018/6/28.
*
* 封装好Ble Peripheral模式的工具类
*/
public class BlePeripheralUtils {
private static final String TAG = "BlePeripheralUtils";
private BluetoothAdapter mBluetoothAdapter;
private BluetoothManager bluetoothManager;
private Context context;
private BluetoothLeAdvertiser bluetoothLeAdvertiser;
private BluetoothGattServer bluetoothGattServer;
//连接上的设备
private ArrayList deviceArrayList = new ArrayList();
//ble的状态callback
private BlePeripheralCallback blePeripheralCallback;
/**
* 开启广播的结果callback
*/
private AdvertiseCallback callback = new AdvertiseCallback() {
@Override
public void onStartSuccess(AdvertiseSettings settingsInEffect) {
Log.d(TAG, "BLE advertisement added successfully");
}
@Override
public void onStartFailure(int errorCode) {
Log.e(TAG, "Failed to add BLE advertisement, reason: " + errorCode);
}
};
public BlePeripheralUtils(Context context) {
this.context = context;
}
/**
* 服务事件的回调
*/
private BluetoothGattServerCallback bluetoothGattServerCallback = new BluetoothGattServerCallback() {
/**
* 1.连接状态发生变化时
* @param device :连接的设备
* @param status :操作状态(0是成功,其他值为失败)
* @param newState :当前连接状态(2是已连接 0是已断开)
*/
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
Log.e(TAG, String.format("1.onConnectionStateChange:device name = %s, address = %s", device.getName(), device.getAddress()));
Log.e(TAG, String.format("1.onConnectionStateChange:status = %s, newState =%s ", status, newState));
if (newState == 2) {
//连接成功后保存当前的设备
deviceArrayList.add(device);
} else {
//断开后从连接的列表里删除设备
int index = 0;
for (int i = 0; i < deviceArrayList.size(); i++) {
if (deviceArrayList.get(i).getAddress().equals(device.getAddress())) {
index = i;
break;
}
}
deviceArrayList.remove(index);
}
//通过回调发送出去
if (blePeripheralCallback != null) {
blePeripheralCallback.onConnectionStateChange(device, status, newState);
}
super.onConnectionStateChange(device, status, newState);
}
@Override
public void onServiceAdded(int status, BluetoothGattService service) {
super.onServiceAdded(status, service);
Log.e(TAG, String.format("onServiceAdded:status = %s", status));
}
@Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
Log.e(TAG, String.format("onCharacteristicReadRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
Log.e(TAG, String.format("onCharacteristicReadRequest:requestId = %s, offset = %s", requestId, offset));
bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
// super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
}
/**
* 3. onCharacteristicWriteRequest,接收具体的字节
* @param device :连接的设备
* @param requestId :请求的ID(也可以理解为流水号)
* @param characteristic :发送消息使用的characteristic
* @param preparedWrite :是否需要等待后续操作
* @param responseNeeded :是否需要回复
* @param offset : 数据内容偏移
* @param requestBytes :数据内容
*/
@Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes) {
Log.e(TAG, String.format("3.onCharacteristicWriteRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
Log.e(TAG, String.format("3.onCharacteristicWriteRequest:requestId = %s, preparedWrite=%s, responseNeeded=%s, offset=%s, value=%s", requestId, preparedWrite, responseNeeded, offset, new String(requestBytes)));
bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
//通过回调发送出去
if (blePeripheralCallback != null) {
blePeripheralCallback.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, requestBytes);
}
}
/**
* 2.描述被写入时,在这里执行 bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS... 收,触发 onCharacteristicWriteRequest
* @param device
* @param requestId
* @param descriptor
* @param preparedWrite
* @param responseNeeded
* @param offset
* @param value
*/
@Override
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
Log.e(TAG, String.format("2.onDescriptorWriteRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
Log.e(TAG, String.format("2.onDescriptorWriteRequest:requestId = %s, preparedWrite = %s, responseNeeded = %s, offset = %s, value = %s,", requestId, preparedWrite, responseNeeded, offset, new String(value)));
// now tell the connected device that this was all successfull
bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
}
/**
* 5.特征被读取。当回复响应成功后,客户端会读取然后触发本方法
* @param device
* @param requestId
* @param offset
* @param descriptor
*/
@Override
public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {
Log.e(TAG, String.format("onDescriptorReadRequest:device name = %s, address = %s", device.getName(), device.getAddress()));
Log.e(TAG, String.format("onDescriptorReadRequest:requestId = %s", requestId));
// super.onDescriptorReadRequest(device, requestId, offset, descriptor);
bluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null);
}
@Override
public void onNotificationSent(BluetoothDevice device, int status) {
super.onNotificationSent(device, status);
Log.e(TAG, String.format("5.onNotificationSent:device name = %s, address = %s", device.getName(), device.getAddress()));
Log.e(TAG, String.format("5.onNotificationSent:status = %s", status));
}
@Override
public void onMtuChanged(BluetoothDevice device, int mtu) {
super.onMtuChanged(device, mtu);
Log.e(TAG, String.format("onMtuChanged:mtu = %s", mtu));
}
@Override
public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
super.onExecuteWrite(device, requestId, execute);
Log.e(TAG, String.format("onExecuteWrite:requestId = %s", requestId));
}
};
/**
* 初始化
*/
public void init() {
bluetoothManager =
(BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
// 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()) {
toEnable();
}
}
/**
* 打开蓝牙
*/
private boolean toEnable() {
boolean result = false;
try {
if (mBluetoothAdapter == null) {
return false;
}
for (Method temp : Class.forName(mBluetoothAdapter.getClass().getName()).getMethods()) {
if (temp.getName().equals("enableNoAutoConnect")) {
result = (boolean) temp.invoke(mBluetoothAdapter);
}
}
} catch (Exception e) {
//反射调用失败就启动通过enable()启动;
result = mBluetoothAdapter.enable();
e.printStackTrace();
}
return result;
}
/**
* 关闭蓝牙
*/
private void toDisable() {
if (mBluetoothAdapter != null) {
mBluetoothAdapter.disable();
}
}
/**
* 开启广播
*
* @param bleName:ble设备的名称
* @param serviceData:要放到scanrecord中的数据
* @param parcelUUID:要放到scanrecord中的UUID
*/
public void startBluetoothLeAdvertiser(String bleName, byte[] serviceData, UUID parcelUUID) {
//广播设置
AdvertiseSettings settings = new AdvertiseSettings.Builder()
.setConnectable(true) //是否被连接
.setTimeout(0) //超时时间
.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED) //广播模式
.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) //发射功率
.build();
//广播数据设置
AdvertiseData advertiseData = new AdvertiseData.Builder()
.setIncludeDeviceName(true) //是否在广播中携带设备的名称
.setIncludeTxPowerLevel(true) //是否在广播中携带信号强度
.build();
//扫描回应的广播设置
AdvertiseData scanResponseData = new AdvertiseData.Builder()
.setIncludeTxPowerLevel(true) //是否在广播中携带设备的名称
.addServiceData(new ParcelUuid(parcelUUID), serviceData) //在scanrecord中添加的数据
.build();
//设置BLE设备的名称
mBluetoothAdapter.setName(bleName);
//开启广播
BluetoothLeAdvertiser bluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
bluetoothLeAdvertiser.startAdvertising(settings, advertiseData, scanResponseData, callback);
}
/**
* 停止广播
*/
public void stopBluetoothLeAdvertiser() {
bluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
bluetoothLeAdvertiser.stopAdvertising(callback);
}
/**
* 添加ble的service
*
* @param serviceInfo:需要添加服务列表
*/
public void addServices(BluetoothGattServiceInfo... serviceInfo) {
//先获取GattServer
bluetoothGattServer = bluetoothManager.openGattServer(context, bluetoothGattServerCallback);
//循环添加需要添加的service
for (BluetoothGattServiceInfo temp : serviceInfo) {
//实例化一个service
BluetoothGattService service_temp = new BluetoothGattService(temp.getUuid(), temp.getServiceType());
//添加其中需要的Characteristic
for (BluetoothGattCharacteristicInfo temp_CharacteristicInfo : temp.getCharacteristicInfos()) {
//实例化需要的characteristic
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(temp_CharacteristicInfo.getUuid(), temp_CharacteristicInfo.getProperties(), temp_CharacteristicInfo.getPermissions());
//看看需不需要添加descriptor
BluetoothGattDescriptorInfo descriptorInfo = temp_CharacteristicInfo.getBluetoothGattDescriptorInfo();
if (descriptorInfo != null) {
//需要就先实例化descriptor
BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(descriptorInfo.getUuid(), descriptorInfo.permissions);
//添加到characteristic里
characteristic.addDescriptor(descriptor);
}
//把characteristic添加到service
service_temp.addCharacteristic(characteristic);
}
//把service添加到GattServer
bluetoothGattServer.addService(service_temp);
}
}
/**
* 发送通知给主机
*
* @param device :发送的目标设备
* @param characteristic :用来通知的characteristic
* @param data :通知的内容
*/
public boolean notify(BluetoothDevice device, BluetoothGattCharacteristic characteristic, byte[] data) {
if (device != null && characteristic != null && data != null) {
//设置写操作的类型 WRITE_TYPE_DEFAULT的情况选 底层会自动分包 不用人为分包
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
//把要设置的数据装进characteristic
characteristic.setValue(data);
//发送出去
return bluetoothGattServer.notifyCharacteristicChanged(device, characteristic, false);
} else {
return false;
}
}
/**
* 获取service下的所有Characteristic
*
* @param serviceUuid :service的UUID
*/
public List getCharacteristicList(UUID serviceUuid) {
//根据UUID获取service
BluetoothGattService service = bluetoothGattServer.getService(serviceUuid);
//获取到了service则获取其中所有的BluetoothGattCharacteristic列表并返回出去
if (service != null) {
return service.getCharacteristics();
} else {
return null;
}
}
/**
* 获取service下的所有Characteristic
*
* @param serviceUuid :service的UUID
* @param characteristicUuid : Characteristic的UUID
*/
public BluetoothGattCharacteristic getCharacteristic(UUID serviceUuid, UUID characteristicUuid) {
//根据UUID获取service
BluetoothGattService service = bluetoothGattServer.getService(serviceUuid);
//获取到了service则根据Characteristic的UUID获取Characteristic
if (service != null) {
return service.getCharacteristic(characteristicUuid);
} else {
return null;
}
}
public ArrayList getDeviceArrayList() {
return deviceArrayList;
}
public BlePeripheralCallback getBlePeripheralCallback() {
return blePeripheralCallback;
}
public void setBlePeripheralCallback(BlePeripheralCallback blePeripheralCallback) {
this.blePeripheralCallback = blePeripheralCallback;
}
}
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattCharacteristic;
/**
* Created by 601042 on 2018/6/28.
*/
public interface BlePeripheralCallback {
void onConnectionStateChange(BluetoothDevice device, int status, int newState);
void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes);
}
调用也很简单,下面是demo中的调用方式
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import java.util.UUID;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
public final static UUID UUID_SERVER = UUID.fromString("0000181C-0000-1000-8000-00805F9B34FB");
public final static UUID UUID_SERVER1 = UUID.fromString("0000181C-0000-1000-8000-00805F9B34FA");
public final static UUID UUID_CHARREAD = UUID.fromString("0000C101-0000-1000-8000-00805F9B3401");
public final static UUID UUID_DESCRIPTOR = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
public final static UUID UUID_CHARWRITE = UUID.fromString("0000C101-0000-1000-8000-00805F9B3402");
public final static UUID UUID_WRITE = UUID.fromString("0000C101-0000-1000-8000-00805F9B3403");
BluetoothGattCharacteristic characteristicnotify;
BlePeripheralUtils blePeripheralUtils;
BlePeripheralCallback callback = new BlePeripheralCallback() {
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
}
@Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] requestBytes) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
blePeripheralUtils = new BlePeripheralUtils(MainActivity.this);
blePeripheralUtils.init();
blePeripheralUtils.setBlePeripheralCallback(callback);
Button open = (Button) findViewById(R.id.open);
Button send = (Button) findViewById(R.id.send);
final byte[] serviceData = "1111111".getBytes();
open.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
blePeripheralUtils.startBluetoothLeAdvertiser("xuge", serviceData, UUID_SERVER1);
BluetoothGattCharacteristicInfo[] bluetoothGattCharacteristicInfos = new BluetoothGattCharacteristicInfo[3];
BluetoothGattDescriptorInfo descriptorInfo = new BluetoothGattDescriptorInfo(UUID_DESCRIPTOR, BluetoothGattCharacteristic.PERMISSION_WRITE);
bluetoothGattCharacteristicInfos[0] = new BluetoothGattCharacteristicInfo(UUID_CHARREAD, BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ,null);
bluetoothGattCharacteristicInfos[1] = new BluetoothGattCharacteristicInfo(UUID_WRITE, BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_WRITE,null);
bluetoothGattCharacteristicInfos[2] = new BluetoothGattCharacteristicInfo(UUID_CHARWRITE, BluetoothGattCharacteristic.PROPERTY_NOTIFY, BluetoothGattCharacteristic.PROPERTY_NOTIFY,descriptorInfo);
BluetoothGattServiceInfo bluetoothGattServiceInfo1 = new BluetoothGattServiceInfo(UUID_SERVER,BluetoothGattService.SERVICE_TYPE_PRIMARY,bluetoothGattCharacteristicInfos);
blePeripheralUtils.addServices(bluetoothGattServiceInfo1);
}
});
send.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(characteristicnotify == null){
characteristicnotify = blePeripheralUtils.getCharacteristic(UUID_SERVER,UUID_CHARWRITE);
}
blePeripheralUtils.notify(blePeripheralUtils.getDeviceArrayList().get(0),characteristicnotify,"11111".getBytes());
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
blePeripheralUtils.stopBluetoothLeAdvertiser();
}
}
最后附上 demo