在没有发现服务的情况下编写BLE特性Android

时间:2019-01-07 10:37:26

标签: android bluetooth bluetooth-lowenergy android-bluetooth smartphone

是否可以在没有先前发现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");
        }

但没有成功。

2 个答案:

答案 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);