实现一个Android APP主要需求:
1、APP连接蓝牙转以太网的转接板给底板配置广播信息;
2、广播板的状态能通过蓝牙转接板透传给APP;
蓝牙搜索,发现这些之前一个app都做过,但是读写数据没有做,关键点是:
1、GATT连接;
2、服务特征UUID/读特征UUID 配置特征UUID/写特征UUID,这几个特征UUID 最好是找厂家确认。
要接收到蓝牙的数据,关键是读配置Enable功能:setBleNotification方法,网上这块有很多方法,最后生效的是下面的方法。
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// services are discoverd
Log.d(TAG, "onServicesDiscovered: GATT_SUCCESS");
mBluetoothGatt = gatt;
}
List<BluetoothGattService> list = gatt.getServices();
for(BluetoothGattService service: list){
serviceUid = service.getUuid();
for(BluetoothGattCharacteristic characteristic : service.getCharacteristics()){
//获取到相应的服务UUID和特征UUID
characterUid = characteristic.getUuid();
if (characterUid.toString().contains("8e32")){
//readd
characterReadUid = characterUid;
m_bluetoothGattCharacteristic_read = characteristic;
gatt.setCharacteristicNotification(characteristic, true);
}
if (characterUid.toString().contains("8e40")){
//write
characterWriteUid = characterUid;
}
if (characterUid.toString().contains("2902")){
//read config
characterReadConfigUid = characterUid;
}
}
if (serviceUid.toString().contains("8e20")){
break;
}
}
gatt.requestMtu(200);
}
//关键是这个方法,网上的说法很多,但是最后生效的还是下面的方法
private void setBleNotification(){
if (characterReadConfigUid == null){
characterReadConfigUid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
}
BluetoothGattService service = mBluetoothGatt.getService(serviceUid);
if(m_bluetoothGattCharacteristic_read != null) {
List<BluetoothGattDescriptor> descriptors = m_bluetoothGattCharacteristic_read.getDescriptors();
Log.v(TAG, "len:"+descriptors.size());
// 遍历设置 BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE 值 , 并写出
for(BluetoothGattDescriptor descriptor : descriptors) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
// BluetoothGattDescriptor descriptor = m_bluetoothGattCharacteristic_read.getDescriptor(characterReadConfigUid);
// descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
// mBluetoothGatt.writeDescriptor(descriptor);
// descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
// mBluetoothGatt.writeDescriptor(descriptor);
mBluetoothGatt.readCharacteristic(m_bluetoothGattCharacteristic_read);
}
}
3、写完成的回调;
写需要设置最大MTU,否则大于MTU的字符串发不出去
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// services are discoverd
Log.d(TAG, "onServicesDiscovered: GATT_SUCCESS");
mBluetoothGatt = gatt;
}
gatt.requestMtu(200);
}
@Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
Log.v(TAG, "onMtuChanged:"+status + ",mtu:"+mtu);
if(status == BluetoothGatt.GATT_SUCCESS){
setBleNotification();
}
}
4、读数据的回调函数;onCharacteristicChanged 蓝牙收到数据的回调方法,网上有说是onCharacteristicRead方法,实际是这个。
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
if (characteristic.getUuid().equals(characterReadUid)) {
//step 7-1:读取出characteristic的value值
// 收到的数据
byte[] receiveByte = characteristic.getValue();
String res = new String(receiveByte);
Log.i(TAG, "=====>2 value =" + res + ",len:" + receiveByte.length);
if (notifyCallback != null){
notifyCallback.notifyMessage(res);
}
}
}
5、蓝牙转接板居然还有一个NAT的问题,蓝牙转接板主动转发过来的UDP包,必须使用相同的端口回过去,否则转接板收不到包。
6、主要代码:
GattCommnucationManage.java代码
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.util.Log;
import java.util.List;
import java.util.UUID;
import top.keepempty.MyApplication;
public class GattCommnucationManager {
static GattCommnucationManager instanceGattMgr = new GattCommnucationManager();
private BluetoothDevice selectBleDevice;
private Context mContext;
public static final String TAG = "GattCommnucationManager";
BluetoothGatt mBluetoothGatt;
private UUID serviceUid;
private UUID characterUid;
private UUID characterReadUid;
private UUID characterReadConfigUid;
private UUID characterWriteUid;
private BleMessageNotify notifyCallback;
private GattCommnucationManager(){
}
public static GattCommnucationManager getInstance(){
if (instanceGattMgr == null){
instanceGattMgr = new GattCommnucationManager();
}
return instanceGattMgr;
}
public void registerInterface(BleMessageNotify callback){
notifyCallback = callback;
}
public void setDevice(BluetoothDevice device){
mContext = MyApplication.getInstance();
if (selectBleDevice != null && mBluetoothGatt != null){
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
mBluetoothGatt = null;
}
selectBleDevice = device;
connectSelectDevice();
}
public void connectSelectDevice(){
if (selectBleDevice == null){
return;
}
mBluetoothGatt = selectBleDevice.connectGatt(mContext, false, mGattCallback);
}
//关闭蓝牙和Gatt输入通道 避免出现Gatt 133状态错误
public void closeBlueToothGatt(){
if (mBluetoothGatt == null){
return;
}
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
mBluetoothGatt = null;
selectBleDevice = null;
}
/**
向设备发送数据 @param value
@return/
public boolean writeRXCharacteristic(byte[] value) {
if (mBluetoothGatt == null){
return false;
}
BluetoothGattService rxService = mBluetoothGatt.getService(serviceUid);
if (rxService == null) {
//Service not supported
Log.d(TAG, "writeRXCharacteristic: Service not supported");
return false;
}
BluetoothGattCharacteristic rxChar = rxService.getCharacteristic(characterWriteUid);
if (rxChar == null) {
// service not supported
Log.d(TAG, "writeRXCharacteristic: Service not supported");
return false;
}
rxChar.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
rxChar.setValue(value);
Log.d(TAG, "writeRXCharacteristic: "+String.valueOf(rxChar));
return mBluetoothGatt.writeCharacteristic(rxChar);
}
public final UUID DEVICE_INFO_SERVICE_UUID = UUID.fromString("00001800-0000-1000-8000-00805f9b34fb");
//Charcteristic UUID
public final UUID VID_PID_CHARACTERISTIC_UUID = UUID.fromString("00002a00-0000-1000-8000-00805f9b34fb");
BluetoothGattCharacteristic m_bluetoothGattCharacteristic_read;
/**
连接成功或者失败的回调函数/
public final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
Log.d(TAG, "onConnectionStateChange: "+newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
//bluetooth is connected so discover services
Log.d(TAG, "onConnectionStateChange: "+mBluetoothGatt.getDevice().getName());
mBluetoothGatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
//Bluetooth is disconnected
Log.d(TAG, "onConnectionStateChange: disconnected");
mBluetoothGatt = null;
}
}
private void setBleNotification(){
if (characterReadConfigUid == null){
characterReadConfigUid = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
}
BluetoothGattService service = mBluetoothGatt.getService(serviceUid);
if(m_bluetoothGattCharacteristic_read != null) {
List<BluetoothGattDescriptor> descriptors = m_bluetoothGattCharacteristic_read.getDescriptors();
Log.v(TAG, "len:"+descriptors.size());
// 遍历设置 BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE 值 , 并写出
for(BluetoothGattDescriptor descriptor : descriptors) {
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
mBluetoothGatt.writeDescriptor(descriptor);
}
// BluetoothGattDescriptor descriptor = m_bluetoothGattCharacteristic_read.getDescriptor(characterReadConfigUid);
// descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
// mBluetoothGatt.writeDescriptor(descriptor);
// descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
// mBluetoothGatt.writeDescriptor(descriptor);
mBluetoothGatt.readCharacteristic(m_bluetoothGattCharacteristic_read);
}
}
@Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
Log.v(TAG, "onMtuChanged:"+status + ",mtu:"+mtu);
if(status == BluetoothGatt.GATT_SUCCESS){
setBleNotification();
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
// services are discoverd
Log.d(TAG, "onServicesDiscovered: GATT_SUCCESS");
mBluetoothGatt = gatt;
}
List<BluetoothGattService> list = gatt.getServices();
for(BluetoothGattService service: list){
serviceUid = service.getUuid();
for(BluetoothGattCharacteristic characteristic : service.getCharacteristics()){
//获取到相应的服务UUID和特征UUID
characterUid = characteristic.getUuid();
if (characterUid.toString().contains("8e32")){
//readd
characterReadUid = characterUid;
m_bluetoothGattCharacteristic_read = characteristic;
gatt.setCharacteristicNotification(characteristic, true);
}
if (characterUid.toString().contains("8e40")){
//write
characterWriteUid = characterUid;
}
if (characterUid.toString().contains("2902")){
//read config
characterReadConfigUid = characterUid;
}
}
if (serviceUid.toString().contains("8e20")){
break;
}
}
gatt.requestMtu(200);
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
String value = "";
if (characteristic.getUuid().equals(characterReadUid))
{
//step 7-1:读取出characteristic的value值
// 收到的数据
byte[] receiveByte = characteristic.getValue();
Log.i(TAG, "=====>读取到 value =" +String.valueOf(receiveByte) + ",len:"+receiveByte.length);
//step 7-2:此处为ascii表字符,需转换为十进制ascii值
//再将十进制ascii值,转换为十六进制
//String VID = changeAsciiTo16(value.charAt(0));
//String PID = changeAsciiTo16(value.charAt(value.length() - 1));
//设备VID、PID读取成功,handle更新主线程界面UI
//Log.i(TAG, characteristic.getUuid()+",VID:"+VID+",PID:"+PID);
}
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
if (characteristic.getUuid().equals(characterReadUid)) {
//step 7-1:读取出characteristic的value值
// 收到的数据
byte[] receiveByte = characteristic.getValue();
String res = new String(receiveByte);
Log.i(TAG, "=====>2 value =" + res + ",len:" + receiveByte.length);
if (notifyCallback != null){
notifyCallback.notifyMessage(res);
}
}
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
mBluetoothGatt.readCharacteristic(m_bluetoothGattCharacteristic_read);
}
}
};
static public interface BleMessageNotify {
void notifyMessage(String msg);
}
}