是否可以在没有先前发现ble服务的情况下编写ble特性?
我想实现一个应用程序,该应用程序连接到外围设备,写入特性并断开连接,然后连接到另一个设备,依此类推...
断开连接后,我调用gatt.close()
命令以释放所有资源。
在第一个连接上,我创建绑定。
如果我等待回调onServicesDiscovered
并编写特征:
BluetoothGattService mCustomService = mBluetoothGatt.getService(myUUID));
byte[] values = new byte[]{0x00, 0x01};
mWriteCharacteristic.setValue(values);
if(mBluetoothGatt.writeCharacteristic(mWriteCharacteristic) == false) {
Log.w(TAG, "Failed to write characteristic");
}
一切正常。但我想改善并加快整个过程。 与bond ble设备连接后,是否可以跳过发现服务并写入ble char?
BluetoothGattCharacteristic mCharacteristic = new BluetoothGattCharacteristic(UUID.fromString(GattAttributes.P1_MINI_POWER_CHARACTERISTIC), (BluetoothGattCharacteristic.PROPERTY_WRITE |BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE | BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS), 0);
mCustomService.addCharacteristic(mCharacteristic);
byte[] values = new byte[]{0x00, 0x01};
mWriteCharacteristic.setValue(values);
if(mBluetoothGatt.writeCharacteristic(mWriteCharacteristic) == false) {
Log.w(TAG, "Failed to write characteristic");
}
但没有成功。
答案 0 :(得分:1)
否,您必须使用discoverServices。您不能自己编写定义。许多原因之一是BLE堆栈需要知道特征值的ATT句柄,而BluetoothGattCharacteristic没有公开该句柄。
答案 1 :(得分:1)
尽管某些技术要求您使用NDK访问BluetoothGattService中灰色列出的字段,并在连接到BluetoothDevice的BluetoothGatt上使用一些反射,但在某些版本的Android上还是可以的。请注意,除非您要连接许多相同的蓝牙设备,否则这样做是不值得的,因为这样做并不会节省太多时间-您仍然需要在第一个蓝牙设备上进行连接并执行discoverServices()。
就我而言,我有数百人需要交谈,因此缓存GATT是值得的。如果只有两个,请不要浪费时间。这是为特定的Android设备开发的,尽管可能也有解决方法,但不适用于(例如)三星Galaxy S8。
步骤是: 1.在第一个设备上,连接,执行discoverServices(),保留要缓存的GattService和GattCharacteristics的副本。我有一个类(GattWrapper),该类具有一些用于缓存服务和特征的静态字段。
连接到第二台及后续设备时,请检查是否已经完成了discoverServices()。如果有的话,您可以复制GattService和GattCharacteristics并将新设备注入到新创建的副本中:
ble_inject.c-用于在BluetoothGattService上设置设备
#include <jni.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include "android/log.h"
// inject a bluetooth device into a BluetoothGattService
JNIEXPORT jint JNICALL Java_com_foo_Utilities_BLEFix_injectdevice
(JNIEnv *, jobject,jobject, jobject);
// inject a bluetooth device into a BluetoothGattService
JNIEXPORT jint JNICALL Java_au_com_smartshepherd_ss2_Utilities_BLEFix_injectservices
(JNIEnv *, jobject,jobject, jobject);
JNIEXPORT jint JNICALL
Java_com_foo_Utilities_Utilities_BLEFix_injectdevice(JNIEnv *env, jobject bleFix,
jobject bluetoothGattService, jobject bluetoothDevice)
{
jclass bGattServiceClass = (*env)->GetObjectClass(env,bluetoothGattService);
//jclass bGattServiceClass = (*env)->FindClass(env,"android/bluetooth/BluetoothGattService");
jfieldID f_setDevice = (*env)->GetFieldID(env,bGattServiceClass,"mDevice","Landroid/bluetooth/BluetoothDevice;");
(*env)->SetObjectField(env,bluetoothGattService,f_setDevice,bluetoothDevice);
//env->SetObjectField(instance_CS, f_codeHeight, cs.codeHeight);
return 0;
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
TARGET_PLATFORM := android-3
LOCAL_MODULE := libblefix
LOCAL_SRC_FILES := ble_inject.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
BLEFix.java
import android.bluetooth.BluetoothGattService;
import android.util.Log;
import java.util.List;
public class BLEFix {
private static final String TAG = "ble_fix";
private static boolean mLoaded = false;
public void InjectDevice(BluetoothGattService service, BluetoothDevice dev)
{
injectdevice(service,dev);
}
private native int injectdevice(Object bluetoothGattService, Object bluetoothDevice);
static {
try {
System.loadLibrary("blefix");
mLoaded = true;
}
catch(java.lang.UnsatisfiedLinkError e)
{
mLoaded = false;
Log.e( TAG, "Failed to load blefix library" );
}
}
}
用于复制BluetoothGattService和BluetoothGattCharacteristic的代码:
private BluetoothGattCharacteristic cloneGattCharacteristic(BluetoothGattCharacteristic bgc)
{
return new BluetoothGattCharacteristic(bgc.getUuid(),bgc.getProperties(),bgc.getPermissions());
}
static Field mServicesField = null;
// static initialiser for this field
static
{
Field[] fields = BluetoothGatt.class.getDeclaredFields();
for (Field fld : fields)
{
if (fld.getName() == "mServices")
{
mServicesField = fld;
if (Modifier.isPrivate(mServicesField.getModifiers())) {
mServicesField.setAccessible(true);
}
}
}
}
private static BluetoothGattService mGattService;
private static BluetoothGatt mBluetoothGatt; // set this after onConnected()
private boolean copyCharacteristics()
{
mGattService = new BluetoothGattService(sGattService.getUuid(),BluetoothGattService.SERVICE_TYPE_PRIMARY);
// FIXME extremely unsafe juse of JNI to inject this device into already discovered characteristics
bleFix.InjectDevice(mGattService,mBluetoothGatt.getDevice());
List<BluetoothGattService> services = mBluetoothGatt.getServices();
if (services.isEmpty()) {
// use reflection, the mServices value isn't hidden it's private though
try {
services.add(mGattService);
if (mServicesField != null) // if this doesn't exist you are SOL on this device, it is implementation dependent I think
{
mServicesField.set(mBluetoothGatt, services);
}
} catch (Exception ex) {
mBluetoothGatt.discoverServices();
return false;
}
// sMyGattCharacteristic - store it away in a static after the first discoverServices() is successful
mMyGattCharacteristic = cloneGattCharacteristic(sMyGattCharacteristic);
mGattService.addCharacteristic(mMyGattCharacteristic);