设置蓝牙信标设备的 UUID 无法正常工作
Setting the UUID of a bluetooth beacon device does not work correctly
我使用此代码与我的设备配对并连接到它
//this will try to connect to our bluetooth device
public void connectGatt(Context context, BluetoothDevice btDevice) {
this.btDevice = btDevice;
mBluetoothGatt = btDevice.connectGatt(context, false, mGattCallback);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mBluetoothGatt != null) {
mBluetoothGatt.requestMtu(512);
}
}
这是我的 GATT 回调:
private final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
tryToConnect = false;
Log.i("BluetoothService", "BluetoothService onConnectionStateChange CONNECTED");
if (back != null)
back.onResponse(REMOVE_CALLBACKS);
Log.i("", "Connected to GATT server.");
boolean discover = mBluetoothGatt.discoverServices();
Log.i("", "Attempting to start service discovery:" + discover);
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i("BluetoothService", "BluetoothService onConnectionStateChange STATE_DISCONNECTED");
if (tryToConnect) {
if (back != null)
back.onResponse(REMOVE_CALLBACKS);
stopMonitoringBeacons();
stopListeningForBeacons();
mBluetoothAdapter.disable();
setSleep(1500);
mBluetoothAdapter.enable();
setSleep(1500);
Log.i("BluetoothService", "BluetoothService onConnectionStateChange WILL TRY CONNECT");
if (back != null)
back.onResponse(CONNECT);
tryToConnect = false;
}
}
}
@Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
tryToConnect = false;
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i("BluetoothService", "BluetoothService onConnectionStateChange onServicesDiscovered GATT_SUCCESS" + status);
Log.w("", "onServicesDiscovered GATT_SUCCESS: " + status);
List<BluetoothGattService> listBGS = mBluetoothGatt.getServices();
Log.i("", "list size: " + listBGS.size());
if (listBGS.size() > 0) {
if (back != null)
back.onResponse(CONFIGURE);
String character = "FF05";
if (justName)
character = "FF01";
setCharacteristic(gatt, character);
} else {
Log.i("BluetoothService", "BluetoothService onConnectionStateChange onServicesDiscovered GATT_SUCCESS but ZERO SERVICES: " + btDevice.getBondState());
if (btDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
setSleep(500);
if (btDevice.getBondState() == BluetoothDevice.BOND_BONDED)
mBluetoothGatt.discoverServices();
} else if (btDevice.getBondState() == BluetoothDevice.BOND_NONE) {
askPairDevice();
}
}
} else {
askPairDevice();
Log.w("BluetoothService", "BluetoothService onServicesDiscovered received: " + status);
}
}
@Override
// Result of a characteristic read operation
public void onCharacteristicRead(final BluetoothGatt gatt,
final BluetoothGattCharacteristic characteristic,
int status) {
handler.removeCallbacksAndMessages(null);
Log.i("BluetoothService", "BluetoothService onCharacteristicRead");
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i("BluetoothService", "BluetoothService onCharacteristicRead GATT_SUCCESS");
Log.w("", "BGC onCharacteristicRead GATT_SUCCESS: " + status + " / char: " + characteristic);
if (characteristic.getUuid().toString().toUpperCase().contains("FF05")) {
final String value = toHexadecimal(characteristic.getValue());
if (newBeacon == null || newBeacon.getName() == null) {
checkIfNeedsToChangeUUID(gatt, value);
} else if (newBeacon != null && (newBeacon.getUuid() != null || justName)) {
Log.i("BluetoothService", "BluetoothService new Beacon UUID is: " + value);
newBeacon.setUuid(Identifier.parse(value).toString());
if (back != null)
back.onResponse(CHANGED);
} else {
changeUUID(gatt, characteristic, value);
}
} else if (characteristic.getUuid().toString().toUpperCase().contains("FF01")) {
changeName(gatt, characteristic);
}
} else {
Log.i("", "");
}
}
};
我感兴趣的部分在这里:
public void changeUUID(final BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, String value) {
int size = value.length();
RandomString gen = new RandomString(size, new SecureRandom());
String uuid = gen.nextString();
Log.i("", "BluetoothService BGC value NEW UUID: " + uuid);
boolean change = characteristic.setValue(hexStringToByteArray(uuid));
Log.i("", "BluetoothService BGC value after: " + toHexadecimal(characteristic.getValue()) + " / has changed: " + change);
boolean statusWrite = gatt.writeCharacteristic(characteristic);
Log.i("", "BluetoothService BGC value after statusWRITE: " + statusWrite);
if (statusWrite) {
newBeacon.setUuid(Identifier.parse(toHexadecimal(characteristic.getValue())).toString());
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
setCharacteristic(gatt, "FF05");
}
});
} else {
if (back != null)
back.onResponse(ERROR);
}
}
这将调用:
try {
Log.i("BluetoothService", "BluetoothService set characteristic: " + characteristic);
BluetoothGattCharacteristic btChar = null;
for (BluetoothGattService bgs : gatt.getServices()) {
for (final BluetoothGattCharacteristic bgc : bgs.getCharacteristics()) {
if (bgc.getUuid().toString().toUpperCase().contains(characteristic)) {
btChar = bgc;
gatt.readCharacteristic(bgc);
break;
}
}
}
final BluetoothGattCharacteristic btF = btChar;
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (btF != null)
gatt.readCharacteristic(btF);
}
}, 1000);
} catch (Exception e) {
Log.i("BluetoothService", "BluetoothService set characteristic ERROR: " + e.getMessage());
setCharacteristic(gatt, characteristic);
}
}
这有效,但不是 100%,我可以说它适用于不到 50% 的情况。我不明白为什么。有人可以帮忙吗?
我的意思是 boolean statusWrite = gatt.writeCharacteristic(characteristic);
对我来说总是 returns "TRUE" 那么如果在“changeUUID 函数中我在那次调用之后进行了另一个调用,尝试记录它,为什么它不是变了?
同样对于其他应用程序,如果我检查,我的 UUID 没有改变,这真的很奇怪。如果值相同,为什么要为写入获取 TRUE?
如果您查看 writeCharacteristic
的 documentation,您会看到:
Returns boolean true, if the write operation was initiated successfully
上面的强调是我的。仅仅因为您成功启动写入并不意味着它 完成 成功,事实上,在我的应用程序中我经常看到它没有。
您需要做的是实现回调public void onCharacteristicWrite (BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)
,然后检查状态是否为BluetoothGatt.GATT_SUCCESS
。如果没有,您将需要重试写入。我通常编写最多重试 10 次的代码,然后放弃,触发向用户显示错误的代码。
大多数其他 Android 蓝牙 API 都是这样工作的——发现服务、发现特征等。这些异步操作中的每一个都可能失败,您必须实施回调以查明它们是否真的成功了或不,并添加重试策略。
我使用此代码与我的设备配对并连接到它
//this will try to connect to our bluetooth device
public void connectGatt(Context context, BluetoothDevice btDevice) {
this.btDevice = btDevice;
mBluetoothGatt = btDevice.connectGatt(context, false, mGattCallback);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mBluetoothGatt != null) {
mBluetoothGatt.requestMtu(512);
}
}
这是我的 GATT 回调:
private final BluetoothGattCallback mGattCallback =
new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
tryToConnect = false;
Log.i("BluetoothService", "BluetoothService onConnectionStateChange CONNECTED");
if (back != null)
back.onResponse(REMOVE_CALLBACKS);
Log.i("", "Connected to GATT server.");
boolean discover = mBluetoothGatt.discoverServices();
Log.i("", "Attempting to start service discovery:" + discover);
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i("BluetoothService", "BluetoothService onConnectionStateChange STATE_DISCONNECTED");
if (tryToConnect) {
if (back != null)
back.onResponse(REMOVE_CALLBACKS);
stopMonitoringBeacons();
stopListeningForBeacons();
mBluetoothAdapter.disable();
setSleep(1500);
mBluetoothAdapter.enable();
setSleep(1500);
Log.i("BluetoothService", "BluetoothService onConnectionStateChange WILL TRY CONNECT");
if (back != null)
back.onResponse(CONNECT);
tryToConnect = false;
}
}
}
@Override
// New services discovered
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
tryToConnect = false;
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i("BluetoothService", "BluetoothService onConnectionStateChange onServicesDiscovered GATT_SUCCESS" + status);
Log.w("", "onServicesDiscovered GATT_SUCCESS: " + status);
List<BluetoothGattService> listBGS = mBluetoothGatt.getServices();
Log.i("", "list size: " + listBGS.size());
if (listBGS.size() > 0) {
if (back != null)
back.onResponse(CONFIGURE);
String character = "FF05";
if (justName)
character = "FF01";
setCharacteristic(gatt, character);
} else {
Log.i("BluetoothService", "BluetoothService onConnectionStateChange onServicesDiscovered GATT_SUCCESS but ZERO SERVICES: " + btDevice.getBondState());
if (btDevice.getBondState() == BluetoothDevice.BOND_BONDED) {
setSleep(500);
if (btDevice.getBondState() == BluetoothDevice.BOND_BONDED)
mBluetoothGatt.discoverServices();
} else if (btDevice.getBondState() == BluetoothDevice.BOND_NONE) {
askPairDevice();
}
}
} else {
askPairDevice();
Log.w("BluetoothService", "BluetoothService onServicesDiscovered received: " + status);
}
}
@Override
// Result of a characteristic read operation
public void onCharacteristicRead(final BluetoothGatt gatt,
final BluetoothGattCharacteristic characteristic,
int status) {
handler.removeCallbacksAndMessages(null);
Log.i("BluetoothService", "BluetoothService onCharacteristicRead");
if (status == BluetoothGatt.GATT_SUCCESS) {
Log.i("BluetoothService", "BluetoothService onCharacteristicRead GATT_SUCCESS");
Log.w("", "BGC onCharacteristicRead GATT_SUCCESS: " + status + " / char: " + characteristic);
if (characteristic.getUuid().toString().toUpperCase().contains("FF05")) {
final String value = toHexadecimal(characteristic.getValue());
if (newBeacon == null || newBeacon.getName() == null) {
checkIfNeedsToChangeUUID(gatt, value);
} else if (newBeacon != null && (newBeacon.getUuid() != null || justName)) {
Log.i("BluetoothService", "BluetoothService new Beacon UUID is: " + value);
newBeacon.setUuid(Identifier.parse(value).toString());
if (back != null)
back.onResponse(CHANGED);
} else {
changeUUID(gatt, characteristic, value);
}
} else if (characteristic.getUuid().toString().toUpperCase().contains("FF01")) {
changeName(gatt, characteristic);
}
} else {
Log.i("", "");
}
}
};
我感兴趣的部分在这里:
public void changeUUID(final BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, String value) {
int size = value.length();
RandomString gen = new RandomString(size, new SecureRandom());
String uuid = gen.nextString();
Log.i("", "BluetoothService BGC value NEW UUID: " + uuid);
boolean change = characteristic.setValue(hexStringToByteArray(uuid));
Log.i("", "BluetoothService BGC value after: " + toHexadecimal(characteristic.getValue()) + " / has changed: " + change);
boolean statusWrite = gatt.writeCharacteristic(characteristic);
Log.i("", "BluetoothService BGC value after statusWRITE: " + statusWrite);
if (statusWrite) {
newBeacon.setUuid(Identifier.parse(toHexadecimal(characteristic.getValue())).toString());
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
setCharacteristic(gatt, "FF05");
}
});
} else {
if (back != null)
back.onResponse(ERROR);
}
}
这将调用:
try {
Log.i("BluetoothService", "BluetoothService set characteristic: " + characteristic);
BluetoothGattCharacteristic btChar = null;
for (BluetoothGattService bgs : gatt.getServices()) {
for (final BluetoothGattCharacteristic bgc : bgs.getCharacteristics()) {
if (bgc.getUuid().toString().toUpperCase().contains(characteristic)) {
btChar = bgc;
gatt.readCharacteristic(bgc);
break;
}
}
}
final BluetoothGattCharacteristic btF = btChar;
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (btF != null)
gatt.readCharacteristic(btF);
}
}, 1000);
} catch (Exception e) {
Log.i("BluetoothService", "BluetoothService set characteristic ERROR: " + e.getMessage());
setCharacteristic(gatt, characteristic);
}
}
这有效,但不是 100%,我可以说它适用于不到 50% 的情况。我不明白为什么。有人可以帮忙吗?
我的意思是 boolean statusWrite = gatt.writeCharacteristic(characteristic);
对我来说总是 returns "TRUE" 那么如果在“changeUUID 函数中我在那次调用之后进行了另一个调用,尝试记录它,为什么它不是变了?
同样对于其他应用程序,如果我检查,我的 UUID 没有改变,这真的很奇怪。如果值相同,为什么要为写入获取 TRUE?
如果您查看 writeCharacteristic
的 documentation,您会看到:
Returns boolean true, if the write operation was initiated successfully
上面的强调是我的。仅仅因为您成功启动写入并不意味着它 完成 成功,事实上,在我的应用程序中我经常看到它没有。
您需要做的是实现回调public void onCharacteristicWrite (BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)
,然后检查状态是否为BluetoothGatt.GATT_SUCCESS
。如果没有,您将需要重试写入。我通常编写最多重试 10 次的代码,然后放弃,触发向用户显示错误的代码。
大多数其他 Android 蓝牙 API 都是这样工作的——发现服务、发现特征等。这些异步操作中的每一个都可能失败,您必须实施回调以查明它们是否真的成功了或不,并添加重试策略。